<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
  <title type="html">ReinH Blog</title>
  <subtitle>Ruby and Rails Best Practices</subtitle>
  
  <link href="http://reinh.com/" />
  <updated>2009-04-27T21:13:00-04:00</updated>
  <author>
    <name>Rein Henrichs</name>
    <email>reinh@reinh.com</email>
  </author>
  <id>http://reinh.com/</id>
  
  <link rel="self" href="http://feeds.feedburner.com/reinh" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
    <title type="html">How to Cache Anything With&amp;nbsp;ActiveSupport</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/VIZkXEfUzQo/how-to-cache-anything-with-activesupport.html" />
    <id>tag:reinh.com,2009-04-27:1240869339</id>
    <published>2009-04-27T17:55:39-04:00</published>
    <updated>2009-04-27T17:55:39-04:00</updated>
    <content type="html">&lt;p&gt;We use a &lt;span class="caps"&gt;REST&lt;/span&gt;-like web service to communicate with a large Endeca index. This web service is stateless and uses &lt;span class="caps"&gt;JSON&lt;/span&gt;. Unfortunately, its performance leaves much to be desired and the server does not cache requests. Fortunately, even with its weak implementation of &lt;span class="caps"&gt;REST&lt;/span&gt;, the service&amp;#8217;s statelessness makes it trivial to add a caching layer to our client.&lt;/p&gt;
&lt;p&gt;Rather than write our own caching solution, we looked to reuse one that already exists. No &lt;acronym title="Not Invented Here"&gt;&lt;span class="caps"&gt;NIH&lt;/span&gt;&lt;/acronym&gt; for us. The caching provided by &lt;code&gt;ActiveSupport::Cache&lt;/code&gt; turned out to be perfect for our needs and darn simple to implement. The end result is that web services requests that took from 200ms to 500ms and sometimes more (I told you it was slow) are now cache retrievals that take from 2ms to 5ms. That&amp;#8217;s &lt;strong&gt;10,000%&lt;/strong&gt; faster. From 20 lines of code. With all the power and flexibility of the caching already built in to Rails. &lt;a href="http://catb.org/jargon/html/W/winnage.html"&gt;Winnage&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;A Brief Review of ActiveSupport Caching&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ActiveSupport&lt;/code&gt; caching is used by Rails to provide page, action, fragment and SQL caching. With SQL caching, the results of a SQL query are cached in memory for a given action so that repeated queries within an action hit the cache rather than the database. The &lt;a href="http://guides.rubyonrails.org/caching_with_rails.html"&gt;Caching With Rails&lt;/a&gt; guide has a section on &lt;a href="http://guides.rubyonrails.org/caching_with_rails.html#sql-caching"&gt;SQL Caching&lt;/a&gt; that provides a brief overview of the concept. For a more thorough introduction to caching in general, check out Ryan Tomayko&amp;#8217;s &lt;a href="http://tomayko.com/writings/things-caches-do"&gt;&amp;#8220;Things Caches Do&amp;#8221;&lt;/a&gt;. It has sweet illustrations.&lt;/p&gt;
&lt;p&gt;Our strategy is similar to SQL caching, except that we want to persist the cache rather than emptying it after each rails request. The API documentation for &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/Cache.html"&gt;&lt;code&gt;ActiveSupport::Cache&lt;/code&gt;&lt;/a&gt; explains how to set up a cache store and we will implement caching using the interface provided by the abstract class &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html"&gt;&lt;code&gt;ActiveSupport::Cache::Store&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Caching A RESTful Web Service&lt;/h3&gt;
&lt;p&gt;We need to set up a cache store and determine whether or not we&amp;#8217;re going to use caching. This will work similar to &lt;code&gt;ActionController::Base.cache_store&lt;/code&gt;.&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;Endeca&lt;/span&gt;
  &lt;span class="r"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="cl"&gt;self&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_store&lt;/span&gt;; &lt;span class="iv"&gt;@cache_store&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;perform_caching?&lt;/span&gt;; !&lt;span class="iv"&gt;@cache_store&lt;/span&gt;.nil? &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_store=&lt;/span&gt;(store_option)
      &lt;span class="iv"&gt;@cache_store&lt;/span&gt; = &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;Cache&lt;/span&gt;.lookup_store(store_option)
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next, we need a unique cache key. Because we&amp;#8217;re caching a web service that provides &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html"&gt;safe and idempotent&lt;/a&gt; &lt;code&gt;GET&lt;/code&gt; requests, the simplest cache key is the &lt;code&gt;Request-URI&lt;/code&gt; itself. We&amp;#8217;ll &lt;code&gt;SHA1&lt;/code&gt; encode it for space and consistency, but this step is optional (and will require &lt;code&gt;digest/sha1&lt;/code&gt; from the Ruby standard library).&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_key&lt;/span&gt;
  &lt;span class="co"&gt;Digest&lt;/span&gt;::&lt;span class="co"&gt;SHA1&lt;/span&gt;.hexdigest uri.to_s
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We&amp;#8217;ll write a wrapper for &lt;code&gt;ActiveSupport::Cache::Store#fetch&lt;/code&gt; that uses the generated cache key:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;fetch&lt;/span&gt;(&amp;amp;block)
  &lt;span class="co"&gt;Endeca&lt;/span&gt;.cache_store.fetch(cache_key, &amp;amp;block)
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We&amp;#8217;ll also hook into the client&amp;#8217;s &lt;code&gt;get_request&lt;/code&gt; method (which performs the request and returns the &lt;acronym title="JavaScript Object Notation"&gt;JSON&lt;/acronym&gt; body of the response) using Rails&amp;#8217; &lt;code&gt;alias_method_chain&lt;/code&gt;. We need to return the response directly unless we are performing caching. If we are performing caching, we attempt to fetch the cached response. If the cache retrieval fails, we make the actual web service call, cache the result, and return it. Here&amp;#8217;s that code:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get_response_with_caching&lt;/span&gt;
  &lt;span class="r"&gt;return&lt;/span&gt; get_response_without_caching &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;Endeca&lt;/span&gt;.perform_caching?
  fetch { get_response_without_caching }
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;#fetch&lt;/code&gt; method provided by &lt;code&gt;ActiveSupport::Cache::Store&lt;/code&gt; is a particularly useful pattern. It takes a cache key and does a cache lookup (à la &lt;code&gt;#read&lt;/code&gt;). If a value is cached by that key &amp;#8211; a cache hit &amp;#8211; then it is returned. So far, so good. But here&amp;#8217;s where it gets interesting: if there isn&amp;#8217;t a value for that cache key &amp;#8211; a cache miss &amp;#8211; then one of two things happens. Either &lt;code&gt;nil&lt;/code&gt; is returned or, if a block is given, that block is executed and the result is both written to the cache (à la &lt;code&gt;#write&lt;/code&gt;) and returned.&lt;/p&gt;
&lt;p&gt;Finally, we hook up the &lt;code&gt;alias_method_chain&lt;/code&gt; when the module is included:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.included(base)
  base.alias_method_chain &lt;span class="sy"&gt;:get_response&lt;/span&gt;, &lt;span class="sy"&gt;:caching&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And that&amp;#8217;s it. Seriously. &lt;a href="http://github.com/primedia/endeca/blob/b2869176c90adfe351e76a225a521a22297d1b4a/lib/endeca/caching.rb"&gt;The entire caching code&lt;/a&gt; is available on the githubs for you to review. Yes, &lt;a href="http://github.com/primedia/endeca/blob/b2869176c90adfe351e76a225a521a22297d1b4a/spec/endeca/caching_spec.rb"&gt;it has tests&lt;/a&gt;. This caching strategy can be reused to provide a transparent caching layer for many applications. It also works out of box with all of the cache stores provided by Rails, which means that if you are already using memcache for your rails caching in production then this will plug right in without any extra fuss.&lt;/p&gt;
&lt;p&gt;The caching code is reproduced here in its entirety (minus documentation) for your reading pleasure:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="c"&gt;# lib/endeca/caching.rb&lt;/span&gt;

require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;digest/sha1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;

require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;active_support/core_ext/module/aliasing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;active_support/core_ext/array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;active_support/core_ext/class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;active_support/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;Endeca&lt;/span&gt;

  &lt;span class="r"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="cl"&gt;self&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;perform_caching?&lt;/span&gt;; !&lt;span class="iv"&gt;@cache_store&lt;/span&gt;.nil? &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_store&lt;/span&gt;; &lt;span class="iv"&gt;@cache_store&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_store=&lt;/span&gt;(store_option)
      &lt;span class="iv"&gt;@cache_store&lt;/span&gt; = &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;Cache&lt;/span&gt;.lookup_store(store_option)
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;

  &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;Caching&lt;/span&gt;    
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.included(base)
      base.alias_method_chain &lt;span class="sy"&gt;:get_response&lt;/span&gt;, &lt;span class="sy"&gt;:caching&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;

    private

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get_response_with_caching&lt;/span&gt;
      &lt;span class="r"&gt;return&lt;/span&gt; get_response_without_caching &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;Endeca&lt;/span&gt;.perform_caching?
      fetch { get_response_without_caching }
    &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;cache_key&lt;/span&gt;; &lt;span class="co"&gt;Digest&lt;/span&gt;::&lt;span class="co"&gt;SHA1&lt;/span&gt;.hexdigest uri.to_s &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;fetch&lt;/span&gt;(&amp;amp;block); &lt;span class="co"&gt;Endeca&lt;/span&gt;.cache_store.fetch(cache_key, &amp;amp;block) &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/VIZkXEfUzQo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2009/04/27/how-to-cache-anything-with-activesupport.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Custom FiveRuns TuneUp&amp;nbsp;Instrumentation</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/FkKcsX1thy4/custom-fiveruns-tuneup-instrumentation.html" />
    <id>tag:reinh.com,2009-04-21:1240327823</id>
    <published>2009-04-21T11:30:23-04:00</published>
    <updated>2009-04-21T11:30:23-04:00</updated>
    <content type="html">&lt;p&gt;&lt;img src="http://reinh.com/images/product_tuneup.gif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.fiveruns.com/products/tuneup"&gt;TuneUp&lt;/a&gt; is a development performance monitoring tool from &lt;a href="http://www.fiveruns.com"&gt;FiveRuns&lt;/a&gt;. It can help you catch poorly performing actions and queries early and is a great tool to add to your performance monitoring toolbelt. TuneUp also makes it very simple to add custom instrumentation to your Rails app, which came in handy when we needed to report on web service queries made by our Endeca client.&lt;/p&gt;
&lt;p&gt;A brief chat with &lt;a href="http://codefluency.com"&gt;Bruce Williams&lt;/a&gt; helped point the way to TuneUp&amp;#8217;s &lt;code&gt;FiveRuns::TuneUp.step&lt;/code&gt;, the jumping-off point for its instrumentation of your model, view and controller activity. We were able to write a simple plugin that adds instrumentation to calls made by the &lt;a href="http://github.com/primedia/endeca"&gt;Primedia Endeca gem&lt;/a&gt; (a gem used to consume Endeca&amp;#8217;s RESTful JSON bridge API).&lt;/p&gt;
&lt;p&gt;The plugin takes advantage of &lt;code&gt;alias_method_chain&lt;/code&gt; to add instrumentation to the Endeca query methods. This solution is very clean and is idiomatic to Rails itself as Rails uses &lt;code&gt;alias_method_chain&lt;/code&gt; to &amp;#8220;embellish&amp;#8221; many parts of the request response cycle for things like benchmarking and caching, as &lt;a href="http://www.loudthinking.com/posts/33-myth-4-rails-is-a-monolith"&gt;David mentions&lt;/a&gt; in a blog post from his Rails Myths series&lt;/p&gt;
&lt;p&gt;If you want to look at the code, you can find the plugin at its &lt;a href="http://github.com/primedia/endeca_tuneup"&gt;github repo&lt;/a&gt;. All the code is in the &lt;a href="http://github.com/primedia/endeca_tuneup/blob/0e59b0c1f2bdac7f09bb07649b6aab5541aebd7d/init.rb"&gt;&lt;code&gt;init.rb&lt;/code&gt;&lt;/a&gt; but I&amp;#8217;ll reprint it here for convenience. Note that we could have refactored these similar method definitions using metaprogramming techniques but chose not to do so for reasons of simplicity and clarity.&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="r"&gt;defined?&lt;/span&gt; &lt;span class="co"&gt;FiveRuns&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="r"&gt;defined?&lt;/span&gt; &lt;span class="co"&gt;Endeca&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="r"&gt;defined?&lt;/span&gt; &lt;span class="co"&gt;Endeca&lt;/span&gt;::&lt;span class="co"&gt;Document&lt;/span&gt;
  &lt;span class="c"&gt;# Tuneup instrumentation&lt;/span&gt;
  &lt;span class="r"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="cl"&gt;Endeca::Document&lt;/span&gt;
    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;all_with_tuneup&lt;/span&gt;(*args)
      &lt;span class="co"&gt;Fiveruns&lt;/span&gt;::&lt;span class="co"&gt;Tuneup&lt;/span&gt;.step &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.all&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:model&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
        all_without_tuneup(*args)
      &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
    alias_method_chain &lt;span class="sy"&gt;:all&lt;/span&gt;, &lt;span class="sy"&gt;:tuneup&lt;/span&gt;

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;first_with_tuneup&lt;/span&gt;(*args)
      &lt;span class="co"&gt;Fiveruns&lt;/span&gt;::&lt;span class="co"&gt;Tuneup&lt;/span&gt;.step &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.first&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:model&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
        first_without_tuneup(*args)
      &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
    alias_method_chain &lt;span class="sy"&gt;:first&lt;/span&gt;, &lt;span class="sy"&gt;:tuneup&lt;/span&gt;

    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;by_id_with_tuneup&lt;/span&gt;(*args)
      &lt;span class="co"&gt;Fiveruns&lt;/span&gt;::&lt;span class="co"&gt;Tuneup&lt;/span&gt;.step &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.by_id&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:model&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
        by_id_without_tuneup(*args)
      &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
    alias_method_chain &lt;span class="sy"&gt;:by_id&lt;/span&gt;, &lt;span class="sy"&gt;:tuneup&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/FkKcsX1thy4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2009/04/21/custom-fiveruns-tuneup-instrumentation.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Simplify Your Dev Environment With Passenger&amp;nbsp;Pane</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/j5LM3K0Ci2E/simplify-your-dev-environment-with-passenger-pane.html" />
    <id>tag:reinh.com,2009-04-17:1239977051</id>
    <published>2009-04-17T10:04:11-04:00</published>
    <updated>2009-04-17T10:04:11-04:00</updated>
    <content type="html">&lt;p&gt;&lt;img src="http://reinh.com/images/phusion-logo.png" alt=""&gt;&lt;/p&gt;


&lt;p&gt;On OS X? Develop web applications with Rails? Or Merb? Or Sinatra? Or any other Rack compatible framework? Want drag-and-drop and point-and-click development server management? Then you need Passenger Pane. We&amp;#8217;ll walk you through the installation process and show you how to get a simple Rack application up and running. Thanks to &lt;a href="http://jasonnoble.org"&gt;Jason Noble&lt;/a&gt; for his help getting everything working.&lt;/p&gt;


&lt;p&gt;Passenger Pane is an OS X preference pane designed to work in concert with Phusion Passenger and your OS X Leopard's default Apache2 installation (the same one that serves your Web Sharing). Setup is pretty simple and will probably take about 10 minutes. Here's what we're going to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install Phusion Passenger&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Passenger Pane&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Serve a "Hello World!" Rack endpoint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Profit!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;Install Phusion Passenger&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.modrails.com"&gt;Phusion Passenger&lt;/a&gt; is the (not so) new hotness in the Rails deployment world. Phusion is great for serving Rails applications via Apache in production (especially in concert with Rails Enterprise Edition, which provides a 33% memory savings over standard MRI Ruby), but it's also great for simplifying your development environment.&lt;/p&gt;

&lt;p&gt;The Phusion team have done a great job on the passenger install. Here are the &lt;a href="http://www.modrails.com/install.html"&gt;official installation instructions&lt;/a&gt;. We'll repeat them here for the sake of convenience.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open a Terminal window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the passenger gem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo gem install passenger
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the passenger apache2 module:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo passenger-install-apache2-module
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Include the module and some supporting configuration settings into an apache conf file. The code will be provided by the passenger install script.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, add a &lt;code&gt;Directory&lt;/code&gt; directive to your apache2 config that allows access to the directory where your app source codes are located. You can put this at the bottom of your &lt;code&gt;passenger.conf&lt;/code&gt; file (replace my source directory with yours):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Directory /Users/reinh/code/&amp;gt;
  Order Allow,Deny
  Allow from all
&amp;lt;/Directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p class="note"&gt;&lt;strong&gt;Note:&lt;/strong&gt; We put the passenger apache configuration in &lt;code&gt;/etc/apach2/other/passenger.conf&lt;/code&gt; (a file we created). The default apache2 &lt;code&gt;httpd.conf&lt;/code&gt; imports all &lt;code&gt;.conf&lt;/code&gt; files in &lt;code&gt;/etc/apache2/other&lt;/code&gt;.&lt;/p&gt;


&lt;h3&gt;Install Passenger Pane&lt;/h3&gt;

&lt;p class="right"&gt;
    &lt;a href="http://www.fngtps.com/2008/06/putting-the-pane-back-into-deployment" alt="Passenger Pane"&gt;
        &lt;img src="http://reinh.com/images/passenger_icon.png"&gt;
    &lt;/a&gt;
&lt;/p&gt;


&lt;p&gt;&lt;a href="http://www.fngtps.com/2008/06/putting-the-pane-back-into-deployment"&gt;Passenger Pane&lt;/a&gt; gives you a Preference Pane that lets you add, remove and manage apps deployed on Phusion Passenger. Drag-and-drop to serve a new app and restart with a single click &amp;mdash; it even provides host entries for each app so you don't have to mess with virtual hosts or your hosts file. This is great for serving multiple applications simultaneously or just generally being awesome.&lt;/p&gt;

&lt;p&gt;Installation is simple. Download the preference pane from &lt;a href="http://www.fngtps.com/2008/06/putting-the-pane-back-into-deployment"&gt;their homepage&lt;/a&gt; and double-click to install. If you installed Passenger correctly (as above), this should just work. If not, look for errors in Console.app or a helpful notice in the preference pane and ask for help on the &lt;a href="http://groups.google.com/group/phusion-passenger"&gt;Passenger forums&lt;/a&gt; or in the &lt;code&gt;#passenger&lt;/code&gt; channel on &lt;code&gt;irc.freenode.net&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After installing Passenger Pane, you will need to restart Apache. The simplest way to do this on OS X is to open the Sharing preference pane and uncheck and recheck Web Sharing.&lt;/p&gt;

&lt;h3&gt;Serve A "Hello World!" Rack Endpoint&lt;/h3&gt;

&lt;p&gt;Let's test that everything is working by creating a simple &lt;a href="http://rack.rubyforge.org/"&gt;Rack&lt;/a&gt; "Hello World!" endpoint.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install &lt;code&gt;rack&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo gem install rack
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new directory called &lt;code&gt;rack-hello-world&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a file inside it called &lt;code&gt;config.ru&lt;/code&gt; with these contents:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;run lambda{|env| [200, {"Content-Type" =&amp;gt; "text/plain"}, ["Hello World!"]]}
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;public&lt;/code&gt; directory inside &lt;code&gt;rack-hello-world&lt;/code&gt; (you'll see why later).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag the &lt;code&gt;rack-hello-world&lt;/code&gt; folder into your Passenger Pane panel (if you're using TextMate, you can drag it from the project panel). You will probably need to click the lock first to allow modifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browse to &lt;code&gt;&lt;a href="http://rack-hello-world.local"&gt;http://rack-hello-world.local&lt;/a&gt;&lt;/code&gt; and behold the awesome!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Profit!!!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;If you've done this correctly, your Passenger Pane should look similar to this:&lt;/p&gt;

&lt;p class="screenshot"&gt;
    &lt;img src="http://reinh.com/images/passenger_pane.png"&gt;
&lt;/p&gt;


&lt;p&gt;Your browser should be showing you your glorious "Hello World!" homepage.&lt;/p&gt;

&lt;p&gt;Now you can drag in the app folders of any Rails, Merb, Sinatra or Ramaze applications and have them instantly served by Passenger. In fact, any Ruby web application that can run on Rack can be run in Passenger Pane. How's that for a painless local development environment?&lt;/p&gt;

&lt;p class="note"&gt;&lt;strong&gt;Note:&lt;/strong&gt; Why (I hear you asking) did we create a public directory? The answer is that Apache expects to serve a public directory and will fail if one is not found under the root of the app you're serving. If you had not created the directory, you would have to look at your apache error log (usually located at &lt;code&gt;/var/log/apache2/error_log&lt;/code&gt;) to find out what went wrong.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/j5LM3K0Ci2E" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2009/04/17/simplify-your-dev-environment-with-passenger-pane.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">A Git Workflow for Agile&amp;nbsp;Teams</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/haonYIF0yWU/a-git-workflow-for-agile-teams.html" />
    <id>tag:reinh.com,2009-03-02:1236042355</id>
    <published>2009-03-02T20:05:55-05:00</published>
    <updated>2009-03-02T20:05:55-05:00</updated>
    <content type="html">&lt;p&gt;At &lt;a href="http://hashrocket.com"&gt;Hashrocket&lt;/a&gt; we use git both internally and in our Agile mentoring and training. Git gives us the flexibility to design a version control workflow that meets the needs of either a fully Agile team or a team that is transitioning towards an Agile process.&lt;/p&gt;
&lt;p&gt;There are many usable git workflows. Indeed, git is really &amp;#8220;a tool for designing VCS workflows&amp;#8221; rather than a Version Control System itself&lt;sup class="footnote"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;. Or, as Linus would say, git is just a stupid content tracker&lt;sup class="footnote"&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;This is by no means a normative document or my attempt to define The One True Workflow. I have found this workflow to be productive and relatively painless, especially for teams that are still learning and transitioning towards a more Agile process. I invite you to comment below and describe the git workflow that works best for you.&lt;/p&gt;
&lt;h3 id="thanks"&gt;Thanks&lt;/h3&gt;
&lt;p&gt;Anyone interested in using git in an Agile environment should read Josh Susser&amp;#8217;s &lt;cite&gt;Agile Git and the Story Branch Pattern&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/cite&gt;. This workflow is based largely on his.&lt;/p&gt;
&lt;p&gt;The process of squashing commits into more atomic and incremental units has been described by Justin Reagor in &lt;cite&gt;A &amp;#8220;Squash&amp;#8221; WorkFlow in Git&lt;sup class="footnote"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/cite&gt;. Justin&amp;#8217;s post also references a &lt;code&gt;git rebase -i&lt;/code&gt; walkthrough by MadCoder&lt;sup class="footnote"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; that provides a good explanation the interactive rebase process.&lt;/p&gt;
&lt;p&gt;Thanks also to &lt;a href="http://www.rickbradley.com/"&gt;Rick Bradley&lt;/a&gt; of &lt;a href="http://www.ogtastic.com/"&gt;OG Consulting&lt;/a&gt; and &lt;a href="http://blog.hasmanythrough.com/"&gt;Josh Susser&lt;/a&gt; of &lt;a href="http://pivotallabs.com"&gt;Pivotal Labs&lt;/a&gt; for many fruitful and often hilarious discussions about git, Agile and ponies.&lt;/p&gt;
&lt;h3 id="top"&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="#feature-development"&gt;Feature Development&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#bug-fixes"&gt;Bug Fixes&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#qa-branch-management"&gt;QA Branch Management&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#production-tagging"&gt;Production Tagging&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#summary"&gt;Summary&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#notes"&gt;Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="feature-development"&gt;Feature Development&lt;/h3&gt;
&lt;p&gt;Our git feature development workflow consists of these steps:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;p&gt;Pull to update your local master&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Check out a feature branch&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Do work in your feature branch, committing early and often&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Rebase frequently to incorporate upstream changes&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Interactive rebase (squash) your commits&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Merge your changes with master&lt;/p&gt;&lt;/li&gt;
	&lt;li&gt;&lt;p&gt;Push your changes to the upstream&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First, and while in your master branch (&lt;code&gt;git checkout master&lt;/code&gt;), pull in the most recent changes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git pull origin master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should never create a merge commit because we are never working directly in master.&lt;/p&gt;
&lt;p class="note"&gt;&lt;strong&gt;NB:&lt;/strong&gt; Whenever you perform a pull, merge or rebase, make sure that you run tests directly afterwards. Git may not show any conflicts but that doesn&amp;#8217;t mean that two changes are compatible. Also run tests before you commit (of course).&lt;/p&gt;
&lt;p&gt;We begin with the topmost available story in &lt;a href="http://pivotaltracker.com"&gt;Pivotal Tracker&lt;/a&gt;. Let&amp;#8217;s say that it&amp;#8217;s &lt;em&gt;#3275: User Can Add A Comment To a Post&lt;/em&gt;. First, check out a feature branch named with the story id and a short, descriptive title:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout -b 3275-add-commenting&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The id allows us to easily track this branch back to the story that spawned it. The title is there to give us humans a little hint as to what&amp;#8217;s in it. Do some work on this branch, committing early and often (for instance, whenever your tests pass). Rebase against the upstream frequently to prevent your branch from diverging significantly:&lt;/p&gt;
&lt;div id="rebase"&gt;&lt;pre&gt;&lt;code&gt;git fetch origin master
git rebase origin/master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;NB:&lt;/strong&gt; This is often done by checking master out and pulling, but this method requires extra steps:&lt;/p&gt;
&lt;pre class="bottom"&gt;&lt;code&gt;git checkout master
git pull
git checkout 3275-add-commenting
git rebase master&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Once work on the feature is complete, you will have a branch with a lot of small commits like &amp;#8220;adding a model and a migration&amp;#8221;, &amp;#8220;adding a controller and some views&amp;#8221;, &amp;#8220;oh crap &amp;#8211; adding tests&amp;#8221; and so on. This is useful while developing but larger, incremental commits are more easier to maintain. We will use an interactive rebase&lt;sup class="footnote"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; to squash them together. &lt;span class="quiet"&gt;Also, squashing these commits together will allow us to pretend that we wrote the tests first&amp;hellip;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We want the rebase to affect only the commits we&amp;#8217;ve made to this branch, not the commits that exist on the upstream. To ensure that we only deal with the &amp;#8220;local&amp;#8221; commits, use:&lt;/p&gt;
&lt;div id="interactive"&gt;&lt;pre&gt;&lt;code&gt;git rebase -i origin/master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Git will display an editor window with a list of the commits to be modified, something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pick 3dcd585 Adding Comment model, migrations, spec
pick 9f5c362 Adding Comment controller, helper, spec
pick dcd4813 Adding Comment relationship with Post
pick 977a754 Comment belongs to a User
pick 9ea48e3 Comment form on Post show page
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we tell git what we to do. Change these lines to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pick 3dcd585 Adding Comment model, migrations, spec
squash 9f5c362 Adding Comment controller, helper, spec
squash dcd4813 Adding Comment relationship with Post
squash 977a754 Comment belongs to a User
squash 9ea48e3 Comment form on Post show page
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save and close the file. This will squash these commits together into one commit and present us with a new editor window where we can give the new commit a message. We&amp;#8217;ll use the story id and title for the subject and list the original commit messages in the body:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[#3275] User Can Add A Comment To a Post

* Adding Comment model, migrations, spec
* Adding Comment controller, helper, spec
* Adding Comment relationship with Post
* Comment belongs to a User
* Comment form on Post show page
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This also follows Tim Pope&amp;#8217;s &lt;a href="http://www.tpope.net/node/106"&gt;git commit message best practices&lt;/a&gt;. Now, save and close your editor. This commit is now ready to be merged back into master. First &lt;a href="#rebase" class="facebox"&gt;rebase against any recent changes in the upstream&lt;/a&gt;. Then merge your changes back into master:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout master
git merge 3275-add-commenting&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, push your changes to the upstream:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git push origin master&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="bug-fixes"&gt;Bug Fixes&lt;/h3&gt;
&lt;p&gt;Bugfixes will use the same workflow as feature work. Name your bugfix branch after the bug id and give it a descriptive name. Prefix the branch name with &amp;#8220;bug&amp;#8221; to help you keep track of them, for instance: &lt;code&gt;bug-3845-empty-comments-allowed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Do work in your bugfix branch, committing early and often. &lt;a href="#rebase" class="facebox"&gt;Rebase&lt;/a&gt; frequently against the upstream and again when you are finished. Then, use an &lt;a href="#interactive" class="facebox"&gt;interactive rebase&lt;/a&gt; to squash &lt;strong&gt;all&lt;/strong&gt; the commits together. Use the bug id and title for the subject of the new commit. Include &amp;#8220;BUG&amp;#8221; or &amp;#8220;BUGFIX&amp;#8221; to make these commits easier to identify. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[#3278] BUGFIX: Empty Comments Should Not Be Allowed&lt;/code&gt;&lt;/pre&gt;
&lt;p class="note"&gt;&lt;strong&gt;NB:&lt;/strong&gt; With a bugfix, squash the commits down into one and exactly one commit that completely represents that bugfix. Half of a bugfix is useless.&lt;/p&gt;
&lt;h3 id="qa-branch-management"&gt;&lt;abbr title="Quality Assurance"&gt;QA&lt;/abbr&gt; Branch Management&lt;/h3&gt;
&lt;p&gt;In a truly Agile process, as Josh Susser explained to me, you simply deploy directly from your latest &amp;#8220;green&amp;#8221; build. While this may seem impossible, there are real world examples of the viability of Continuous Deployment&lt;sup class="footnote"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;For most of the teams we train, this sort of extreme agility is a goal rather than a way of life. They are transitioning towards a fully Agile process from a more rigorous one and often have a significant investment in Quality Assurance. For these teams, I recommend a compromise solution: Use a remote QA branch that is fast-forward merged from the latest &amp;#8220;green&amp;#8221; (all &lt;abbr title="Continuous Integration"&gt;CI&lt;/abbr&gt; tests pass) master build for QA deployments.&lt;/p&gt;
&lt;p&gt;If you don&amp;#8217;t already have a QA branch, create one from the current master (assuming it&amp;#8217;s green) and then push it to your git host:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout -b qa
git push origin qa:refs/heads/qa&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To update an existing QA branch with the latest changes from master, do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout qa
git merge master
git push origin qa&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ensure that the master branch is green when you merge. Also ensure that this merge is always a Fast Forward merge. If it is not, it means that commits have been made in the QA branch that are not in the master branch. QA should be merged into from master only, never worked on directly.&lt;/p&gt;
&lt;h3 id="production-tagging"&gt;Production Tagging&lt;/h3&gt;
&lt;p&gt;While an Agile team will be deploying continuously, most teams will require a more rigorous vetting process before a build is deployed to production. Tags provide a simple way for QA to vet a particular build.&lt;/p&gt;
&lt;p&gt;Once QA has signed off on a build as ready for production, a tag should be made and deployed. In git, a tag can be created with &lt;code&gt;git tag &amp;lt;name&amp;gt;&lt;/code&gt;. It is important that tag naming is consistent and it is useful if they sort in a meaningful way (latest last, for instance). Two good options are a timestamp or product version. Use whichever is more meaningful to your team.&lt;/p&gt;
&lt;p&gt;The process of creating a timestamped production tag can be automated with a simple script or a git alias like this one:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config alias.datetag '!git tag `date "+%Y%m%d%H%M"`'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this alias, &lt;code&gt;git datetag&lt;/code&gt; will create a new tag from &lt;code&gt;HEAD&lt;/code&gt; with the current timestamp. You will want to be in the QA branch. If the QA branch has moved beyond the last commit vetted by your QA team, be sure to checkout that commit first.&lt;/p&gt;
&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;a href="http://blog.hasmanythrough.com/2008/12/18/agile-git-and-the-story-branch-pattern"&gt;Agile git and the story branch pattern&lt;/a&gt; by &lt;a href="http://blog.hasmanythrough.com/"&gt;Josh Susser&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; &lt;a href="http://blog.kineticweb.com/articles/2008/08/02/a-squash-workflow-in-git"&gt;A Squash WorkFlow in Git&lt;/a&gt; by &lt;a href="http://blog.kineticweb.com/"&gt;Justin Reagor&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; &lt;a href="http://blog.madism.org/index.php/2007/09/09/138-git-awsome-ness-git-rebase-interactive"&gt;git awsome-ness [git rebase &amp;#8212;interactive]&lt;/a&gt; by &lt;a href="http://blog.madism.org/index.php/"&gt;MadCoder&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;sup&gt;4&lt;/sup&gt; &lt;a href="http://timothyfitz.wordpress.com/2009/02/08/continuous-deployment/"&gt;Continuous Deployment&lt;/a&gt; and &lt;a href="http://timothyfitz.wordpress.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/"&gt;Continuous Deployment at IMVU: Doing the impossible fifty times a day&lt;/a&gt; by &lt;a href="http://timothyfitz.wordpress.com"&gt;Timothy Fritz&lt;/a&gt; of &lt;a href="http://www.imvu.com/"&gt;IMVU&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;sup&gt;5&lt;/sup&gt; &lt;a href="http://osteele.com/archives/2008/05/my-git-workflow"&gt;My Git Workflow&lt;/a&gt; by &lt;a href="http://osteele.com/"&gt;Oliver Steele&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn6"&gt;&lt;sup&gt;6&lt;/sup&gt; &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/"&gt;git(1) Manaual Page&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/haonYIF0yWU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2009/03/02/a-git-workflow-for-agile-teams.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">REST &amp;&amp;nbsp;Rails</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/goL8um63Q_I/rest-and-rails.html" />
    <id>tag:reinh.com,2007-11-13:1194974956</id>
    <published>2007-11-13T12:29:16-05:00</published>
    <updated>2007-11-13T12:29:16-05:00</updated>
    <content type="html">&lt;p&gt;I am giving a presentation on Rails, REST, and the Resource Oriented Architecture today entitled &amp;#8220;REST &amp;amp; Rails: Web Services for the Rails World&amp;#8221;. Check out &lt;a href="http://assets.reinh.com/talks/REST-and-Rails.pdf"&gt;the slides&lt;/a&gt;.&lt;/p&gt;
&lt;a href="http://assets.reinh.com/talks/REST-and-Rails.pdf" title="REST &amp;amp; Rails"&gt;&lt;img src="http://assets.reinh.com/images/REST-and-Rails.gif" title="REST &amp;amp; Rails"&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/goL8um63Q_I" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2007/11/13/rest-and-rails.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Story Driven Development With&amp;nbsp;Rails</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/HP3m2DV_L4c/story-driven-development-with-rails.html" />
    <id>tag:reinh.com,2008-12-09:1228843346</id>
    <published>2008-12-09T12:22:26-05:00</published>
    <updated>2008-12-09T12:22:26-05:00</updated>
    <content type="html">&lt;p&gt;As a follow up on &lt;a href="http://reinh.com/blog/2008/08/29/incremental-stories-and-micro-releases.html"&gt;writing incremental stories&lt;/a&gt;, we&amp;#8217;re going to take the first story and walk through a behavior driven development process to implement it in a simple Rails application. We will focus on making small, iterative changes and following a strict test-first philosophy where we write granular unit tests and implement them with just enough code to make them pass.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s review our first story:&lt;/p&gt;
&lt;div class='story box negative'&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To View A List Of Projects&lt;br&gt;
&lt;span class="small"&gt;So that I can find a project that interests me&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance clear"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;All projects shown in list&lt;/li&gt;
	&lt;li&gt;List is paginated&lt;/li&gt;
	&lt;li&gt;List is sorted by age&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 1 Point&lt;/h5&gt;
&lt;/div&gt;
&lt;p&gt;At this point, let&amp;#8217;s assume that this story is on top of our current iteration.  First, we&amp;#8217;ll need to review the story for any missing information and communicate with the client to clear up any questions. Keep in mind that a story is just a way to capture a conversation about a feature. It is not set in stone. After talking to the client, we find that we will need to display a project&amp;#8217;s author name and title and that the title will need to link to that project&amp;#8217;s page. Let&amp;#8217;s update the story appropriately.&lt;/p&gt;
&lt;div class='story box negative'&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To View A List Of Projects&lt;br&gt;
&lt;span class="small"&gt;So that I can find a project that interests me&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance clear"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;All projects shown in list&lt;/li&gt;
	&lt;li&gt;Show title for each project&lt;/li&gt;
	&lt;li&gt;Show author name for each project&lt;/li&gt;
	&lt;li&gt;Project title links to the project&amp;#8217;s page&lt;/li&gt;
	&lt;li&gt;List is paginated&lt;/li&gt;
	&lt;li&gt;List is sorted by project age&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 1 Point&lt;/h5&gt;
&lt;/div&gt;
&lt;p&gt;Now that the story is complete, deliverable and acceptable, we can begin work on the new feature. A implementation plan should be forming in your head. Now is the time to divide the work into testable units. In our case we already have a Project model with the requisite fields (let&amp;#8217;s say) so our work will focus on the controller and view.&lt;/p&gt;
&lt;h3&gt;Test All The F***ing Time&lt;/h3&gt;
&lt;p&gt;Client sign-off on well written acceptance tests means that the specifications you write and the feature that is implemented as a result will be more closely in line with the client&amp;#8217;s expectations. This minimizes the kind of impedance mismatch between expectation and execution that so often plagues a project with poor client communication and a disorganized process.&lt;/p&gt;
&lt;p&gt;Now it&amp;#8217;s time to take our acceptance tests and use them to drive our iterative, test-driven development process. Let&amp;#8217;s take it from the top.&lt;/p&gt;
&lt;h4&gt;All Projects Shown in List&lt;/h4&gt;
&lt;p&gt;Let&amp;#8217;s start with the controller. A list of projects needs an index action. Starting at the top, we will need to load all of the projects. Let&amp;#8217;s write a test for this:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;describe &lt;span class="co"&gt;ProjectsController&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  describe &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;getting a list of products&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;loads all the projects&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
      projects = [mock_model(&lt;span class="co"&gt;Project&lt;/span&gt;)]
      &lt;span class="co"&gt;Project&lt;/span&gt;.stub!(&lt;span class="sy"&gt;:all&lt;/span&gt;).and_return(projects)

      get &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;

      assigns(&lt;span class="sy"&gt;:projects&lt;/span&gt;).should == projects
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class='negative box hilight'&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Stubbing the call to &lt;code&gt;Project.all&lt;/code&gt; has the immediate benefit of eliminating the database from our test but is potentially more brittle since we cannot be sure that this interface point to our Project model will not need to change in the future.&lt;/p&gt;
&lt;p class="bottom"&gt;On a side note, I tend to view controller tests as integration-level tests rather than unit tests. As such, I usually do write tests that touch the database since these are often less brittle. If you write tests that touch the database, ActiveRecord factories such as &lt;a href="http://giantrobots.thoughtbot.com/2008/6/6/waiting-for-a-factory-girl"&gt;Factory Girl&lt;/a&gt; or &lt;a href="http://b.logi.cx/2007/11/26/object-daddy"&gt;object daddy&lt;/a&gt; are useful for populating the database with valid records in known&amp;nbsp;states.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now we can write the implementation:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ProjectsController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;
    &lt;span class="iv"&gt;@projects&lt;/span&gt; = &lt;span class="co"&gt;Project&lt;/span&gt;.all
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then we have to display a list of projects. We&amp;#8217;ll write a view test to cover this:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/projects/index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  before(&lt;span class="sy"&gt;:each&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt;
    &lt;span class="iv"&gt;@project&lt;/span&gt; = mock_model(&lt;span class="co"&gt;Project&lt;/span&gt;)
    &lt;span class="iv"&gt;@projects&lt;/span&gt; = [&lt;span class="iv"&gt;@project&lt;/span&gt;]
    assigns[&lt;span class="sy"&gt;:projects&lt;/span&gt;] = &lt;span class="iv"&gt;@projects&lt;/span&gt;
    render &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;projects/index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
  
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should include a list of projects&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    response.should have_tag(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;li.project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:count&lt;/span&gt; =&amp;gt; &lt;span class="iv"&gt;@projects&lt;/span&gt;.size)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And the implementation:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@projects&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |project| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p class="note"&gt;&lt;strong&gt;Note:&lt;/strong&gt; View tests can often be brittle. They can be made less brittle by testing only for semantically appropriate tags, classes and ids whenever possible. Using semantically rich markup in your views will make it much easier to write robust view tests &amp;#8212; and is also a great practice for its own sake.&lt;/p&gt;
&lt;h4&gt;Show Title for Each Project&lt;/h4&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/projects/index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# SNIP&lt;/span&gt;
  
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should show the title for each project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    response.should have_tag(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;li.project .title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="iv"&gt;@project&lt;/span&gt;.title)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@projects&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |project| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="ta"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; project.title &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;Show Author Name for Each Project&lt;/h4&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/projects/index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# SNIP&lt;/span&gt;
  
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should show the author name for each project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    response.should have_tag(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;li.project .author_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="iv"&gt;@project&lt;/span&gt;.author_name)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@projects&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |project| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="ta"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; project.title &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="ta"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;author_name&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; project.author_name &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="note"&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We are using an accessor on our project model, &lt;code&gt;Project#author_name&lt;/code&gt;. There&amp;#8217;s a good chance that this name will be taken from an associated User or Author model in any non-trivial Rails application. From an object oriented standpoint, however, having the author name hang directly from the Project model improves encapsulation.&lt;/p&gt;
&lt;p class="bottom"&gt;The benefits of this were already seen in the test, where we were able to stub &lt;code&gt;author_name&lt;/code&gt; directly on the Project mock. Without the accessor, we would be forced to stub &lt;code&gt;#author&lt;/code&gt; on the Project mock to return an Author mock that then stubs &lt;code&gt;#name&lt;/code&gt; just so that we could properly test the method chain &lt;code&gt;project.author.name&lt;/code&gt; that is used in the view. Violating the &lt;a href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Law of Demeter&lt;/a&gt; makes testing harder.&lt;/p&gt;
&lt;/div&gt;
&lt;h4&gt;Project Title Links to the Project&amp;#8217;s Page&lt;/h4&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/projects/index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# SNIP&lt;/span&gt;
  
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should have project titles that link to the project page&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    response.should have_tag( &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;li.project .title a[href=?]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, project_path(&lt;span class="iv"&gt;@project&lt;/span&gt;),   
      &lt;span class="sy"&gt;:text&lt;/span&gt; =&amp;gt; &lt;span class="iv"&gt;@project&lt;/span&gt;.title)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@projects&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |project| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;project&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="ta"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; link_to project.title, project &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="ta"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="an"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;author_name&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; project.author_name &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The story is now about half complete. I&amp;#8217;ll leave pagination and default sort order as an exercise for the user. In fact, these could also have been broken out into a secondary story or stories given that what we have done so far is an incremental unit of work.&lt;/p&gt;
&lt;p&gt;I hope this rather contrived example shows how stories with well written acceptance tests inform a test- or behavior- driven development process and help bridge the gap between what the client expects and what the developement team delivers.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/HP3m2DV_L4c" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2008/12/09/story-driven-development-with-rails.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Incremental Stories and&amp;nbsp;Micro&amp;#8209;Releases</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/C3hfYblKtqI/incremental-stories-and-micro-releases.html" />
    <id>tag:reinh.com,2008-08-29:1220044463</id>
    <published>2008-08-29T17:14:23-04:00</published>
    <updated>2008-08-29T17:14:23-04:00</updated>
    <content type="html">&lt;p&gt;&lt;a href="http://www.amazon.com/Agile-Estimating-Planning-Robert-Martin/dp/0131479415"&gt;Agile estimating and planning&lt;/a&gt; is difficult. One of the practices that we are learning and adopting at Hashrocket that has truly improved our ability to ship is &lt;a href="http://www.dtsato.com/blog/2008/08/26/agile-2008-estimating-considered-wasteful-introducing-micro-releases/"&gt;&lt;strong&gt;micro-releases&lt;/strong&gt;&lt;/a&gt;. The idea, championed by author Joshua Kerievsky, is that constantly planning and shipping small, feature based incremental releases within the iterative cycle drives the delivery of tangible business value. In other words, the most important stuff gets shipped sooner.&lt;/p&gt;
&lt;p&gt;Committing to micro-releases ensures that we are constantly working on delivering the highest priority features that represent real business value in an agile, incremental way. Complex stories that won&amp;#8217;t fit into a micro-release cycle are broken down into stories that deliver core value and supporting stories that can be deferred to a later iteration.&lt;/p&gt;
&lt;h3&gt;A Complex Story&lt;/h3&gt;
&lt;div class='story box negative' id="story-1"&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To View A List Of Projects&lt;br&gt;
&lt;span class="small"&gt;So that I can find a project that interests me&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance clear"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;All projects shown in list&lt;/li&gt;
	&lt;li&gt;List is paginated&lt;/li&gt;
	&lt;li&gt;List sorts by age by default&lt;/li&gt;
	&lt;li&gt;List is sortable by the following criteria
	&lt;ul&gt;
		&lt;li&gt;Age&lt;/li&gt;
		&lt;li&gt;Owner&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;List is filterable by the following criteria
	&lt;ul&gt;
		&lt;li&gt;Status&lt;/li&gt;
		&lt;li&gt;Category&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 4 Points&lt;/h5&gt;
&lt;/div&gt;
&lt;p&gt;This is a reasonably good story. It is clear, concise and deliverable. Its acceptance criteria are testable. It adds real business value. A short time ago ago I would have been quite happy to write stories just like this. That&amp;#8217;s not the case today.&lt;/p&gt;
&lt;p&gt;Now that our development process is becoming more geared towards focused micro-releases, the value of incremental stories is becoming exceedingly clear. Writing incremental stories allows us to break complex stories apart into a first increment focused on delivering core value and a set of secondary stories that can be added as later increments to deliver supplementary value.&lt;/p&gt;
&lt;h3&gt;A Simple Primary Story&lt;/h3&gt;
&lt;div class='story box negative'&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To View A List Of Projects&lt;br&gt;
&lt;span class="small"&gt;So that I can find a project that interests me&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance clear"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;All projects shown in list&lt;/li&gt;
	&lt;li&gt;List is paginated&lt;/li&gt;
	&lt;li&gt;List is sorted by age&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 1 Point&lt;/h5&gt;
&lt;/div&gt;
&lt;p&gt;This story is smaller and simpler but it delivers most of the value of the original complex story. Users can browse a list and find projects. Additional value is certainly provided by selecting sort and filtering criteria. But that&amp;#8217;s the point: these provide &lt;strong&gt;additional&lt;/strong&gt; value. The simple primary story is an increment that delivers on the core value behind this feature: users want to discover projects. It&amp;#8217;s the minimum functionality needed to start using the feature.&lt;/p&gt;
&lt;h3&gt;Some Simple Supplementary Stories&lt;/h3&gt;
&lt;div class='story box negative'&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To Sort The Project List&lt;br&gt;
&lt;span class="small"&gt;So that I can better discover projects based on certain criteria&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1.1&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance clear"&gt;Requires:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;A list of projects&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story- acceptance"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;List is sortable by the following criteria
	&lt;ul&gt;
		&lt;li&gt;Age&lt;/li&gt;
		&lt;li&gt;Owner&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 1 Point&lt;/h5&gt;
&lt;/div&gt;
&lt;div class='story box negative'&gt;
&lt;h4 class='story-title column span-14'&gt;
As A User I Want To Filter The Project List&lt;br&gt;
&lt;span class="small"&gt;So that I can browse only projects that match a given criterion&lt;/span&gt;
&lt;/h4&gt;
&lt;h4 style="text-align:right;" class="story-number alt column span-1 last"&gt;#1.2&lt;/h4&gt;
&lt;h5 style="margin-bottom:0;" class="story-requires clear"&gt;Requires:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;A list of projects&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-acceptance"&gt;Acceptance:&lt;/h5&gt;
&lt;ul&gt;
	&lt;li&gt;List is filterable by the following criteria
	&lt;ul&gt;
		&lt;li&gt;Status&lt;/li&gt;
		&lt;li&gt;Category&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 style="margin-bottom:0;" class="story-cost"&gt;Cost: 2 Points&lt;/h5&gt;
&lt;/div&gt;
&lt;p&gt;One interesting and important observation is that the primary story is a one point story while the secondary stories total to three points. This means that these secondary stories represent fully three fourths of the original value of the complex story. In other words, shipping on the core value of the feature becomes much, much easier once it&amp;#8217;s broken up into increments.&lt;/p&gt;
&lt;h3&gt;Ship Leaner Features, Sooner&lt;/h3&gt;
&lt;p&gt;Breaking complex stories into simpler incremental stories becomes especially important in situations where your iterations are extremely time-sensitive. This is precisely the case in our &lt;a href="http://www.hashrocket.com/products"&gt;3-2-1 Launch&lt;/a&gt; projects. Breaking stories into increments allows us to deliver more of the application&amp;#8217;s core value sooner. It also helps clients make real-time decisions about the importance of the primary and secondary value stories separately. Once they can get their hands on the core functionality they often re-prioritize the secondary stories more effectively.&lt;/p&gt;
&lt;p&gt;In the case of this particular story, once the basic list and pagination were out there &amp;#8211; and once project search (another core value feature) was implemented &amp;#8211; it became clear that the secondary project listing stories only duplicated functionality. These secondary stories are cooling off in the icebox as we speak. Meanwhile, we shipped a feature four times leaner and four times sooner.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/C3hfYblKtqI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2008/08/29/incremental-stories-and-micro-releases.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Git Push: Just The&amp;nbsp;Tip</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/hM6uUw5zooI/git-push-just-the-tip.html" />
    <id>tag:reinh.com,2008-04-18:1208531353</id>
    <published>2008-04-18T11:09:13-04:00</published>
    <updated>2008-04-18T11:09:13-04:00</updated>
    <content type="html">&lt;p&gt;Today we delve into the world of &lt;code&gt;git push&lt;/code&gt;, one of the most often used git tools. &lt;code&gt;git push&lt;/code&gt; is typically used to update a remote ref and associated objects based on a local ref &amp;#8211; in other words, to push your local changes to an upstream repository &amp;#8211; but you can also use it to create or delete remote branches and &lt;del&gt;much, much more!&lt;/del&gt; actually, that&amp;#8217;s about it.&lt;/p&gt;
&lt;h3&gt;Just The Tip&lt;/h3&gt;
&lt;p&gt;The most common use of &lt;code&gt;git push&lt;/code&gt; is to push your local changes to your public upstream repository. Assuming that the upstream is a remote named &amp;#8220;origin&amp;#8221; (the default remote name if your repository is a clone) and the branch to be updated to/from is named &amp;#8220;master&amp;#8221; (the default branch name), this is done with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git push origin master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Get used to this. You&amp;#8217;ll be doing it a lot.&lt;/p&gt;
&lt;h3&gt;A Bit Deeper&lt;/h3&gt;
&lt;p&gt;Git uses the term &amp;#8220;refspec&amp;#8221; when describing the usage of some of its commands. A refspec is essentially a name that git can resolve to a commit object. This can be the name of a branch or an arbitrary &amp;#8220;SHA1 expression&amp;#8221; such as &lt;code&gt;master~4&lt;/code&gt;, among &lt;a href="http://www.kernel.org/pub/software/scm/git"&gt;others&lt;/a&gt; core/docs/git rev-parse.html. Git gives you a lot of ways to refer to a commit but for most purposes you&amp;#8217;ll just use the name of a branch with &lt;code&gt;git push&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.kernel.org/pub/software/scm/git"&gt;kernel.org manpage for git pull&lt;/a&gt; core/docs/git push.html#URLS will rather cryptically tell you that &amp;#8220;The canonical format of a &amp;lt;refspec&amp;gt; parameter is &lt;code&gt;+?&amp;lt;src&amp;gt;:&amp;lt;dst&amp;gt;&lt;/code&gt;&amp;#8221;. Most of the time this translates to &lt;code&gt;&amp;lt;branch to push from&amp;gt;:&amp;lt;branch to push to&amp;gt;&lt;/code&gt;. The branch to push from and the colon are optional. If left out, git will push from the local branch to the remote branch of the same name. If no refspec is used at all, git will push all &amp;#8220;heads&amp;#8221; (f.e. branches) on the local to matching heads that exist on the remote.&lt;/p&gt;
&lt;p&gt;In practice, this means that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git push origin&lt;/code&gt; will push changes from all local branches to matching branches the origin remote&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;git push origin master&lt;/code&gt; will push changes from the local master branch to the remote master branch&lt;/li&gt;
	&lt;li&gt;@git push origin master:staginwill push changes from the local master branch to the remote staging branch &lt;em&gt;if it exists&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tips and Tricks&lt;/h3&gt;
&lt;h4&gt;Create a Remote Branch&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;git push origin master:refs/heads/staging&lt;/code&gt; will create the branch &lt;code&gt;staging&lt;/code&gt; in the origin      repository by copying the local &lt;code&gt;master&lt;/code&gt; branch&lt;/p&gt;
&lt;h4&gt;Delete a Remote Branch&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;git push origin :staging&lt;/code&gt; will delete the branch &lt;code&gt;staging&lt;/code&gt; from the origin repository.&lt;/p&gt;
&lt;h4&gt;Set Up A Branch&amp;#8217;s Default Remote&lt;/h4&gt;
&lt;p&gt;You can use git config to assign a default remote to a given branch. This default remote will be used to push that branch unless otherwise specified.&lt;br&gt;
    &lt;br&gt;
This is already done for you when you use &lt;code&gt;git clone&lt;/code&gt;, allowing you to use &lt;code&gt;git push&lt;/code&gt; without any arguments to push the local master branch to update the origin repository&amp;#8217;s master branch.&lt;br&gt;
    &lt;br&gt;
&lt;code&gt;git config branch.&amp;lt;name&amp;gt;.remote &amp;lt;remote&amp;gt;&lt;/code&gt; can be used to specify this manually.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/hM6uUw5zooI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2008/04/18/git-push-just-the-tip.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">To Design A Blog (act&amp;nbsp;2)</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/ciiEq6pgk5M/to-design-a-blog-2.html" />
    <id>tag:reinh.com,2008-02-26:1204079296</id>
    <published>2008-02-26T21:28:16-05:00</published>
    <updated>2008-02-26T21:28:16-05:00</updated>
    <content type="html">&lt;p&gt;fig. 1.1 | ReinH-02.png&lt;/p&gt;
&lt;p&gt;In our &lt;a href="http://reinh.com/2008/02/25/to-design-a-blog-1.html"&gt;first installment&lt;/a&gt;, the typography and layout of the blog were mostly decided. With this ground work in place, it&amp;#8217;s time to start focusing on the details. But first, it&amp;#8217;s time to give our eyes and brain a chance to relax and reset. Staring at the same design for hours tends to give you tunnel-vision and we want to be able to look at the site afresh.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#8217;re ready to continue, the most obvious issue is the arrangement of the sections in the footer. The rest of the design follows a strict grid system but the haphazard placement of the bottom columns is jarring to the eye and the whitespace between them is also problematic. &lt;a href="/images/ReinH-02.png" class="figure-1-1"&gt;figure-1-1)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;fig. 1.2 | ReinH-03.png&lt;/p&gt;
&lt;p&gt;A third column is added and the columns are properly aligned with the grid layout once again &lt;a href="/images/ReinH-03.png" class="figure-1-2"&gt;figure-1-2)&lt;/a&gt;. Great success! The remaining changes are all relatively minor and mainly involve tweaks to font size, color, and spacing. Bonus points if you can spot them.&lt;/p&gt;
&lt;p&gt;Now then: Welcome to the new blog! Enjoy your stay.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/ciiEq6pgk5M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2008/02/26/to-design-a-blog-2.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html">Rocking the&amp;nbsp;Hoedown</title>
    <link href="http://feedproxy.google.com/~r/reinh/~3/vYQ4ZyLXmaY/rocking-the-hoedown.html" />
    <id>tag:reinh.com,2008-08-10:1218391358</id>
    <published>2008-08-10T14:02:38-04:00</published>
    <updated>2008-08-10T14:02:38-04:00</updated>
    <content type="html">&lt;p&gt;&lt;img src="/images/hoedown/hoedown-speaker.png" class="box right" alt=""&gt;&lt;br&gt;
&lt;span class="dropcap w"&gt;W&lt;/span&gt;e had a great time at the Ruby Hoedown this weekend. The &lt;a href="http://hashrocket.com"&gt;Hashrocket&lt;/a&gt; crew was out in force (and there was much debauchery in the Hashrocket RV). We got to meet or get better acquainted with a lot of great rubyists and hear a lot of entertaining, informative talks.&lt;/p&gt;
&lt;h3&gt;Jim and Joe&amp;#8217;s Mock Dialog&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://farm4.static.flickr.com/3046/2747232825_923bf6eb27_m.jpg" class="box" alt=""&gt;&lt;br&gt;
&lt;a href="http://onestepback.org/"&gt;Jim Weirich&lt;/a&gt; and &lt;a href="http://objo.com/"&gt;Joe O&amp;#8217;Brien&lt;/a&gt; presented their talk about mocks and stubs in the form of a short play in three acts. This was very timely for me since mocking properly in tests is area we have been discussing quite a bit at Hashrocket.&lt;/p&gt;
&lt;p&gt;One thing they said that struck a chord was that complex mocks are a code smell that can clue you in to problems or hot spots for refactoring in the code under test.&lt;/p&gt;
&lt;p&gt;The presentation style was fresh and the tips they provided should be very valuable to anyone using mocks in testing (which should be everyone).&lt;/p&gt;
&lt;h3&gt;Ruby Best Practice Patterns&lt;/h3&gt;
&lt;p&gt;&lt;img src="/images/hoedown/rein-hoedown-talk.png" class="box right" alt=""&gt;&lt;br&gt;
I&amp;#8217;m afraid I played a little trick on poor Jeremy and my dear audience. Instead of spending an hour giving examples of patterns and practices, I thought it might be fun to take a more satirical slant on the material. The resulting talk, &lt;cite&gt;Unfactoring From Patterns: Job Security Through Code Obscurity&lt;/cite&gt;, turned out to be a modest success (if I do say so myself) and I think rather more entertaining to boot.&lt;/p&gt;
&lt;p&gt;I did have time to show a few actual patterns but the dialog during the question and answer period was especially valuable. David Black, Yehuda Katz and others made some great points and I really enjoyed getting a chance to discuss one of my favorite topics with such a receptive and informed audience.&lt;/p&gt;
&lt;h3&gt;We Ain&amp;#8217;t Got No Keynote&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://farm4.static.flickr.com/3020/2750897640_74a18f4807_m.jpg" class="box" alt=""&gt;&lt;br&gt;
Chris decided to forgo the slides to tell us a more personal story about his growth from a lowly PHP hacker to the successful rubyist, entreprenuer and open-source champion that he is today. Chris is an exemplar for me of the right way to go about creating a personal and company brand.&lt;/p&gt;
&lt;p&gt;Chris&amp;#8217;s years of passion for tinkering, experimenting and exploring really have payed off in a big way. I think his story could rightly be considered inspirational. I&amp;#8217;m sure a lot of people left his talk and started side projects this very weekend. I really enjoyed his talk (even if he did tell people not to buy my book).&lt;/p&gt;
&lt;h3&gt;Flog Your Tests, Test Your Flog&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://farm4.static.flickr.com/3268/2750731456_95a4c0e43d_m.jpg" class="box right" alt=""&gt;&lt;br&gt;
Testing is such a crucial part of my process that I was very excited to hear Rick Bradley&amp;#8217;s account of his rather epic battle to add tests to flog. The irony here, of course, is that flog itself is a testing tool.&lt;/p&gt;
&lt;p&gt;This talk combined two of my favorite topics: testing and refactoring. Rick&amp;#8217;s war stories had some great takeaways: the importance of integration tests to characterize the behavior of the existing system, the ways in which code that is written test first differs from code that is written without tests, the utter importance of testing all the f&amp;#8212;king time. Bryal Liles will have more to say on that last topic in a bit.&lt;/p&gt;
&lt;p&gt;I really can&amp;#8217;t say enough about Rick&amp;#8217;s talk. Hashrocket often takes on applications with little or no testing for our Rescue Missions and Rick&amp;#8217;s deliberate, careful, comprehensive methodology is exactly the process we try to follow when we refactor and resuscitate our clients&amp;#8217; code back to health. Rick could very well write the Hashrocket Rescue Mission manual.&lt;/p&gt;
&lt;h3&gt;MIDI Machinations and Hungry Hungry Hippos&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://farm3.static.flickr.com/2379/2330883047_19ee04ab8d_m.jpg" class="box left" alt=""&gt;&lt;br&gt;
Giles Bowkett is a mad genius. Perhaps more importantly, he&amp;#8217;s an artist who can ship. He lured us all to a talk about archaeopteryx, his amazing MIDI  generator, and then proceeded to smack us all with the enlightenment stick.&lt;/p&gt;
&lt;p&gt;I won&amp;#8217;t spoil his talk for people who haven&amp;#8217;t seen it. Suffice it to say that it was far more than I expected. Giles&amp;#8217;s opinions on software development are unique and somewhat iconoclastic. Be careful, the code he writes might blow some people&amp;#8217;s minds.&lt;/p&gt;
&lt;p&gt;Giles&amp;#8217;s &lt;a href="http://gilesbowkett.blogspot.com/2008/04/my-approach-to-giving-presentations.html"&gt;presentation style&lt;/a&gt; is engaging and he can be down right hilarious at times. Also, hippos are scary!&lt;/p&gt;
&lt;h3&gt;Wrap It Up!&lt;/h3&gt;
&lt;p&gt;Taking a road trip down to the Hoedown with the Hashrocket crew was one of the best conference experiences I&amp;#8217;ve had so far. The talks were great, but I think the after-conference festivities were the real hilight. Watching Obie and Jason play beer pong on a table constructed of pool noodles (watch the video), playing werewolf with a crew of drunken rubyists and spending time with some of my favorite conference friends. Who could ask for more? Also, Jeremy has big plans for next year&amp;#8217;s Hoedown. It involves words like &amp;#8220;free&amp;#8221; and &amp;#8220;Nashville&amp;#8221; &amp;#8211; I would be inclined to add &amp;#8220;awesome&amp;#8221; as well.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/reinh/~4/vYQ4ZyLXmaY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://reinh.com/blog/2008/08/10/rocking-the-hoedown.html</feedburner:origLink></entry>
  
</feed>
