<?xml version='1.0' encoding='utf-8' ?>
<feed xmlns='http://www.w3.org/2005/Atom'>
  <title>
    Alex Vollmer
  </title>
  <link href='http://alexvollmer.com/atom.xml' rel='self' />
  <link href='http://alexvollmer.com/' />
  <updated>
    2010-06-13T15:10:14PDT
  </updated>
  <id>
    http://alexvollmer.com/
  </id>
  <author>
    <name>
      Alex Vollmer
    </name>
    <email>
      alex.vollmer@gmail.com
    </email>
  </author>
  <entry>
    <title>
      <![CDATA[
          A Tale of Two Cultures
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/' />
    <updated>
      2010-06-13T15:10:14PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/
    </id>
    <content type='html'>
      <![CDATA[
          <p><a href="http://www.flickr.com/photos/adamjackson/4670520309/" target="_new">
          <img class="right" src="http://farm5.static.flickr.com/4011/4670520309_fbac12cd42_m.jpg"/>
          </a></p>
          
          <p>I just returned from the 2010 edition of Apple's WWDC. The week before I took
          a week off from my iPhone and lived with an Android Nexus One. Both my personal
          experience with Android and the following week's announcements left a
          strong impression that, in the so-called "smartphone" space, we are really
          seeing the success of two very different mind-sets, cultures and philosophies.
          I'm not interested in a winner-takes-all kind of war. Instead I wanted to look
          at the differences between these two companies in the context of them
          co-existing and each having a happy, satisfied base of customers.</p>
          
          <p>I <em>was</em> going to write about how capable the Nexus One seems to me, but how
          amateurish the UI appears. At times, the look and feel of the Android UI
          looks like its designers simply couldn't figure out how to fill the space
          with something interesting.</p>
          
          <p>I <em>was</em> going to write about how the ubiquity of the four hardware buttons are
          both a blessing and curse. I understand that the designers were trying to
          provide a set of near-universal options in a consistent place. Unfortunately
          it was too easy to accidentally hit the "home" key while typing on the soft
          keyboard.</p>
          
          <p><a href="http://www.flickr.com/photos/oyf/4255429887/" target="_new">
            <img src="http://farm3.static.flickr.com/2770/4255429887_e16b119a2d_m.jpg" class="left"/>
          </a></p>
          
          <p>I <em>was</em> going to write about the moment I realized just how different the
          design philosophies between Android and iOS (nee iPhoneOS) are when I wanted
          Instapaper integration with a good Twitter client. I needed to find an
          Instapaper app, not a Twitter app with Instapaper integration. I simply didn't
          grok the universal plugin architecture of Android at first. In hindsight it
          makes perfect sense&mdash;if you're a software developer or tech-geek. It
          seems insane to require the user to have a mental model that's so intimate
          with Android's implementation details.</p>
          
          <p>I <em>was</em> going to write about how delighted I was with Android's GMail
          integration and how much I wish something similar existed on the iPhone. I
          love GMail. I couldn't care less about other mail configurations (POP or
          IMAP). Maybe the built-in regular mail app is as clunky as Apple's, but I
          didn't use it. Kudos to Google for such a seamless integration with not only
          Gmail, but the calendar and contacts too.</p>
          
          <p>I <em>was</em> going to write about all these little bits of evidence that showed
          just how different the philosophies are between these two companies and
          these two platforms. I was going to write about how it's a bit odd to put
          them in competition with each other because, in a sense, they are really
          trying to build two different things: Google wants to build the most bad-ass
          feature-rich, piece of mobile technology there ever was. Apple wants to build
          a mobile experience.</p>
          
          <p>I <em>was</em> going to write about all of these things, but after attending the
          keynote at WWDC last week, I realized that there was only one thing that I
          needed to point to that most effectively highlights the differences
          between the two:</p>
          
          <p><a href="http://www.apple.com/iphone/features/facetime.html" target="_new">
            <img src="/images/2010/06/facetime.png">
          </a></p>
          
          <p>At the end of this video, you had a room full of five-thousand geeks drying
          their eyes. You can call the video cheesy or manipulative. You can call it a
          piece of marketing fluff. But that video was <em>not</em> about protocols,
          compatibility, specifications or any of the myriad technical details we debate
          on a daily basis. That video was about telling human stories that we can all
          relate to.</p>
          
          <p>I haven't yet been to a Google I/O event. I'd really like to attend one. But
          right, wrong or indifferent, you would never see something like this from
          Google. I can't think of anything that does a better job of summing up the
          completely different views that Google and Apple have of the world.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Cocoa's Broken Tests
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/' />
    <updated>
      2010-06-01T11:20:51PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I'm a long-time TDD kinda guy. I've had the great fortune of learning TDD
          first-hand from <a href="http://en.wikipedia.org/wiki/Kent_Beck" title="Kent Beck - Wikipedia,the free encyclopedia">one of its greatest practitioners</a>
          and consider it one of the core disciplines of the way I go about my
          profession. So when I first started doing Cocoa programming in earnest I was
          shocked at the state of automated testing. Compared to my experiences on other
          platforms, the tools are archaic and backwards. Moreover, the philosophy of
          testing just doesn't seem to be baked into the DNA of the Cocoa community.
          Nobody seems to be talking about it much. So I've just suffered with
          old-fashioned head-against-wall development without the comforting support of
          TDD. But I don't know how much longer I can take it. Am I crazy for wanting
          TDD in Cocoa, or are the two simply incompatible?</p>
          
          <p>Given the current state of affairs, it's not hard to see why there's a
          <a href="http://www.wilshipley.com/blog/2005/09/unit-testing-is-teh-suck-urr.html" title="Call Me Fishmeal.: Unit testing is teh suck, Urr.">bias against unit-testing</a>
          in the Cocoa community. <sup><a href="#note1">1</a></sup> Unit-testing tools,
          support and idioms within Cocoa are nowhere close to where they are in, say,
          the Java, .Net, Ruby or Python communities. Compared to those environments,
          unit-testing in Cocoa is just flat out <em>difficult</em>. I can easily understand
          why a developer would conclude that the cost and effort of TDD outweighs the
          benefits.</p>
          
          <h1>The Dismal Science</h1>
          
          <p><a href="http://www.flickr.com/photos/janbrasna/399875844/" title="Currencies on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/178/399875844_16660fd4bf_m.jpg" class="left" alt="It's all about the money"></a></p>
          
          <p>Think of every "best practice" you've ever been exposed to in software. They
          all come down to cost-benefit tradeoffs in the end. Up-front requirements
          gathering? It's an attempt to manage change and indemnify certain parties when
          things go awry. Iterative development? It's merely a short-term review process
          to evaluate the cost of future development against opportunities in the
          future. Automated testing? Computers (generally) work more cheaply than
          humans, so invest in automating repeated tasks so that, over the long-haul,
          more work is accomplished by cheaper workers. Hell, even the oft-cited goals
          of code-reuse in object-oriented programming are economic ones. The list goes
          on and on and on.</p>
          
          <p>But, even as a long-time practitioner of test-driven development, I don't view
          it as axiomatic. In this big, bad world of ours there have to be cases where
          the economics simply don't add up, and it simply isn't <em>cost effective</em> to
          build stuff using TDD.<sup><a href="#note2">2</a></sup> Returning to
          Cocoa, I can see how developers come to the conclusion that TDD in Cocoa
          simply isn't worth the price of admission.</p>
          
          <p>So what makes TDD in Cocoa so expensive? Would things look different if we
          could change the balance sheet?</p>
          
          <h1>Bear-Skins &amp; Stone Knives</h1>
          
          <p><a href="http://www.flickr.com/photos/g_originals/368093250/" title="working hand on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/169/368093250_8fa93d209a_m.jpg" class="right"/></a></p>
          
          <p>Back in the day, <a href="http://www.sente.ch/software/ocunit/" title="Sen:te - OCUnit">OCUnit</a>
          was <em>the</em> xUnit toolkit of choice for Cocoa programming. In 2006
          Apple put OCUnit right into Xcode and TDD received its first official
          blessing. Now I don't have a beef in particular with OCUnit&mdash;it's
          essentially a faithful implementation of xUnit patterns for Objective-C. What
          is surprising is how weakly it's integrated with Xcode.</p>
          
          <p>To unit-test, you have to create an entirely new target to execute your
          unit-tests within. However, you don't run it like a normal executable. It's
          baked into the build process for that target so that testing errors show up
          just like build errors. I'll admit that's kind of cute and at least makes an
          attempt to integrate TDD into the development process. But keeping unit-tests
          as a separate target means more drop-down flipping in Xcode to go between
          unit-testing and running my application. Oh and the bloody drop-downs in
          Xcode&hellip;don't even get me started&hellip;</p>
          
          <p>The other issue is debugging. If your unit-tests are failing, god help you if
          you want to find out why. It takes <a href="http://chanson.livejournal.com/120740.html" title="Chris Hanson - Xcode: Debugging Cocoa application unit tests">a lot of environment-variable hijinks</a>
          to be able to actually debug your unit-tests &mdash;something that is
          significantly easier on every other platform I've ever worked on. All of this
          leaves me with the distinctly uneasy feeling that Apple and the Cocoa community
          at-large are merely paying lip-service to TDD.</p>
          
          <p>Compare this to how JUnit is integrated into your standard Java IDE or
          awesome Ruby testing tools like
          <a href="http://www.zenspider.com/ZSS/Products/ZenTest/" title="ZenTest: Automated test scaffolding for Ruby">autotest</a>.
          These tools are so much more immediate and easier to reach for. Xcode looks
          like it came from the era of the horse and buggy. These kind of tools and this
          kind of support needs to be a part of the development environment in a
          more natural way. Right now it's just a primitive, bolted-on afterthought.
          It's a wonder anyone has the patience to use it.</p>
          
          <h1>A New Mentality</h1>
          
          <p>Another challenge in Cocoa is figuring out where TDD fits in such a
          framework-driven environment. To Apple's credit, the frameworks that Cocoa
          provides do a pretty good job of "making the simple easy and the difficult
          possible". However because Cocoa is <em>so</em> prescriptive, it can be difficult for
          developers to stand back and figure out what to test. It's just so easy to
          just let the idioms fly off the fingers, that testing them seems like a silly
          exercise.</p>
          
          <p>I think a common conclusion for the the would-be TDD'er is that they often
          find their tests essentially repeating the implementation. These are most
          expensive tests to write and maintain. Not only do you end up duplicating the
          code (thus adding coupling and brittleness), but they also take up a lot of
          time to write and can be pretty error-prone.</p>
          
          <p>There has been a lot of thought about similar problems in other communities,
          so why not steal these ideas and apply them to Cocoa development? Surely
          strategies like <a href="http://martinfowler.com/bliki/InversionOfControl.html" title="MF Bliki: InversionOfControl">inversion of control</a>
          and <a href="http://www.mulle-kybernetik.com/software/OCMock/" title="Mulle kybernetiK -- OCMock">mocks</a>
          would help make TDD in Cocoa an economic possibility. <sup><a href="#note3">3</a></sup></p>
          
          <p>The Cocoa community simply hasn't evolved a good set of testing practices the
          way others have. Given the benefits I've seen in other environments, it's hard
          for me to believe that Cocoa and Objective-C are exceptional in this regard. I
          think that there are ways to do it, we just haven't discovered them yet. I
          recall from my Java and Ruby days that testing idioms and practices evolved <em>a
          lot</em> before we got somewhere reasonable. Simply put, the Cocoa world's
          collective testing skills and knowledge lag severely behind a lot of other
          languages.</p>
          
          <p><img class="right" src="/images/2010/06/kim-jong-il.jpg" alt="Kim Jong Il"></p>
          
          <p>Facing this requires the Cocoa community to face its own isolationist and
          exceptionalist attitudes. There's nothing so special about Cocoa and
          Objective-C that <em>conceptually</em> invalidates the effectiveness of TDD. <sup><a
          href="#note4">4</a></sup> Cocoa folks need to look outside of their walled
          garden to see what others have done. This is not something I've seen much,
          if any of, in the Cocoa community. Frankly, the dominant attitude seems to be
          one of snobbery and elitism. It's an unfortunate attitude that holds us all back.</p>
          
          <h1 id="footnotes">Footnotes</h1>
          
          
          <ol>
          <li>
          <a name="note1"></a>
          Normally it wouldn't be fair to link to a five-year old post and call
          it "representative" of a community's attitude, but I think for an insular
          group like Cocoa-nerds, this is totally reasonable.
          </p>
          </li>
          
          <li>
          <a name="note2"></a>
          I'm not saying that I, personally, have encountered such a thing, but
          I don't think it's unreasonable to assume that the possibility <em>exists</em>.
          </li>
          
          <li>
          <a name="note3"></a>
          There is, of course, a pathological extreme to this line of thinking. That
          extreme is called <a href="http://www.springsource.org/" title="SpringSource.org |">Spring</a>.
          </li>
          
          <li>  
          <a name="note4"></a>
          OK, I'll admit that iPhone development is a little different because of
          having to deal with the device vs. the simulator. Getting tests running on the
          device is a non-trivial exercise. But I'm not convinced that unit-tests have
          to run on the device. Yes, there are differences between the real and
          simulated environments, but those differences should be accounted for in
          <em>integration tests</em>&mdash;a topic I'm not going to address here.
          </li>
          </ol>
          
          
          <p></div></p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The International Colors of iPhoneOS
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/' />
    <updated>
      2010-05-21T08:46:32PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Like flossing or saving for retirement, localizing
          and internationalizing your applications is one of those things "you should
          do". Cocoa, and by extension Cocoa Touch, has pretty decent localization
          (l10n) and internationalization (i18n) support. If you use the
          <code>NSLocalizedString</code> macro along with locale-specific strings files, you will
          handle 99.9% of your localization needs.</p>
          
          <p><img src="http://revoir1printemps.canalblog.com/albums/benetton/m-benetton654.jpg" height="100" class="left"></p>
          
          <p>But what if you're integrating with a web service? What's the best way to
          convey the user's current settings to an external party? I've run into this
          exact situation a couple of times and wanted to share the approach I like to
          take.</p>
          
          <h1>The Server-Side</h1>
          
          <p>The first thing you need to determine is how you'll express the user's
          current locale settings. If you own the servers-side, you can implement this in
          whatever way you see fit. Personally, I like to take advantage of as much
          of the HTTP specification as I can. Rather than overloading every request
          with a request parameter, I like to use the <code>Accept-Language</code> header.
          <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4" title="HTTP/1.1: Header Field Definitions">The specification</a>
          says that the format of the <code>Accept-Language</code> header allows multiple locales with
          <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.10" title="HTTP/1.1: Protocol Parameters">"quality values"</a>
          optionally given to each one to express order of preference.
          For example, a valid <code>Accept-Language</code> header might look like this:</p>
          
          <div class="highlight"><pre>Accept-Language: da, en-gb;q<span class="o">=</span>0.8, en;q<span class="o">=</span>0.7&#x000A;    </pre>
          </div>
          
          
          <p>In this example, Danish (with no specific region) is preferred first, followed
          by English (in the Great Britain region), followed by English in any region. The
          language and region are delicately intertwined in a bunch of different ways.
          Depending on the combination, the region may affect how words are spelled
          (for example "armor" in American English vs. "armour" in British English). Not
          all locales and regions work this way so there are plenty of corner-cases.</p>
          
          <p>Ruby on Rails is my server-side stack of choice these days. Like Cocoa, Rails
          is pretty good at making it easy to localize and internationalize your
          application. However, despite Rails claim to being "opinionated", it's
          surprisingly indecisive about the best way to express language and region
          preferences. The <a href="http://guides.rubyonrails.org/i18n.html" title="Rails Internationalization (I18n) API">Rails i18n Guide</a> suggests that you can get the locale
          as a query parameter (blech), via the domain name (if you've set your
          application and client up this way), via URL parameters (i.e. as a path
          segment within a larger URI structure), via built-in user settings, via GeoIP
          or using the <code>Accept-Language</code> header. As I stated before, I like the latter
          solution the most. However parsing the header, dealing with the quality scores
          and then figuring out the best one is something that has already been solved.
          For that, I like the <a href="http://rubygems.org/gems/http_accept_language" title="http_accept_language |
          RubyGems.org | your community gem host"><code>http_accept_language</code>
          gem</a>.</p>
          
          <p>In the <code>ApplicationController</code>, I setup a <code>before_filter</code> that uses the gem to
          parse the <code>Accept-Language</code> header. Since I may not have localized the web
          server to match a given request, I use the <code>compatible_language_from</code> method
          to figure out what, if any, language match there is.</p>
          
          <div class="highlight"><pre><span class="n">before_filter</span> <span class="ss">:check_language</span>&#x000A;    &#x000A;    <span class="k">def</span> <span class="nf">check_language</span>&#x000A;      <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span> <span class="o">=</span> <span class="k">if</span> <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">].</span><span class="n">nil?</span>&#x000A;        <span class="n">request</span><span class="o">.</span><span class="n">compatible_language_from</span><span class="p">(</span><span class="no">MyApp</span><span class="o">::</span><span class="no">AVAILABLE_LANGUAGES</span><span class="p">)</span>&#x000A;      <span class="k">else</span>&#x000A;        <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span>&#x000A;      <span class="k">end</span>&#x000A;      <span class="no">I18n</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p><code>MyApp::AVAILABLE_LANGUAGES</code> is constant array defined in a Rails
          initializer (in <code>config/intializers</code>) that figures out all of the possible
          locales I have configured:</p>
          
          <div class="highlight"><pre><span class="k">module</span> <span class="nn">MyApp</span>&#x000A;      <span class="no">AVAILABLE_LANGUAGES</span> <span class="o">=</span> <span class="no">Dir</span><span class="o">[</span><span class="no">RAILS_ROOT</span> <span class="o">+</span> <span class="s2">&quot;/config/locales/*&quot;</span><span class="o">].</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span>&#x000A;        <span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">first</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>Despite my aversion to using request parameters, it can be handy for ad-hoc
          testing to be able to tack a query parameter on to change the locale. Also,
          once you've determined the locale, you need to notify the <code>I18n</code> framework
          as I've done in the last line of the <code>check_language</code> method.</p>
          
          <h1>The Client-Side</h1>
          
          <p>OK, great. Now we've figure out how to vary the locale on the web-side. How
          do we extract this information from the device and ship it off in our
          HTTP headers?</p>
          
          <p>Here you have two tasks: the first is to determine what the value of the
          <code>Accept-Language</code> header should be and second, to actually make sure you send
          those values. Since there are several ways of making HTTP requests in iPhoneOS
          I'm not going to go into the details. Whether you're using <code>NSURLRequest</code>,
          <a href="http://allseeing-i.com/ASIHTTPRequest/" title="ASIHTTPRequest Documentation - All-Seeing Interactive">ASIHTTPRequest</a>,
          <a href="http://alternateidea.com/blog/articles/2009/7/11/introducing-httpriot-easily-consume-rest-resources-on-the-iphone-and-os-x" title="AlternateIdea:  Introducing HTTPRiot - Easily Consume REST Resources on the iPhone and OS X">HTTPRiot</a>
          or your own homegrown thing, presumably you have
          some reasonable way of setting the <code>Accept-Language</code> header in a consistent
          way.</p>
          
          <p>To figure out what locale your user is in, you need to consult the
          <code>NSLocale</code> class. This provides several class methods that yield a
          <code>NSLocale</code> instance that reflects the user's current settings. If you look
          at the docs, there are three class-methods that return a <code>NSLocale</code> instance:
          <code>+systemLocale</code>, <code>+currentLocale</code> and <code>+autoupdatingCurrentLocale</code>. The
          differences between the three are not apparently obvious and, I think, reflect
          <code>NSLocale</code>'s original desktop heritage.</p>
          
          <p>The <code>+systemLocale</code> method will return a default <code>NSLocale</code> instance when one
          cannot otherwise be determined. In my experience, I've never seen this return
          anything but a blank and useless <code>NSLocale</code> instance. Don't bother using it.</p>
          
          <p>The <code>+currentLocale</code> method returns a <code>NSLocale</code> instance that reflects the
          user's current setting. However there is a bit of language in the docs that
          I initially found confusing:</p>
          
          <blockquote><p>Settings you get from this locale do not change as System Preferences are
          changed so that your operations are consistent. Typically you perform some
          operations on the returned object and then allow it to be disposed of.
          Moreover, since the returned object may be cached, you do not need to hold on
          to it indefinitely.</p></blockquote>
          
          <p><em>Huh?</em> To understand what's going on here, we need to take a look at the docs
          for the <code>+autoupdatingCurrentLocale</code> method:</p>
          
          <blockquote><p>Settings you get from this locale do change as the user’s settings change
          (contrast with currentLocale).</p></blockquote>
          
          <p>Remember, a lot of CocoaTouch came from the desktop Cocoa environment. On the
          desktop you can open the System Preferences and change your region and
          language settings anytime <em>while applications are running.</em> However, until
          iPhone OS 4.0 is released, this is <em>not</em> something you can do on any iPhoneOS
          device. So the net effect, and this matches my own observations, is that on
          iPhone OS 3.x <code>+currentLocale</code> and <code>+autoupdatingCurrentLocale</code> are
          essentially the same. But, if you want to be prepared for the future, go ahead
          and use the <code>+autoupdatingCurrentLocale</code> method. Once you have a <code>NSLocale</code>
          instance, you call the <code>-localeIdentifier</code> method on it to get a <code>NSString</code>
          like <strong>en_US</strong> or <strong>fr_FR</strong>.</p>
          
          <p>So if you're like me, you want to test that this actually works. So, naturally,
          you would figure out how to modify the settings on your phone to yield
          different responses. What you'll soon discover is that the current locale
          settings are derived from two separate and independent settings and that
          various combinations of the two can produce unexpected results.</p>
          
          <p>Start by launching the "Settings" application. Select <em>General ⇢
          International</em>. You'll get a screen where you can pick your language, your
          keyboards and your region format. What may surprise you is that <em>changing the
          language does not affect the current locale.</em> I'm in the United States so my
          region format is set to "United States". If I change my language to French,
          but leave the region format setting alone, all localization within the system
          and applications will use the French language, but my locale remains
          <strong>en_US</strong>.</p>
          
          <p><img src="/images/2010/05/international-iphone.jpg" alt="International Settings on iPhone" /></p>
          
          <p>OK, so <code>NSLocale</code> doesn't quite work as expected, but where does the system
          store the current language? It turns out the <code>NSLocale</code> provides yet another
          class method, named <code>+preferredLanguages</code>, that returns an array of language
          codes as strings. With the settings described above, the first entry in that
          array is "fr".</p>
          
          <p>If you change your settings where you leave the language set to English, but
          change the region format to French (in the "France" region), the current locale
          will now be set to <strong>fr_FR</strong> and the first entry in the <code>preferredLanguages</code>
          array will be "en" for English.</p>
          
          <h1>What It All Means</h1>
          
          <p>Out of the box, Rails doesn't provide full-blown region-specific localization.
          You can either hack something or use one of many <a href="http://rails-i18n.org/wiki" title="Rails I18n">i18n plugins</a>
          or <a href="http://github.com/joshmh/globalize2" title="joshmh's globalize2 at master - GitHub">Globalize2</a>.
          So if you try to send a language-region combination to Rails (such as <strong>en_US</strong>),
          chances are good that you won't have the right localization setup and you'll
          fall-back to your default locale.</p>
          
          <p>You have two choices: you can make the client send something that the server
          understands, or teach the server to respect more fine-grained localization
          values. If you want to go the first route, I would suggest simply querying the
          <code>+preferredLanguages</code> array and using the first entry as the value for your
          <code>Accept-Language</code> header. However if your server-side localization can handle
          it, use the <code>+currentLocale</code> instead so that you can handle regional
          differences and spelling much better.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Visual Affordance in a Touch-Enabled World
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/' />
    <updated>
      2010-05-07T10:46:39PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/
    </id>
    <content type='html'>
      <![CDATA[
          <p><em>Ooooh</em>, you must be thinking, <em>what a posh title this is!</em> Okay, I'll admit
          to copping a bit of a grandiose attitude when I came up with this, but hear
          me out on this one.</p>
          
          <p><img src="/images/2010/05/mad-as-hell.jpg" class="left" alt="I was mad as hell
          about a mouse and keyboard until I got an iPad!"/> The iPad has generated a
          lot of criticism, scrutiny and analysis in recent months. The debate about the
          ills and assets of the platform have, and will continue to be, debated
          endlessly. I think one thing is pretty clear though&mdash; whether you like
          Apple or not, whether you have an iPad or not, whether you think it's the most
          awesome-est thing ever or not, it <em>is</em> revolutionary device. I don't mean in
          terms of technical execution (yes the A6 chip is a marvel, the
          power-consumption is amazing, blah blah blah). What I mean is that somebody
          with Apple's clout finally stood up and threw away the last three decades of
          user-interface paradigm <em>and they're laughing all the way to the bank doing
          it</em>.</p>
          
          <p>So, if you jettison The Way We've Always Done Things &trade;, what do you replace
          it with? More importantly, which things from The Old Way are no longer
          applicable to The New Way? This is a big topic that will take some time to
          settle itself. We've had this CPU/mouse/keyboard setup for nearly thirty years
          and we're <em>still</em> learning how to make it work for humans. I don't expect us
          to settle the micro-debates of touch-interface design for quite a while, but
          I do want drill down to something pretty specific.</p>
          
          <p>Take a moment and ponder what the mouse <em>really is</em> in a graphic user
          interface. It's a proxy. It's a loosely-connected device where movement and
          gestures in one space are translated to movement and gestures in another
          virtual space. To operate a mouse well, you have to perform constant mental
          transform operations from the physical world to the world you are trying to
          manipulate on the screen. The mouse is, effectively, a rather thick layer
          between you and what you're trying to do.</p>
          
          <h1>Exploiting the Gap</h1>
          
          <p>As we got better and better with the mouse <sup><a href="#note1">1</a></sup>
          software started to exploit this gap between you and your machine. The first
          place this showed up was in context menus. Once we already had to make a
          mental stop on the train ride from our brain to the machine, why not make the
          station more useful to folks? <em>Hell, let's put in some vending machines,
          and perhaps some couches. We could even install</em> Wi-Fi <em>and people could
          get</em> even more <em>productive.</em> Pile it on, pile it on.</p>
          
          <p>Taken to an extreme, the mouse becomes the primary means by which we
          interact with our machines. If you don't believe me, take a look at any
          professional CAD workstation or that god-awful OpenOffice mouse.</p>
          
          <p><img src="/images/2010/05/context_menu.png" class="right" alt="The ubiquitous,
          right-click-able, context menu"/> However these are extremes. There isn't
          necessarily anything wrong with things like extra mice buttons or context
          menus. But, in a world of touch, where the mental and physical distance
          between our intentions and execution is much smaller, that thick
          layer/opportunity is gone. <em>Context menus?</em> How the hell do I "right-touch"
          the screen? <em>Mouse-overs?</em> Current touch interfaces don't have any proximity
          sensors <sup><a href="#note2">2</a></sup>&mdash;either you touch something or
          you don't. Yet these two very simple interaction models have become a crucial
          part of the UI vocabulary we have all acquired over the years.</p>
          
          <p>Think about a mouse-over. What is it there for? Mouse-overs offer two things:
          a preview mechanism allowing you to learn more about something without having
          to commit to it, and as a backup when a pictorial icon's meaning isn't clear
          enough. We don't have these on the iPad <sup><a href="#note3">3</a></sup>. So
          as an application designer and builder, how do we give people some notion of
          what this thing can do? What kind of <em>affordance</em> can we offer?</p>
          
          <h1>Spelunking</h1>
          
          <p>As you start using and learning an application, you generally have two
          questions:</p>
          
          <ul>
          <li>What can this thing do?</li>
          <li>How can I get this to do ______?</li>
          </ul>
          
          
          <p>These are asked from two opposing angles, but both are about discovering the
          capabilities of the software. When a user doesn't know what your application
          can do, how can you build it in a way that they can discover it? An equally
          important question is how can they explore your application without having to
          commit to any action, particularly a destructive one?</p>
          
          <p><img src="/images/2010/05/nnw-ipad.png" class="left" alt="The 'next unread'
          button in NNW"/> Let's look at one of my favorite iPad apps in particular,
          <a href="http://netnewswireapp.com/ipad/" title="NetNewsWire for iPad &laquo; NetNewsWire">Net News Wire</a>.
          A nice feature of the application is the ability to progress through all of your unread items
          with a single tap. When I first got the app, I <em>knew</em> that there had to be a
          way to do this, but I couldn't find it. There <em>was</em> a mysterious-looking button
          in the corner of the screen, but I wasn't sure what it was for. I mean, it
          might do <em>anything</em>. How was I to know what would happen? It wasn't until I saw a
          <a href="http://seattlexcoders.org/2010/04/20/april-22-meeting---brent-simmons-and-brad-ellis.html" title="Seattle Xcoders - April 22 Meeting - Brent Simmons and Brad Ellis">presentation by Brent Simmons and Brad Ellis on the design of NNW</a> that I
          actually found out where that button was. You can't really figure out what it
          does unless you poke it. If you poke that button, there isn't a corresponding
          "undo" button for that action.</p>
          
          <p>That's not a dig against Brent and Brad, I think they did a wonderful job
          with NNW. But it does highlight how difficult it can be to convey such a
          feature to the user. I think it may be one of the biggest challenges on the
          platform. How do we let the user know what our application can do?</p>
          
          <p>Let's be honest here, if you're relying on documentation to teach the user
          the basics, you've already lost the battle. Documentation is fine for really
          deep, detailed information (see OmniGraffle on the iPad for an example). But
          requiring a user to read the Owner's Manual before they can even use your
          software went out about the same time as floppy disks. On the iPad an
          up-front documentation requirement is just laughable.</p>
          
          <h1>Little Gets Big</h1>
          
          <p>One final thought is that although the iPhone and iPad obviously share the
          same DNA, the difference in size makes this acutely problematic on the iPad.
          On the iPhone you simply can't cram that much stuff into an application. Read
          the iPhone Human Interface Guidelines and you'll quickly get the message that
          on the iPhone, <em>less is more</em>. By and large, the best iPhone apps simply don't
          have that many features integrated into them. This gives application designers
          more freedom to make clear the intent of the features that are implemented.</p>
          
          <p>On the iPad, it's a different story. There's so much more real-estate. Running
          an iPhone application on the iPad is so laughably awkward that it starkly
          highlights just how different the platforms really are. So now, as iPad
          application builders, we have more space than ever. While we're freed from the
          space constraints of the iPhone, we now have a challenge (and responsibility)
          to use it effectively. It's not hard to imagine some developers embracing
          these new green fields to produce some truly awful interfaces. Please, don't
          be one of them.</p>
          
          <h2>Tangents</h2>
          
          <p> <a name="note1"></a>1. Make no mistake here, we've had to <em>train</em>
          ourselves to use the mouse. Just watch your grandparents struggle with a 
          mouse and you'll realize how un-intuitive the device really is.</p> 
          
          
          
          
          <p><a name="note2"></a>2. I'm not even sure if they did that it would be such a good
          idea. Requiring that level of fine-finger dexterity immediately makes such a
          device exclusive to the young and facile.</p>
          
          
          
          
          <p><a name="note3"></a>3. OK, there <em>is</em> a common trick
          of touching and holding a hyperlink long enough to get a menu of
          options.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          On Technical Presentations
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/' />
    <updated>
      2010-04-30T07:51:51PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I spent last weekend at the Seattle version of the <a href="http://www.voicesthatmatter.com/iphone2010/" title="iPhone
          Developers Conference - Using the iPhone OS to build apps for the iPad and
          iPhone">Voices That Matter iPhone
          Developer's conference</a>. The content was great, but aside from John "Wolf" Rentzch's Core
          Data talk, the quality of the slides and presentation was pretty lacking. I'm
          not here to dogpile on those speakers. I still got a lot out of their talks,
          but the experience crystallized some important rules for me about technical
          presentations.</p>
          
          <h2>Size and Geometry</h2>
          
          <p><a href="http://www.flickr.com/photos/laffy4k/405446783/" title="Huntington
          University: Zurcher Auditorium on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/122/405446783_a88c63ce0c_m.jpg"
          class="left"/></a></p>
          
          <p>There is a axiom in military science that says no plan survives contact with
          the enemy. In a similar vein, no slide layout survives contact with an actual
          display screen. As we craft presentations it's easy to get so locked into
          looking at our screens that we often forget about the context of the room in
          which it will be given. There are two important things to consider about the
          room: how far back the audience stretches from the screen and the angle of the
          audience. In a room with a "deep" audience and shallow angle, anywhere from
          the bottom 20% - 30% of the screen will only be visible to the front row. Some
          professional presenters make it a matter of habit to simply avoid the bottom
          quarter of the screen. Think of this as a creative constraint to embrace and
          help you focus your message.</p>
          
          <p>The dimensions of the audience also affect the size of the content in your
          slides —specifically the font size you choose. Somehow font sizes that look
          like billboards on your laptop are diminished to footnotes once they are
          projected. In practice, it's pretty hard to make text too big. If you have a
          problem fitting what you want to say on the slide, perhaps you need to
          reconsider the phrasing.</p>
          
          <p>Aside from direct quotations, I find that it's rarely useful to have full
          paragraphs of text in your slides. You want your audience to be focused on
          <em>you</em>, not your slides. Think of the slides as simply the supporting cast to
          what you're telling the audience verbally. How can you craft your slides to
          complement what you're trying to convey?</p>
          
          <h2>Live Demos</h2>
          
          <p>Slides can only take us so far, especially for technical presentations.
          Sometimes we need to turn away from the "what", and explain the "how" of
          something. We want to demonstrate how something works. For coders, this often
          means a live coding or tool demonstration. If you're trying to convince your
          audience that technology XYZ is the greatest thing since sliced bread and will
          save them all sorts of time and headaches, you want to be able to <em>show</em> it,
          not just tell it.</p>
          
          <p>Fantastic. Good for you. Here's the problem: <em>live</em> coding demos are a recipe
          for disaster. I can't think of a better scenario that demonstrates Murphy's
          law than trying to execute a live coding demo. You may not have an internet
          connection (oops, there goes the ubiquitous twitter client demo). You may have
          installed some beta software on the plane ride out and, unknowingly, destroyed
          your development environment. The list of things that could go wrong is
          unbounded.</p>
          
          <p>The other problem with live demos is the switching in and out of the
          presentation software you're using. Not only is it visually jarring for the
          audience, but there is invariably some down-time as you switch displays and
          try to figure out which windows are where. Don't give your audience the
          opportunity to tune you out during these noisy transitions.</p>
          
          <p>So, just like you wouldn't create your slides on-the-fly as you present, you
          shouldn't demonstrate live without a net. Instead, record a video of it and
          embed it in your presentation. With a video you get a chance to edit out all
          of the hiccups and noise of the demonstration process. Mistyped something? Got
          a compilation error? Tools are running really slow for some reason? Great,
          just edit those frames out.</p>
          
          <p>Leaving these blemishes in only gives the third-grader part of your audience's
          brain time to sneak in and distract them. You want to keep your audience
          engaged with you every step of the way. Introducing these interruptions into
          the continuity of your presentation breaks the audience's concentration and your
          flow.</p>
          
          <p>Once you get your video captured and edited, practice speaking over it. Really
          make sure that what you say matches well with the video. Get the timing down
          and stay focused on what you're trying to show. Is there something you want to
          say that you isn't in the video? Get back in there and record the right video.
          Don't half-ass it. When you put the time in to make a good supporting video,
          you keep your audience longer.</p>
          
          <h3>Keynote Specifics</h3>
          
          <p><img src="/images/2010/04/keynote-video.png" alt="Video prefs in Keynote" class="right"/></p>
          
          <p>If you're using Apple's Keynote, here are a couple of tips. Once you've
          captured and edited your video, simply drag the video object onto a new slide.
          Open the inspector palette and select the last tab with the Quicktime logo on
          it. Select the checkbox labeled "Start movie on click". This way your video
          won't start running before you're ready to talk about it.</p>
          
          <div class="clear"></div>
          
          
          <p><img src="/images/2010/04/apple-remote.jpg" class="left"/> Also, with a stock
          Apple remote, you can pause and resume your video as needed. This is
          especially helpful when you have a multi-step process to explain that you want
          to cover in bite-sized chunks. This means that you should consider
          pause-points in your capture and editing process. Practicing your speech along
          with the video will help you figure out where the natural breakpoints are.
          Alternatively, you could split the process up into multiple videos on
          different slides.</p>
          
          <h2>Eschew Style</h2>
          
          <p>Customization and personal style are well and good. On your machine you should
          feel free to tweak every little setting to your heart's content. But, please,
          don't force these styles on your audience. Ditch the alpha blend on your
          terminal. Turn off your crazy four-line shell prompt. Pick a color theme in
          your editor that is easy to read in a large font. Pick a display font that is
          appropriate for large projection, not just what you prefer.</p>
          
          <p><img src="http://ecx.images-amazon.com/images/I/51toYiHF35L._SL500_AA300_.jpg" height="150" width="150" class="left"/></p>
          
          <p>Make those fonts BIG. Just like your regular speaking voice needs to be
          amplified to carry to the back of the room, so does the visual volume of your
          content. When recording your coding demos, pick unusually large font sizes and
          take up all of the screen. Also, when capturing your video, try to keep the
          capture frame focused on the essential parts of the demo. For example, if
          you're only editing text, don't clutter the video capture up with a toolbar
          full of things you won't use. Remember, keep it focused! Don't give your
          audience a chance to get distracted by clutter.</p>
          
          <div class="clear"></div>
          
          
          <h2>Keep It Focused</h2>
          
          <p>When presenting a technical topic, it can be frustrating having to jam a large
          amount of content into a small space. There's just so much to share! How can I
          possibly discuss Core Animation in forty-five minutes? The answer is, <em>you
          don't</em>. What you <em>can</em> do is give your audience a taste of the topic you're
          trying to present. Give them enough information for them to decide if they
          want to pursue more on their own. Give them enough terminology and background
          concepts to help them continue the journey.</p>
          
          <p>Presentations are <em>not</em> a good vehicle for in-depth training. Books or
          workshops are much more appropriate for real hands-on learning. Presentations
          are good at giving people a mental roadmap to get started. Get them excited
          by your topic, but don't exhaust them with it.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Menu Bar Ghetto
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/' />
    <updated>
      2010-04-23T08:49:57PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/
    </id>
    <content type='html'>
      <![CDATA[
          <p>The menu bar has become a dumping ground. With each new application I install
          another grubby child is dropped off at the doorstep of the orphanage known
          as the OS X menu bar. This has simply got to stop.</p>
          
          <p><img src="/images/2010/04/status-bar.png"/></p>
          
          <p>Just look at that. Do you think that fits on anything but a large display? I
          can't even see most of these icons on my built-in MacBook display. Only
          humble little Finder, with its spartan set of menus, yields enough real
          estate to display all of these items.</p>
          
          <p>Sadly, I had gotten into the habit of knowing which applications hid status
          bar items from me and would automatically switch to Finder just to reveal
          them. It was the classic mistake we all make of giving in to bad design
          instead of addressing the problem.</p>
          
          <p>So I waged a small holy-war this morning to kick out all but the essential
          applications from my status bar. I feel a little better that I've reclaimed
          my territory, but can't help but feel frustrated that I'll have to do it
          again soon. Why? Because, somehow, application developers got it in their
          heads that they <em>all</em> have to have menu bar items.</p>
          
          <p>I want this to stop. Right now. Please. Do it for the children.</p>
          
          <p>I can't help but think that this reflects a dangerous attitude underlying a
          lot of applications. Stop for a moment and think of the reasons why an
          application provides a menu bar item. Menu bar items exist for applications
          running in the background. These come in two flavors: applications with no
          other user interface (like a window or a preference pane), and ones that do.I
          don't have much of a beef for the ones that can only provide a menu bar item
          as their sole interaction mechanism. It's the applications that <em>do</em> have a
          main UI that I want to give a stern talking-to.</p>
          
          <p>In a windowing system users get to choose what they focus on (save for a few
          cases with alerts and modal dialogs and such). Applications are supposed to do
          the bidding of the user. When I switch away from application XYZ, it means I
          have something more important I need to do. Having that application pop back
          in my face drives me nuts. It drives everyone nuts. I think most folks would
          agree that this is a Bad Experience.</p>
          
          <p>But some applications want to keep your attention. So they compromise by
          creating a little persistent bit of goo and sticking it in the menu bar.
          Because these apps are <em>so fabulous</em>, how could you not want them around all the
          time?</p>
          
          <p>The best menu bar items are ones that provide the essential capabilities of
          the application <em>and</em> give you a quick way to expand to the full application.
          I run iStat menus because it gives me a lot of information in the small
          space it takes up. Why is my machine so slow? Ah, the CPUs are pegged. Why
          are they pegged? Well, just click the menu item and see that application XYZ
          is taking up 90% of my cycles. It's a great example progressive disclosure.</p>
          
          <p>Some applications like <a href="http://www.shinywhitebox.com/home/home.html" title="iShowU">iShowU</a> or <a href="http://www.realmacsoftware.com/littlesnapper/" title="Little Snapper">Little Snapper</a> provide a menu bar item because they need to get out of your
          way. You don't want to screen capture the screen capture tool itself, right?
          For these kinds of apps that provide functionality that spans multiple
          applications, I think this is okay.</p>
          
          <p>What I can't stand are applications that provide a menu bar item, then keep it
          there after I've quit the application. <a href="http://www.evernote.com" title="Evernote">Evernote</a> is a good example of this. You have to <em>really</em> go out of your way
          to make Evernote not do this. Worse yet, its default behavior is to install
          itself as a startup item so that it's sitting there in your menu bar until you
          take time out of your busy day to turn it off. Boo. Hiss.</p>
          
          <p>I like Evernote quite a bit, but I get the impression its creators think it's
          so special that it deserves to be in your face, all the time. It's like that
          annoying guy you got stuck talking to at the company party that you can't rid
          yourself of. Go away.</p>
          
          <p>The worst case of this is VMWare. I can't, for the life of me, figure out how
          to disable VMWare's menu bar item. For folks that need to run a lot of non-Mac
          apps I can see the advantage. The Unity stuff in VMWare is pretty freaking
          cool. But if you're <em>not</em> one of those people, it's pretty rude to have this
          whole other application-launcher sitting there, taking up space, that you only
          occasionally use. Shame on you VMWare. I'm happy to pay for a license because
          I think it's a great product, but that doesn't mean I want to see your
          goddamned menu item in my status bar all the time.</p>
          
          <p>So if you're building a Mac application and considering a menu bar item,
          please consider the following advice. If you're building a background utility
          with no other UI, think hard about how much the user needs to interact with
          your application. Is it something they need to fiddle with more than once a
          session? If not, try to make a Preference Pane and leave it at that. If it's
          something the user is going to use a lot, or displays some kind of realtime
          information (à la iStat menus) then adding to the menu bar is okay.</p>
          
          <p>If you're building an application with a main UI component, think long and
          hard about the necessity of menu bar item. If it can integrate with other
          applications (like Little Snapper) there's a reasonable case to be made for
          providing a menu bar item. Even then, you should consider providing a Services
          menu item and/or a global keyboard shortcut. This is an especially good idea
          if your application only provides one or two actions that users can take. It's
          hard to justify a two-item menu bar item, so sometimes you see applications
          put other non-essential items in there like Preferences or an About dialog.
          Don't do this.</p>
          
          <p>For these sorts of applications, the menu bar item should <em>always</em> be
          optional. The app should still be able to do what it needs to without having
          that menu bar item enabled. Also, leave it off by default and make it easy for
          the user to turn it on. Make it an opt-in feature rather than an opt-out
          feature. As much as I love Tweetie, the opt-out nature of its menu bar item is
          the kind of stuff that drives me nuts. The option is enabled (or not
          disabled?) and the language is confusing. Worse yet, it doesn't take effect
          until you restart the application.</p>
          
          <p><img src="/images/2010/04/tweetie-prefs.png"/></p>
          
          <p>Finally, unless you have some kind of special papal dispensation, never, ever,
          ever keep your menu bar item running when the application is gone. OK,
          technically if there's a menu bar item the application is still running, but
          that's a distinction that user's don't care about (nor should they have to).</p>
          
          <p>There's been a long, ongoing debate about the necessity of optimizing the
          performance of applications. As horsepower has increased, programmers have
          been afforded some laziness in optimizing their applications. I only have a
          problem with that in extreme cases because hardware power has increased at
          such an impressive rate. However, our displays aren't growing at the same
          rate. We need to treat that screen real estate as precious. The menu bar is a
          great place to put global, cross-application functionality, but there's only
          so much space for all of these applications. Think long and hard about the
          necessity of taking up that space and always put the power in the users' hands
          to choose.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Thanks, mom
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/17/thanks-mom/' />
    <updated>
      2010-04-17T20:23:21PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/04/17/thanks-mom/
    </id>
    <content type='html'>
      <![CDATA[
          <p>It's been a while since I last posted. Normally I wouldn't preface a post with
          that (it drives me crazy when I read it elsewhere), but my world changed
          completely last month when, on March 5th, my mom unexpectedly passed
          away. I found out the following morning, and things haven't been the same
          ever since.</p>
          
          <p><img class="left" src="/images/2010/04/rosebowl.jpeg" title="My last day with mom at the 2010 Rose Bowl"/></p>
          
          <p>Since her death, I've been tossed into the deep-end of estate-management as
          I try to clean up the remnants of her financial and legal life. It's amazing
          how much a person leaves behind. There are all sorts of things to clean up like
          calling her dentist and canceling a pending appointment, or telling the local
          pharmacy that she won't ever be coming in again to pick up her prescription.</p>
          
          <p>In the last month, I've realized I'm not the same person I used to be. It sounds
          trite, but this event has given me a serious perspective
          adjustment. Things that used to seem scary to me now seem insignificant.
          Things I always wanted to do but put off for some day in the future, get
          addressed now. Life is short. You never know what can happen.</p>
          
          <p>By nature, my wife and I inveterate planners. My god, I started an IRA when
          I was 21. Who the hell does that? But now it's time to think more about
          the present. We haven't completely abandoned our careful planning, but we've
          stopped putting off things we want to do.</p>
          
          <p>One of those things has been a growing desire to be my own boss. For
          the longest time I could never imagine running my own show. There was
          too much work, stress and responsibility. I was happy trading independence for
          the comfort and security of a steady paycheck. But over the last few years
          I've been feeling a deep and acute dissatisfaction working for someone else.
          I came to the conclusion that I wasn't going to be happy until I stopped
          working on other people's ideas and took a shot (or two) at working on my own.</p>
          
          <p>So now it's time to stop being so unhappy about it. As of May, I'm on my own.
          My plan is to build a small product-development company. I don't need to make
          scads of money, I just want to support my family. I want to work on things that
          I deeply care about. I want to spend my time doing things that matter to me,
          and as little time as possible on "shoulds", "musts", and "have-tos". I'll
          pick up contracting work as needed (tell all your friends),
          but the long-term plan is to live off of product revenue. I guess some people
          might call it a "lifestyle business". I call it dropping out of the rat-race
          and living the life more fully.</p>
          
          <p>How am I going to do this? What's my plan? Beats the hell out of me. I'll
          figure it out as I go. All I know is that everything I've gone through in the
          last month has made me realize that it's going to work out fine. There's
          nothing that could happen that would equal what I've recently gone through.</p>
          
          <p>So what about the title of this post? What exactly am I so thankful for?
          Well, certainly not about the loss of my mother. Nothing could replace her.
          Nothing will bring her back. She was my moral compass. She was the greatest
          teacher I ever had. I didn't really appreciate the tools she left me with
          until she was gone. Now I realize that she left me with everything I needed
          to cope with this tragedy as well as being able to move beyond it. I don't
          know if I would ever have been shaken out of my day-to-day routine without her
          loss. I wouldn't trade this epiphany for her, but I don't have that option.
          What I can do is move forward and live a life that honors her memory.</p>
          
          <p>My mom was a survivor. She survived the breakup of my family. She survived
          cancer. She survived my brother's death. After her divorce she rebuilt her
          life from scratch, eventually becoming an assistant Dean at the School of
          Education at the University of Oregon. Her crowning achievement was completion
          of school's new building on the U of O campus. Over the span of nearly a decade
          she raised funds from private donors&mdash;mostly teachers. But the final
          dollar amount isn't what's impressive about her work. What's impressive is
          how she took a group of people, turned them into a community and got them to
          believe in themselves. Mom, I wish I could have told you just how proud I am
          of you.</p>
          
          <p>So, mom, this life is for you. You always had a strong independent streak. You
          didn't get a chance to enjoy the future that you worked so hard for. You
          gave me so much. The best way I can think to pay it back, is to live the life
          you would have wanted for me, and to pass that on to my daughter.</p>
          
          <p>Thanks, mom. Thank you, so very much.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Scripting Build Selection in Xcode
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/' />
    <updated>
      2010-03-06T00:20:30PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/
    </id>
    <content type='html'>
      <![CDATA[
          <p>When I'm doing iPhone development, I constantly
          switch between running on the device and the simulator. As far
          as I can tell, Xcode doesn't provide an easily-accessible keyboard
          shortcuts for switching between SDKs. Since I <em>hate</em> breaking up my flow by
          having to reach for the mouse, I put together a couple of
          AppleScripts that bind hot-keys to switching between SDKs. Download
          these two scripts to wherever you like to store your AppleScripts.
          I like to put mine in <code>~/Library/Scripts</code>.</p>
          
          <p>First, is the script that selects the SDK for the device:</p>
          
          <div>
          <a href="/files/SwitchToDevice.scpt" class="attachment">
            SwitchToDevice.scpt
          </a>
          
          
          <div class="highlight"><pre><span class="k">tell</span> <span class="nb">application</span> <span class="s2">&quot;Xcode&quot;</span>&#x000A;      <span class="k">set</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="na">active</span> <span class="nv">project</span> <span class="na">document</span>&#x000A;      <span class="k">set</span> <span class="na">active</span> <span class="nv">SDK</span> <span class="k">of</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="s2">&quot;iphoneos3.1.3&quot;</span>&#x000A;    <span class="k">end</span> <span class="k">tell</span>&#x000A;    </pre>
          </div>
          
          </div>
          
          
          <p>Next up, the script that selects the simulator SDK:</p>
          
          <div> 
          <a href="/files/SwitchToSimulator.scpt" class="attachment">
            SwitchToSimulator.scpt
          </a>
          
          
          <div class="highlight"><pre><span class="k">tell</span> <span class="nb">application</span> <span class="s2">&quot;Xcode&quot;</span>&#x000A;      <span class="k">set</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="na">active</span> <span class="nv">project</span> <span class="na">document</span>&#x000A;      <span class="k">set</span> <span class="na">active</span> <span class="nv">SDK</span> <span class="k">of</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="s2">&quot;iphonesimulator3.1.3&quot;</span>&#x000A;    <span class="k">end</span> <span class="k">tell</span>&#x000A;    </pre>
          </div>
          
          </div>
          
          
          <p>Now, open up Xcode and and select "Edit User Scripts..." in the
          scripts menu:</p>
          
          <p><img src="/images/2010/02/xcode-script-menu.png" class="plain"/></p>
          
          <p>This opens the script organizer. In the left-hand pane is a list of
          all the script groups. Which group you put a script in effects what
          submenu they are available from in the main scripts menu. But we like
          shortcut keys so who cares where it goes? I put these in the "Build"
          group, but feel free to put them wherever makes the most sense to
          you. Select the group you want to add these scripts to and click the "+"
          button and choose "Add Script File&hellip;":</p>
          
          <p><img src="/images/2010/02/edit-user-scripts-dropdown.png" class="plain"/></p>
          
          <p>Use the standard Finder dialog to find the scripts you just downloaded
          and select one of them. To set the shortcut key for the script,
          double-click the right-hand column of the newly-added script. For the
          simulator script I use <code>⌃⌘⎇S</code> and <code>⌃⌘⎇D</code> for the device script. You
          can try out different combinations. If you come up with a key-chord
          that clobbers an existing key-binding Xcode will give you a warning at
          the bottom of the window.</p>
          
          <p><img src="/images/2010/02/edit-user-scripts-warning.png" class="plain"/></p>
          
          <p>One thing to be aware of is that while you're setting the shortcut
          key for the script <em>all</em> of your keyboard input is directed to that
          field. So you can't use ESC to cancel or Enter to set the value. You
          need to grab that infernal mouse and click somewhere else.</p>
          
          <p>Before you close the dialog, be sure to set the "Output" drop-down
          menu to "Discard Output" otherwise Xcode will paste some odd gibberish
          into your current file. And, just in case there's some kind of
          unforseeable error, set "Errors" drop down to "Display in Alert". Once
          you have both scripts configured you can close the dialog and try your
          new hot-keys out.</p>
          
          <p>I don't claim to have any proficiency with AppleScript, so there
          may very well be a better way to do this. Certainly one thing that is
          brittle about these scripts is how they are hard-coded to a particular
          version of the SDK. Whenever a new SDK is released I'll have to update
          the strings in the script. Oh well, it beats having to reach for the
          mouse several more times a day.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          RVM meets zsh
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/' />
    <updated>
      2010-02-27T17:19:45PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/
    </id>
    <content type='html'>
      <![CDATA[
          <p><a href="http://rvm.beginrescueend.com/">RVM</a> is a nifty tool for managing
          multiple ruby installations. Not only does it make it easy to install
          and switch between multiple rubies, but you can also install
          gems without <code>sudo</code> access. But, as great as RVM is, I still have to
          remember to switch between rubies and often I don't remember to do it
          until I see some weird behavior or a test breaks. I'm very lazy and
          I want even <em>more</em>.</p>
          
          <p>So I've setup a tiny bit of zsh-fu to automatically switch which ruby
          implementation to use based on the directory that I'm in. To do this, one
          needs to take advantage of <a href="http://zsh.sourceforge.net/Doc/Release/Functions.html#SEC45">zsh's
          hooks</a>,
          particular the one invoked when you change directories. By default,
          you can simply declare a function named <code>chdir()</code> and it will
          automatically be invoked whenever you change directories. Mine looks
          like this:</p>
          
          <div class="highlight"><pre>chpwd<span class="o">()</span> <span class="o">{</span>&#x000A;        <span class="o">[[</span> -t 1 <span class="o">]]</span> <span class="o">||</span> <span class="k">return</span>&#x000A;    <span class="k">    case</span> <span class="nv">$TERM</span> in&#x000A;          sun-cmd<span class="o">)</span> print -Pn <span class="s2">&quot;\e]l%~\e\\&quot;</span>&#x000A;            ;;&#x000A;          *xterm*|rxvt|<span class="o">(</span>dt|k|E<span class="o">)</span>term<span class="o">)</span> print -Pn <span class="s2">&quot;\e]2;%3~\a&quot;</span>&#x000A;            ;;&#x000A;        <span class="k">esac</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>This function just prints out the name of the directory I've change
          into and it's found in a lot of zsh distributions. To keep things clean
          I want to have a separate function that just manages the RVM
          updating. For the moment, let's ignore the fact that I already have an
          existing <code>chdir()</code> function, and look at the hook function I created
          to invoke RVM:</p>
          
          <div class="highlight"><pre>chpwd_check_rvm<span class="o">()</span> <span class="o">{</span>&#x000A;        <span class="nv">current_version</span><span class="o">=</span><span class="k">$(</span>rvm info | grep <span class="s2">&quot; version:&quot;</span> | cut -d <span class="s1">&#39;&quot;&#39;</span> -f2<span class="k">)</span>&#x000A;        <span class="nv">dir</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>&#x000A;        <span class="k">while</span> <span class="o">[</span> <span class="s2">&quot;${dir}&quot;</span> !<span class="o">=</span> <span class="s2">&quot;&quot;</span> <span class="o">]</span>; <span class="k">do</span>&#x000A;    <span class="k">        </span><span class="nv">cfg</span><span class="o">=</span><span class="s2">&quot;${dir}/.rvminfo&quot;</span>&#x000A;            <span class="k">if</span> <span class="o">[</span> -f <span class="k">${</span><span class="nv">cfg</span><span class="k">}</span> <span class="o">]</span>; <span class="k">then</span>&#x000A;    <span class="k">            </span><span class="nv">want_version</span><span class="o">=</span><span class="k">$(</span>cat <span class="k">${</span><span class="nv">cfg</span><span class="k">})</span>&#x000A;                <span class="k">if</span> <span class="o">[</span> <span class="s2">&quot;${want_version}&quot;</span> !<span class="o">=</span> <span class="s2">&quot;${current_version}&quot;</span> <span class="o">]</span>; <span class="k">then</span>&#x000A;    <span class="k">                </span>rvm use <span class="k">${</span><span class="nv">want_version</span><span class="k">}</span>&#x000A;                <span class="k">fi</span>&#x000A;    <span class="k">            </span><span class="nb">break</span>&#x000A;    <span class="nb">        </span><span class="k">else</span>&#x000A;    <span class="k">            </span><span class="nv">dir</span><span class="o">=</span><span class="k">${</span><span class="nv">dir</span><span class="p">%/*</span><span class="k">}</span>&#x000A;            <span class="k">fi</span>&#x000A;    <span class="k">    done</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>This function looks for a file named <code>.rvminfo</code> in the current
          directory (this function is invoked <em>after</em> we've changed
          directories). If the file isn't found in the new directory, it searches
          upward through each parent directory to see if it can find one. If
          it's found, the function invokes <code>rvm use</code> with the version string
          found in that file.</p>
          
          <div class="highlight"><pre><span class="nv">$ </span>cat .rvminfo&#x000A;    1.8.6&#x000A;    </pre>
          </div>
          
          
          <p>There's also some additional checking to avoid extra <code>rvm</code> invocations
          if we're already set to the desired version. This is done more to
          reduce the chatter in the shell than for performance reasons.</p>
          
          <p>Now let's get back to invoking multiple hook functions.
          If you have more than one function you'd like to have called when
          you change directories, you can declare these in an array named
          <code>chpwd_functions</code>. After declaring the <code>chpwd_check_rvm()</code> function
          above, having two functions for the <code>cd</code> hook is trivial. I just add
          this declaration to my <code>~/.zshrc</code> file:</p>
          
          <div class="highlight"><pre><span class="c">#--- chpwd_functions</span>&#x000A;    <span class="nv">chpwd_functions</span><span class="o">=(</span> chpwd_check_rvm chpwd <span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>Now, whenever I change into a directory with a <code>.rvminfo</code> file, my
          hooks are automatically executed and I get the right ruby version:</p>
          
          <div class="highlight"><pre><span class="o">[</span>island<span class="o">]</span> ~/Development: <span class="nb">cd </span>alexvollmer.com &#x000A;    &lt;i&gt; Now using ruby 1.8.6 p383 &lt;/i&gt;&#x000A;    </pre>
          </div>
          
          
          <p>One final note is that I put all of my specific functions in the
          <code>~/.zsh/functions</code> directory, and automatically load all of them in my
          <code>~/.zshrc</code> file with the snippet below. I do all of this <em>before</em> I
          declare the <code>chpwd_functions</code> array.</p>
          
          <div class="highlight"><pre><span class="c">#--- Shell Functions ---</span>&#x000A;    <span class="c">#</span>&#x000A;    fpath+<span class="o">=(</span>&#x000A;      <span class="k">${</span><span class="nv">HOME</span><span class="k">}</span>/.zsh/functions&#x000A;    <span class="o">)</span>&#x000A;    &#x000A;    autoload -U ~/.zsh/functions/*<span class="o">(</span>:t<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>You may want to organize your functions differently. Just be aware
          that zsh needs to know about your functions before you can put them in
          the <code>chpwd_functions</code> array.</p>
          
          <p><em>UPDATE (3/1/2010):</em> Per comments below from RVM's creator, Wayne Seguin, RVM
          actually comes with it's own built-in way of handling this. Somehow I
          completely missed <a href="http://rvm.beginrescueend.com/workflow/rvmrc/">the rvmrc
          documentation</a> for this
          feature (how embarassing!). I'm usually inclined to avoid re-inventing
          the wheel, but there are two small things I like about the way I
          implemented this. First, the solution proposed here doesn't redefine
          the <code>cd</code> command, which feels a bit like duck-punching the shell to
          me. I don't know if bash has the same kind of hooks that zsh does, so
          the implementation is understandable. As for me, I like the hooks
          better.  Second, the solution I show here works for any sub-directory
          within a project that has a specific RVM setting. That said, I'll
          probably just use what's already been implemented in RVM.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Static Cling
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/02/22/static-cling/' />
    <updated>
      2010-02-22T17:40:40PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/02/22/static-cling/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Lord knows why, but in the last couple of months I felt compelled to
          move off of Wordpress and onto one of those new static content
          generators for this site. Part of it was motivated by getting fed up
          with constantly upgrading Wordpress. I suppose another part of it was
          because all the <a href="http://userprimary.net">cool</a>
          <a href="http://davepeck.org/">kids</a> were doing it. But, most importantly,
          I wanted to give the site design a reboot&mdash;something I did <em>not</em>
          want to do in PHP in the form of Wordpress themes. So with a little
          help from <a href="http://whole-studios.com/">a friend</a>, this site got a
          facelift and a new platform to boot.</p>
          
          <p>I chose to use <a href="http://nanoc.stoneship.org">Nanoc</a> as the
          site-generator. Originally I was going to go with
          <a href="http://github.com/mojombo/jekyll">Jekyll</a>. I really liked its
          simplicity and the fact that it had prescribed locations for
          everything. However, I still wanted to maintain some
          backward-compatability with the old site. This meant a little bending
          of Jekyll's rules and, frankly, Jekyll just isn't as configurable and
          flexible as Nanoc. That's not a dig against Jekyll, nor is it an
          endorsement of Nanoc. Nanoc is a general-purpose solution for
          generating static sites, but it's not necessarily optimized for
          blogging. But with Nanoc I can use HAML, SASS and other Rails-isms
          with which I'm already familiar. If you want to see the gory details,
          I've put the whole thing up on
          <a href="http://github.com/alexvollmer/alexvollmer.com">GitHub</a>.</p>
          
          <p>Sadly, this ended up taking much longer than I anticipated.
          First, I had to import the old posts from Wordpress. The database
          schema for Wordpress is pretty wacky looking when you're used to
          working with Rails. Thankfully, Jekyll already gone down this path and
          I used their Wordpress importer as inspiration for writing my
          own. Along the way I discovered what great gem
          <a href="http://rubygems.org/gems/sequel">Sequel</a> is. A large part of the
          importing process was converting from all of the jacked-up formats
          I've amassed over the years to Markdown. It took a <em>lot</em> of iterations
          to catch every weird character-encoding and formatting issue.</p>
          
          <p>Another large effort was creating the RSS feeds. Now Nanoc has <em>some</em>
          support for Atom, but it didn't quite do what I wanted. I was trying
          to match what Wordpress was generating for me so I basically
          re-implemented feed-generation from scratch.</p>
          
          <p>Moving old comments into <a href="http://disqus.com">Disqus</a> took about
          a week to get right. As a user, the Disqus service is pretty
          cool. As a web API, it's a little&hellip;ahem&hellip; lacking. If
          you're used to well-constructed REST APIs, you'd best drink something
          stiff before settling in with the <a href="http://groups.google.com/group/disqus-dev/web/api-1-1">API
          docs</a>. The
          <a href="http://github.com/norman/disqus">disqus gem</a> borders on useless. So,
          I ended having to write my own importer with httparty. It took several
          iterations to really get this nailed and the process was pretty
          frustrating.</p>
          
          <p>The sad part about this, is that originally I was on the fence about
          adding comments at all. Initially I thought I'd try it out and see if
          I liked it. But I'm a geek, right? I couldn't get it working right
          away and it drove me nuts! I <em>had</em> to figure it out. So eventually I
          figured out the magic recipe, and now I'm wondering if I even really
          wanted comments integrated at all. Oh well.</p>
          
          <p>One trick that I found very helpful throughout this process was
          creating some scripts that dropped me into an IRB session with the
          Nanoc blog or Disqus API objects already initialized. This was
          inspired by the Rails console which I find invaluable for tinkering with
          things in real-time. For example, while I was dickering with the Nanoc
          internals, I found this console script to be quite helpful:</p>
          
          <div class="highlight"><pre><span class="c1">#!/usr/bin/env ruby</span>&#x000A;    &#x000A;    <span class="nb">require</span> <span class="s2">&quot;irb&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;rubygems&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;nanoc3&quot;</span>&#x000A;    <span class="nb">load</span> <span class="s2">&quot;lib/helpers.rb&quot;</span>&#x000A;    &#x000A;    <span class="vi">@site</span> <span class="o">=</span> <span class="no">Nanoc3</span><span class="o">::</span><span class="no">Site</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>&#x000A;    <span class="vi">@site</span><span class="o">.</span><span class="n">load_data</span>&#x000A;    &#x000A;    <span class="no">IRB</span><span class="o">.</span><span class="n">start</span>&#x000A;    </pre>
          </div>
          
          
          <p>Now, Wordpress and I differ on what constitutes a sensible URL
          scheme. So that last bit I needed was to concoct some redirect rules
          to port the old URL scheme to the new one. Currently, this site is
          hosted on <a href="Dreamhost">http://dreamhost.com</a> which, provides support
          for <code>.htaccess</code> files. With a little Apache-fu I was able to get most
          of the old WP URLs to redirect correctly:</p>
          
          <div class="highlight"><pre>RewriteEngine ON&#x000A;    RewriteRule ^index.php/feed/ /feeds/rss_2_0.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/feed/rss/ /feeds/rss_0_9_2.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/feed/atom/ /feeds/atom.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/<span class="o">(</span>.*<span class="o">)</span> /posts/<span class="nv">$1</span> <span class="o">[</span>R<span class="o">]</span>&#x000A;    &#x000A;    ErrorDocument 404 /missing.html&#x000A;    </pre>
          </div>
          
          
          <p>Well, that took longer than I thought. I can't say that it wasn't
          educational. Now, what was I <em>supposed</em> be doing?</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The iPad
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/31/the-ipad/' />
    <updated>
      2010-01-31T08:12:05PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/01/31/the-ipad/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/IPad-01.jpg/250px-IPad-01.jpg" alt="iPad" class="left">
          After letting the dust settle around Apple's announcement of the iPad,
          I wanted to take a more measured, less reactionary look at the new
          device. The coverage that immediately followed the announcement was
          even more biased to both extremes than coverage of the President's
          State of the Union address which occurred the same day. I know that
          there's a growing body of folks who just don't like Apple, but I was
          surprised at the level of antipathy.</p>
          
          <p>Those that damned the iPad seemed to come in two flavors: those that
          saw the iPad as the embodiment of corporate greed and walled gardens,
          and those that thought the device didn't measure up to their personal
          expectations.</p>
          
          <p>There is a sizable (and growing) population of folks that simply will not
          purchase an Apple product or participate in its eco-system for
          various reasons. I think that's fine. While I personally enjoy their
          products, I don't believe that everyone has to agree with me. I get no
          less enjoyment out of my MacBook or iPhone by someone else having a
          Lenovo ThinkPad or an Android Phone.</p>
          
          <p>Unfortunately, that view isn't shared by many. Take the flame-baiting
          in the aftermath of the iPad announcement and replace the term "iPad"
          with "gay marriage" and the arguments look nearly identical. Gay
          marriage is so upsetting to conservatives that they can't imagine
          being in a world where it exists. It's not that gays are coming into
          their homes and performing unspeakable acts, it's that they can't
          imagine <em>even being on the same planet with them</em>. So it goes with the
          iPad&mdash;there are the FSF types who can't imagine living in a world
          where Apple controls every single thing that goes on a device.</p>
          
          <p><img
          src="http://cache.gawker.com/assets/images/jalopnik/2009/02/obama-state-of-the-union.jpg"
          alt="The Prez" class="left" style="height: 162px; width: 293px;"/>
          I'm not aware of anything in the President's address that said every
          man, woman and child in the U.S. was going to be forced to use an
          iPad. As far as I know, people are still free to choose whether or not
          they wish to purchase and iPad and wander about in Apple's walled
          garden. Don't want an iPad? <em>Fabulous</em>. Don't buy one.</p>
          
          <p>Folks, it's a <em>big</em> world out there. There doesn't have to be a single
          winner. Even as Apple trumpets having over 50 million touch devices,
          that pales in comparison to the worldwide population of those who
          <em>could</em> afford such devices. That's even without considering the fact
          that if you own one iPod/iPhone, you probably own another. In terms of
          real numbers, I don't see a growing "collectivization" movement to dress
          everyone in Apple products. If Apple were interested in market share,
          they would charge a lot less for their products.</p>
          
          <p><a href="http://arstechnica.com/tech-policy/news/2010/01/protestors-ipad-is-nothing-more-than-a-golden-calf-of-drm.ars">
          <img
          src="http://static.arstechnica.com/01-27-2010/apple-ipad-protest.jpg"
          alt="iPad Protest" class="right" style="width: 132px; height: 202px;"/>
          </a>
          Besides calling the iPad a freedom-killer, the other category of
          critiques were that the device was simply disappointing. This reaction
          particularly surprises me. Yes, there are certainly quibbles to make
          about various features of the device (no camera, no multitasking,
          etc.) but the dismissive observations that the iPad is simply "a big
          iPhone" I think misses the point. Yeah, it <em>is</em> a big iPhone, which
          has been a huge success by any measurement. If you love the iPhone,
          then the things you most wish it had were more of are screen
          real-estate and speed. So making one that is bigger and faster is
          totally logical. What did people expect? Roomba integration? A
          toaster? 3D goggles?</p>
          
          <div style="clear: both;"></div>
          
          
          <p>ReadWriteWeb attempted to
          <a href="http://www.readwriteweb.com/archives/how_to_hate_the_ipad_a_break-down_of_the_backlash.php#more" title="How to Hate the iPad: A Break-Down of the Backlash">break down the
          anger</a>
          with this graph:</p>
          
          <p><a href="http://www.tweetpad.com" title="TweetPad"><img src="http://www.readwriteweb.com/images/NegativeiPadStory.jpg" alt="" /></a></p>
          
          <p>Looking at this chart, I would categorize 38% of the complaints as
          just pure snark. The next 27% that dismiss it as a "big iPhone" are
          missing the point. The remaining complaints are all valid and worth
          talking about a bit:</p>
          
          <h3>No Flash</h3>
          
          <p>Hooray, I say. I don't run Flash on my desktop or laptop if I can help
          it. I simply do not like Flash. It rarely enhances my experience on a
          site and often pegs my CPUs for no good reason. Yes, <a href="http://theflashblog.com/?p=1641">I'm aware that
          Adobe has to do a lot of video codec work without the aid of
          hardware</a>, but that doesn't address
          the jarring user experience that is Flash. I have not missed Flash on
          the iPhone either. If you want Flash, don't buy a iPod, iPhone or
          iPad. It's as simple as that.</p>
          
          <p>Oh, and if you're running a Mac and feel the same way, do yourself a
          favor and install the <a href="http://rentzsch.github.com/clicktoflash/">Click to Flash
          plugin</a>, which lets you
          ignore Flash on the web completely.</p>
          
          <h3>No Multitasking</h3>
          
          <p>I'm on the fence about this one. I'm not convinced that multi-tasking
          is essential for a device like the iPhone or the iPad. The truth is, I
          have not had many instances where I thought, "Damn! If only I could
          run two apps at once!" I think a lot of people <em>think</em> they want it
          because their computer has this capability.</p>
          
          <p>I think that's the point that is being missed. The iPad is not, in any
          way, being put forth as a general computing device. In fact, to
          categorize it as a "tablet PC" is to completely misunderstand the
          iPad's underlying design philosophy. When I watched the presentation
          and demonstration video what I saw was easy execution of tasks. Nobody
          was demonstrating bit-rates, frames-per-second, or tail-call
          optimization. The underlying technology and "platform" are simply the
          means to an end.</p>
          
          <p>This is a different enough device that people will have to change
          their thinking about their relationship with their computers. I don't
          think it means a comprimising relationship, but one that is different
          from today. Fraser Speirs eloquently called the inability to
          comprehend this shift as <a href="http://speirs.org/blog/2010/1/29/future-shock.html">Future
          Shock</a>.</p>
          
          <h3>Lock-In</h3>
          
          <p>Another major complaint of the iPad and the entire Apple/iTunes
          ecosystem is that it is a closed system. Users don't get to mix and
          match devices freely from other manufacturers. The party-line from
          Apple is that they want to control every aspect to provide the best
          user experience. Detractors argue that it is part of Apple's plan to
          own all of your content like Big Brother (as Microsoft has attempted
          to in the past).</p>
          
          <p>I get why people feel uncomfortable with handing Apple control of
          their stuff. Personally, I have a lot of Apple products in my house
          and I'm happy to give them that control because, for me, it <em>is</em> a
          better experience. I will happily trade some vague notion of "freedom"
          for stuff that just works. Endless fiddling and integration of
          disparate technologies isn't freedom at all&mdash;it's an enslavement
          of the most precious resource I have, which is my time.</p>
          
          <p>Not everyone is happy with that and they prefer an alternative. Hey,
          no problem. Live and let live. You want to run Boxee on Linux
          connected to an iRiver. More power to you. I won't sneer at you or
          call you a fool. If it makes you happy, your choices <em>don't affect me
          in the slightest</em>.</p>
          
          <p>As an aside, if anyone complaining about the lack of Flash is also
          complaining about lock-in, that person needs to be hit repeatedly with
          a rake.</p>
          
          <h3>No Camera</h3>
          
          <p>Sigh. Yeah, this one is a bit disappointing. I don't really care so
          much about having for video chatting (which I do maybe once a
          year). But I really like using a camera to capture things I would
          otherwise have to take a lot of effort to write down. How cool would it
          be to have your iPad in a brainstorming session where you can still
          jot a few notes down then associate a snapshot of the whiteboard?</p>
          
          <p>Now there is an interesting design conundrum here. Do you put the
          camera on the front or the back? Depending on the tasks you expect to
          perform, this makes a huge difference. If you want people to see
          <em>you</em>, you put it on the front and figure out how to give the user
          the user visual feedback so they can position the camera.</p>
          
          <p>If you want to take pictures of other things, you put the camera on
          the back and use the video display as the viewfinder. However you
          can't reasonably reverse the tasks for these two positions. OK, so do
          you put <em>two</em> cameras on? I don't know. How do you control them? Does
          each bit of software implicitly decide which camera to enable? Does
          the user have to decide?</p>
          
          <p>I don't know the answer, but I would be very surprised if a camera
          didn't show up in the next version of the device. They put cameras in the
          iPod Nanos for cryin' out loud. Surely they can figure out how to
          stick one in an iPad.</p>
          
          <h3>More AT &amp; T</h3>
          
          <p>The amount of bad press AT &amp; T has received via the iPhone has to make
          them wonder what sort of devil they've made a deal with. Are there
          serious issues with AT &amp; T? You betcha. Do they effect everyone? I'm
          not convinced. Coverage in San Francisco and Manhattan seem acutely
          poor, but in my corner of the Northwest coverage is pretty damn good.</p>
          
          <p>The non-iPhone types love to make fun of AT&amp;T, fueled largely (I think)
          by schadenfreude. I'd be very curious to see how other carriers handle
          a similar load. I used to work in that industry and the mentality
          among carriers is <em>all the same</em>. They all want to wring every penny
          they can out of you by charging for every bit you use. Let's not kid
          ourselves.</p>
          
          <p>Kudos to Apple for making a WiFi-only version. For me, this is a
          pretty compelling configuration. I'm an urban kid. There are few
          places I go where I can't get some kind of access to WiFi. In the
          cases where I can't get WiFi, I have an iPhone. Plus, I imagine using
          an iPad primarily at home, or on vacation, but not for commuting.</p>
          
          <p>I'm no AT &amp; T apologist&mdash;there are some serious issues they need
          address&mdash; but I'm not convinced that this makes the iPad a
          "failure".</p>
          
          <h3>Conclusion</h3>
          
          <p>Am I an Apple apologist? I hope not, but people are notoriously bad
          judges of their own character. What I can say is that there are
          certainly things about the company that frustrate both as a user and
          developer. However, I am still more delighted by their products than I
          am frustrated with them. When that balance changes, I'll move on to
          something else.</p>
          
          <p>I'm pretty jazzed about this device, both as a consumer and as a
          developer. What sucked me into the iPhone was how it just oozed with
          <em>utility</em>. Not in terms of potential energy, but in that it fulfills
          the notion of computers as and extension of our own minds. The iPad
          just takes the next step forward. I can't wait to see how it all
          unfolds.</p>
          
          <p>P.S. Just I'm glad to see the iPhone finally get some competition, I'm
          also looking forward to somebody putting up a good fight against the
          iPad.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Prototyping with Briefs
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/' />
    <updated>
      2010-01-10T17:40:40PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/
    </id>
    <content type='html'>
      <![CDATA[
          <p>One of the best sessions I saw at the 2009 WWDC was titled "Prototyping iPhone User Interfaces". In this session, Bret Victor laid out a strategy and some techniques for building cheap prototypes on the the device in lieu of "static" mockups.</p>
          
          <p>After returning from WWDC I was inspired to try this technique out and after playing with the idea for a bit, it was clear that there was a lot of repetition in the process. To really make prototyping cheap, we need a simple framework that makes the process fast and easy. Enter <a href="http://github.com/capttaco/Briefs">Briefs</a>, a lightweight iPhone application that allows you to embed and run simple prototypes built with nothing more than images and a property list.</p>
          
          <p>With Briefs, you don't write a separate application for the device (imagine the provisioning headaches), but instead embed separate prototypes (called "briefs") into a single Briefs application. Briefs is still pretty new and I expect to see (and contribute) many enhancements, but if you like this style of application development, it's certainly worth spending some time with Briefs.</p>
          
          <p>Let's look at how it works. We're going to start with the goal of prototyping the built-in Photos application. Now obviously, nobody is going to actually <em>re-write</em> the Photos app, but since we all have familiarity with it, it's a good example to see how a working application can be expressed as a Briefs prototype.</p>
          
          <h1>Getting Briefs</h1>
          
          <p>Before we do anything, we need to get Briefs on our local machine. Briefs is distributed in source-only form via <a href="http://github.com/capttaco/Briefs">GitHub</a>. You'll need to find a nice place to check out the two main Briefs project, then do the following:</p>
          
          <div class="highlight"><pre><span class="nv">$ </span>git clone git://github.com/capttaco/Briefs.git&#x000A;    <span class="nv">$ </span>git clone git://github.com/capttaco/Briefs-util.git&#x000A;    <span class="nv">$ </span><span class="nb">cd </span>Briefs&#x000A;    <span class="nv">$ </span>git submodule update -i&#x000A;    </pre>
          </div>
          
          
          <p>In order to put our first Brief together, we need to build a command-line tool that is part of the Briefs project. Open the Xcode project in the Briefs folder (<code>Briefs.xcodeproj</code>) and select the "Briefs Compactor" target and set the architecture to "Base SDK".</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-7.50.17-AM.png" alt="Screen shot 2010-01-10 at 7.50.17 AM.png" /></p>
          
          <p>Now execute the target to build the <code>compact-briefs</code> executable. When it's finished, Xcode will put the final binary in <code>build/Debug/compact-briefs</code> in the Briefs project directory. Copy this file to a location in your <code>$PATH</code>. Personally I like to keep such stuff in <code>~/bin</code>. We'll need this command in a little bit.</p>
          
          <h1>How it Works</h1>
          
          <p>Before we dive into our project, we should get a little terminology under our belt. Each application prototype you create is called a "Brief". Each Brief is composed of one or more "Scenes". Scenes usually have an associated image, so you can think of a scene and a screen in the application as being more or less equivalent.</p>
          
          <p>Scenes can also have any number of "Actors", which are regions on the screen that perform some action when touched. For example, to mimic navigating to a new view via a view controller, a region on a table view could be rigged to an action that slides another scene into place.</p>
          
          <p>Briefs are expressed as Property List (Plist) files in the Briefs application. If you like writing XML or are proficient with the Property List Editor application, then you're golden. Otherwise there is another format in which you can write your brief that compiles down to a final Plist. This is the route we'll explore in our prototype.</p>
          
          <h1>Protyping Photos.app</h1>
          
          <h2>Generate Image Files</h2>
          
          <p>Now let's generate the image files for our prototype. In the case of the existing Photos app, I just screen-captured the running application on the simulator. Obviously, you won't be in the same position with a new application, so you'll need to generate some images by hand.</p>
          
          <p>If you use OmniGraffle, there are several good iPhone stencil sets on <a href="http://graffletopia.com/categories/iphone">Graffletopia</a>. If you prefer Photoshop, checkout the exhaustive <a href="http://www.teehanlax.com/blog/2009/06/18/iphone-gui-psd-30/">iPhone GUI PSD</a>. Either one of them will generate the appropriate files. There's no requirement that the image files <em>look</em> like the iPhone. You could use a  tool like <a href="http://www.balsamiq.com/products/mockups">Balsamiq</a> or scan hand-drawn sketches to generate very simple wireframe sketches. Regardless, all you need to do is produce PNG, GIF or JPEG files that fit within the normal iPhone dimensions (320 x 480).</p>
          
          <p>Let's create a folder called "photos app" and put our image files in it. I've created <a href="http://alexvollmer-public.s3.amazonaws.com/photos_app.tgz">a tar-ball of this entire project</a>, which you can download, explore and run.</p>
          
          <h2>Writing the Brief</h2>
          
          <p>Let's think a bit about the flow of our application. We're only going to implement a sub-set of Photo.app's full navigation&mdash;we'll just implement the flow for the Hawaii photo album. We have a top-level screen that shows all of the photo albums. From there the user can select "Hawaii" and drill into a display of a few images in the album. Touching any of the images will take the user into the image browser where users can go back and forth between the various images. Each screen has a common "back" button in the top-left. The overall screen layout and flow looks like this:</p>
          
          <p><a name="app-flow"><img src="/images/2010/01/photos-app-flow.png" alt="photos-app-flow.png" /></a></p>
          
          <p>The pink boxes highlight the touchable areas in each scene. The arrows between them show which scene a particular area navigates to. In Briefs-parlance, each screen is a "Scene" and each pink box is an "Actor".</p>
          
          <p>Let's step through the Brief (the <code>photos.bs</code> file), a bit at a time. If you get lost, refer back to the <a href="#app-flow">application flow diagram</a> above.</p>
          
          <p>First we declare that our starting scene is the "Home" scene. Next, we define that scene with the image <code>home.png</code> as the background image and one actor that will navigate to the next scene. The position and size of this actor corresponds to the table cell labeled "Hawaii". If we wanted to support the table rows, we'd need to add an actor for each one.</p>
          
          <p>When the user touches the "Hawaii" row, we'll transition the "Hawaii" scene (defined shortly) by executing a "push left" animation. This will mimic the standard animation of pushing a new view controller onto the navigation controller stack:</p>
          
          <div class="highlight"><pre>start:Home&#x000A;    scene:Home&#x000A;      image:home.png&#x000A;      actor:HawaiiPictures &#x000A;        position:0,123 &#x000A;        wh:320,53&#x000A;        action:goto<span class="o">(</span>Hawaii, push left<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>Next, we'll define a scene that shows the thumbnail images for each photo in the Hawaii album. This scene will display the <code>hawaii.png</code> background image and has an actor for the return navigation button in the upper-left as well as for each thumbnail image. Note the differences in the direction of the push animation in the actors. The "back" button pushes right (like the normal return navigation animation), while the thumbnails push left.</p>
          
          <div class="highlight"><pre>scene:Hawaii&#x000A;      image:hawaii.png&#x000A;      actor:Home &#x000A;        position:17,30 &#x000A;        wh:87,24 &#x000A;        action:goto<span class="o">(</span>Home, push right<span class="o">)</span>&#x000A;      actor:image1 &#x000A;        position:5,69 &#x000A;        wh:72,72 &#x000A;        action:goto<span class="o">(</span>Image1, push left<span class="o">)</span>&#x000A;      actor:image2&#x000A;        position:84,70&#x000A;        wh:72,72&#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;      actor:image3&#x000A;        position:162,70&#x000A;        wh:72,72&#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>Now we'll define the scenes for each of the three images. Each image scene has an actor for the return navigation button in the top-left. The first image also has two actors to navigate to the next image. The <code>NextImage</code> actor is for the navigation button in the toolbar, whereas the <code>NextImageSwipe</code> actor covers the right side of the image itself. This is done to mimic the swiping motion normally used to navigate photos. Right now, Briefs only supports single-touch interactions so it won't behave <em>exactly</em> like the real application in supporting swipes.</p>
          
          <div class="highlight"><pre>scene:Image1&#x000A;      image:image1.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:NextImage &#x000A;        position:202,450 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;      actor:NextImageSwipe &#x000A;        position:156,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>The "Image2" scene is a lot like the "Image1" scene, except that it has button and swipe actors for both the previous and next images:</p>
          
          <div class="highlight"><pre>scene:Image2&#x000A;      image:image2.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:PreviousImage &#x000A;        position:94,452 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image1, push right<span class="o">)</span>&#x000A;      actor:PreviousImageSwipe &#x000A;        position:0,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image1, push right<span class="o">)</span>&#x000A;      actor:NextImage &#x000A;        position:202,450 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;      actor:NextImageSwipe &#x000A;        position:156,60&#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>Finally, the last image scene. It only has "backward" navigation in the photo set since we've only put three photos in our album:</p>
          
          <div class="highlight"><pre>scene:Image3&#x000A;      image:image3.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:PreviousImage &#x000A;        position:94,452 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image2, push right<span class="o">)</span>&#x000A;      actor:PreviousImageSwipe &#x000A;        position:0,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image2, push right<span class="o">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>We've just done simple scene-to-scene transitions in this Brief, but there are also several transitions you can perform directly on actors such as moving them, fading them in and out and others. I've created a <a href="http://alexvollmer-public.s3.amazonaws.com/Briefs%20Cheatsheet.pdf">syntax cheatsheet</a> which you can use as a reference for your own Briefs.</p>
          
          <h2>Compiling the Brief</h2>
          
          <p>Once we have our photos, it's time to start writing our Brief. As mentioned earlier, the Briefs application consumes Plist files. However you can't just create one out of the box because it will only have image file <em>references</em> in it, but not the actual data. The reason we built the <code>compact-briefs</code> command earlier, was so that we could take our intermediate Briefs file (usually called a <em>source</em> brieflist) and embed the image data directly in the final product.</p>
          
          <p>However I find editing XML tiresome, whether it's by hand or with a tool. Briefs provides an alternate syntax in which to write briefs which is transformed by a Ruby script into the intermediate Plist format. You can then compile the source brieflist to the final format using the <code>compact-briefs</code> command. The flow between formats and tools looks like this:</p>
          
          <p><img src="/images/2010/01/briefs-flow.png" alt="briefs-flow.png" /></p>
          
          <p>In the <code>Briefs-util</code> project (which you checked out earlier), you can find the Ruby script in <code>BS/bs</code>. I run these tools all at once in a script named <code>compile</code>:</p>
          
          <div class="highlight"><pre><span class="c">#!/bin/bash</span>&#x000A;    ~/Development/Briefs-util/BS/bs photos.bs &gt; photos-source.brieflist <span class="o">&amp;&amp;</span> <span class="se">\</span>&#x000A;        ~/bin/compact-briefs photos-source.brieflist ~/Development/Briefs/sample/photos.brieflist&#x000A;    </pre>
          </div>
          
          
          <h2>Installing the Brief</h2>
          
          <p>The next step is to build the Briefs application with our newly-compiled Brief. Switch back to the Briefs Xcode project and choose the "Briefs" application target. If you haven't yet added the new brief to the Xcode project, right-click on the "My Briefs" and choose Add > Existing Files. Select the <code>photos.brieflist</code> file in the <code>samples</code> directory and in the following dialog make sure the checkbox at the top is unselected.</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-2.08.27-PM.png" alt="Screen shot 2010-01-10 at 2.08.27 PM.png" /></p>
          
          <p>Now you can build the Briefs application for either the simulator or the device. If you're building for the device, make sure you have a proper provisioning profile in place that matches the bundle identifier of the project. Now we can Build &amp; Run the project, and our <code>photos.brieflist</code> should appear in the list:</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-8.54.47-AM.png" alt="Screen shot 2010-01-10 at 8.54.47 AM.png" /></p>
          
          <p>Select our new Brief and play with the application. To exit a Brief, touch and hold your finger down until a new screen appears asking you if you want to exit the current Brief.</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-11.54.51-AM.png" alt="Screen shot 2010-01-10 at 11.54.51 AM.png" /></p>
          
          <h2>Distributing the Brief</h2>
          
          <p>The idea behind these prototypes is putting a tangible example in front of users to get their feedback. So what do you do if you want to distribute Briefs to a wider audience? Ad-hoc builds are a pain and require access to the physical device. Fortunately, Briefs provides a tool called "Briefcasts", which is simply one or more Briefs embedded in an RSS feed. The Briefs application can retrieve Briefcasts via HTTP, so distributing Briefs is a snap if you have a web server to serve new Briefcasts from. This means you can install the Briefs application once on a device and provide updates anytime without having direct access to the hardware.</p>
          
          <p>Currently, there isn't a tool to easily create a Briefcast directly out of a list of Briefs. For now, the project web site recommends copying and modifying the RSS template below:</p>
          
          <div class="highlight"><pre><span class="cp">&lt;?xml version=&quot;1.0&quot;?&gt;</span>&#x000A;    <span class="nt">&lt;rss</span> <span class="na">version=</span><span class="s">&quot;2.0&quot;</span><span class="nt">&gt;</span>&#x000A;      <span class="nt">&lt;channel&gt;</span>&#x000A;        <span class="nt">&lt;title&gt;</span>*Briefcast Demo*<span class="nt">&lt;/title&gt;</span>&#x000A;        <span class="nt">&lt;link&gt;</span>*http://island.local/~alex/briefcasts/*<span class="nt">&lt;/link&gt;</span>&#x000A;        <span class="nt">&lt;description&gt;</span>*Demonstrate how awesome it is to use a briefcast to get briefs on the iPhone.*<span class="nt">&lt;/description&gt;</span>&#x000A;        <span class="nt">&lt;language&gt;</span>en-us<span class="nt">&lt;/language&gt;</span>&#x000A;        *Thu, 12 Nov 2009 03:05:00 GMT*<span class="nt">&lt;/pubDate&gt;</span>&#x000A;        <span class="nt">&lt;lastBuildDate&gt;</span>*Thu, 12 Nov 2009 03:05:00 GMT*<span class="nt">&lt;/lastBuildDate&gt;</span>&#x000A;        <span class="nt">&lt;item&gt;</span>&#x000A;          <span class="nt">&lt;title&gt;</span>*Photos.app Sketch*<span class="nt">&lt;/title&gt;</span>&#x000A;          <span class="nt">&lt;enclosure</span> <span class="na">url=</span><span class="s">&quot;*http://island.local/~alex/briefcasts/photos.brieflist*&quot;</span> <span class="na">length=</span><span class="s">&quot;*954708*&quot;</span> <span class="na">type=</span><span class="s">&quot;application/brief&quot;</span> <span class="nt">/&gt;</span>&#x000A;          <span class="nt">&lt;description&gt;</span>*An example brief of the built-in Photos.app.*<span class="nt">&lt;/description&gt;</span>&#x000A;          *Sun, 13 Sep 2009 03:05:00 GMT*<span class="nt">&lt;/pubDate&gt;</span>&#x000A;          <span class="nt">&lt;guid&gt;</span>*http://island.local/~alex/cast/1#item1*<span class="nt">&lt;/guid&gt;</span>&#x000A;        <span class="nt">&lt;/item&gt;</span>&#x000A;      <span class="nt">&lt;/channel&gt;</span>&#x000A;    <span class="nt">&lt;/rss&gt;</span>&#x000A;    </pre>
          </div>
          
          
          <p>The bits marked <em>in bold</em> need to replaced with your particular details. In the example above I only have one Brief, but if you had more than one, you would just include additional <code><item></code> elements. You need to have this RSS file on disk as well as the brieflist file referred to in the <code><enclosure></code> tag.</p>
          
          <p>Assuming that you have your web server all setup with the RSS file as well as the Briefs files, you can launch the application and add the Briefcast by selecting the "+" button in the top-right of the home screen. Enter the details on the next dialog and touch the "Save" button:</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.20.37-AM.png" alt="Screen shot 2010-01-10 at 9.20.37 AM.png" /></p>
          
          <p>On the next screen you'll see the details of the Briefcast. Each Brief in the Briefcast will be listed under the section titled "Enclosed Briefs". Touch the "Download this Brief" button to retrieve the associated brief.</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.20.49-AM.png" alt="Screen shot 2010-01-10 at 9.20.49 AM.png" /></p>
          
          <p>Once the brief is downloaded, you end up on a rather unhelpful confirmation screen:</p>
          
          <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.16.27-AM.png" alt="Screen shot 2010-01-10 at 9.16.27 AM.png" /></p>
          
          <p>You have to touch the screen, then navigate back to the top. Then you'll find the new Brief in your list of briefs. To update the Brief, you navigate back into the Briefcast section from the home page and download the correct Brief again.</p>
          
          <p>One nice enhancement I'd love to see is a custom application URL for Briefs so that you could just email the link to someone. They could read the email from their device, select the URL and Briefs would launch and download the newest Briefs.</p>
          
          <h1>Conclusion</h1>
          
          <p>Briefs is a great tool for building live prototypes. Since it's a relatively young project, it still has a lot of rough edges, but I expect it to mature over time.</p>
          
          <p>Don't hesitate to dive into the code behind Briefs. There are occasions when Briefs (the application or the command-line tool) will crash without much detail. I found that this is usually the result of bad syntax in the Briefs so a little sleuthing may be required to get things working.</p>
          
          <h1>Resources</h1>
          
          <p>Here's a list of related resources:</p>
          
          <ul>
          <li><a href="http://giveabrief.com/">Briefs Homepage</a></li>
          <li><a href="http://github.com/capttaco/Briefs">Briefs on GitHub</a></li>
          <li><a href="https://alexvollmer-public.s3.amazonaws.com/photos_app.tgz">Sample Brief of Photos.app</a></li>
          <li><a href="https://alexvollmer-public.s3.amazonaws.com/Briefs%20Cheatsheet.pdf">Briefs Syntax Cheatsheet</a></li>
          <li><a href="http://graffletopia.com/categories/iphone">iPhone Templates for OmniGraffle</a></li>
          <li><a href="http://www.teehanlax.com/blog/2009/06/18/iphone-gui-psd-30/">iPhone PSD for PhotoShop</a></li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Tools of 2009
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/07/tools-of-2009/' />
    <updated>
      2010-01-07T04:35:42PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2010/01/07/tools-of-2009/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I suppose if I were really on the ball I would have posted this right after New Year's Day, but I needed to ruminate a bit on what was worth summarizing for 2009. In the end I decided to talk about the tools I found in 2009 that really made a difference in my life.</p>
          
          <h2>LaunchBar</h2>
          
          <p>When I first switched to the Mac, I discovered Quicksilver and it was like discovering something essential that you didn't know you needed. QS was a revelation to me because it drastically reduced the mental distance between the what I wanted to accomplish and executing it.</p>
          
          <p>Over time though, I found some things in QS that just didn't work consistently. It would crash and some of configuration was pretty clumsy. It became pretty clear that there was little, if any, forward progress being made on it. So, on the advice of several local Ruby/Mac nerds, I tried out <a href="http://www.obdev.at/products/launchbar">LaunchBar</a>. At first I was disappointed that it didn't have the breadth of QS, but after investing a little time and effort I found that it handled 99% of the things I wanted. More importantly, there was somebody actually working on it which meant it was going to evolve and improve.</p>
          
          <p>Now I can hardly use a machine that doesn't have it installed. I can't believe people use the dock to launch apps. Yuck.</p>
          
          <h2>Mailplane</h2>
          
          <p>By and large, I'm biased to using the built-in Apple-given tools where possible. Apple usually gets it right and most other tools are designed to work with these apps. I've used Mail.app since I switched to the Mac, but always felt the interface to be inferior to GMail's tag-oriented structure. But since I had some non-GMail accounts, <em>and</em> I wanted to have a single app, I stuck with Mail.app.</p>
          
          <p>However, once I dropped my last IMAP-only account I was ready to switch back. The only parts I really missed were the tight integration with the desktop that Mail.app brought. Lo and behold, along comes <a href="http://mailplaneapp.com">Mailplane</a> to fill the gap. It is, essentially, a WebKit view of GMail with some extra bits to glue the web application to your desktop. I think it's brilliant and was happy to part with some hard-earned money for the privilege to use it.</p>
          
          <h2>zsh completion</h2>
          
          <p>My introduction to zsh came many years ago from a co-worker who boot-strapped my entr&eacute;e into zsh-land with his configuration files. For the longest time I treated them like mystic, sacred tablets to be worshipped, but never to be understood. But over time I found little gaps I wanted to fill in with my zsh setup, especially with command auto-completion.</p>
          
          <p>I'm a keyboard kind of guy. I like the command prompt. I also like going fast, so anything that makes me faster in the command prompt is like gold to me. I love shell auto-completion and found lots of things I wanted completion for, like <a href="http://gist.github.com/164465">RubyGems</a>. So this year I finally pounded through enough documentation and samples to put together a few home-grown completion bits. I still don't understand most of the incantations that make it go (guilty as charged of cargo-culting) but it has made my command-line work-flow that much better.</p>
          
          <h2>Dropbox</h2>
          
          <p>Since switching to the Mac, I've always had at least two machines that I needed to share files between. For the longest time I used to store files in S3 then sync them back and forth. This worked, but it sucked because I had to do it manually and I had to get the order right so I didn't clobber any files.</p>
          
          <p>When <a href="http://www.dropbox.com">Dropbox</a> came along, the clouds parted and the golden light of heaven shown down from above. Dropbox makes sharing files super-duper, idiotically simple. Combined with tools like <a href="http://agilewebsolutions.com/products/1Password">1Password</a>, having consistent data across multiple machines is like magic on a daily basis&mdash;it just works and I don't even have to think about it.</p>
          
          <h2>One Bus Away</h2>
          
          <p>The thing I love about the iPhone is how it's an Swiss Army Knife for information in the modern age. You can find apps that do very specific things, very well and put them in a single box that you keep in your pocket. The <a href="http://www.onebusaway.org">One Bus Away</a> app is one of my favorite iPhone tools.</p>
          
          <p>I ride the bus a lot and to have real-time transit data in the palm of my hand is fantastic. No guessing about when the next bus is coming. No extra waiting. I know just when to leave to catch my next ride.</p>
          
          <h2>Mint.com</h2>
          
          <p>I was a long-time Quicken user but finally had it last January. It's a bloated app with serious usability issues. I finally reached a point where using Quicken had a net-negative impact on my life. It simply drove me crazy to use it.</p>
          
          <p>Enter <a href="http://mint.com">mint.com</a>. At first I was very hesitant to give my information to these guys. But eventually I was convinced to try it because:
          *  if I use Quicken another minute I'll go postal
          *  sometimes the future doesn't start until you acknowledge it, and this looks like the future to me
          *  I'm probably already more open to financial security risk anyway, so what the hell?</p>
          
          <p>I get exactly what I want out of mint: a high-level dashboard that just updates itself. I use a few of the budgeting features which are nice, but really it's all about automated data acquisition and display. Oh yeah, did I mention that they have an iPhone app too?</p>
          
          <h2>Instapaper</h2>
          
          <p>Several years ago I built my own news-feed reader and one of the features I really wanted to implement was a temporary "holding pen" where I could put URLs to visit later. These were things that didn't quite warrant a Delicious bookmark, but I wanted to get back to.</p>
          
          <p>By itself, <a href="http://instapaper.com">Instapaper</a> satisfied my original need and worked great as a bookmarklet in my browser. However it went from a convenient curiosity to an essential tool once other apps started integrating with it (e.g. Net News Wire, Tweetie 2) <em>and</em> Kindle integration (see below).</p>
          
          <p>Oh yeah, did I mention that there's an iPhone app for that too?</p>
          
          <h2>Kindle (device and app)</h2>
          
          <p>The final tool of 2009 that made itself indispensable was the Kindle. It's a great example of "good enough". The Kindle is fraught with polish and usability issues, but they don't overwhelm the utility of the device.</p>
          
          <p>I've been on a long dispense-with-all-physical-media kick, with books being my primary target. I have lots of books, but I don't have lots of space. Since I'm not emotionally wedded to the form-factor of paper books, the Kindle solves my reading-appetite vs. space problem quite well. I can stuff that thing full of books and not take up an inch of extra space in my house.</p>
          
          <p>Like so many of the other tools I've listed, it's the other things that integrate with the Kindle that multiply its utility. First, the Kindle has gained a lot of adoption by other publishers. The <a href="http://pragprog.com">Prags</a> and <a href="http://oreilly.com">O'Reilly</a>, in particular, have been eager to jump into the e-book biz with first-class Kindle support. I probably go through about fifteen to twenty tech books a year and having them on the Kindle is great.</p>
          
          <p>Another great bit of integration is how Instapaper delivers me a weekly digest of links I've captured right to my Kindle. I can read the full content of every page I bookmarked right there on my Kindle without the need for a network connection. This is a great for travel.</p>
          
          <h2>So?</h2>
          
          <p>Looking over this list, if there's one theme that emerges, it's all about ubiquity and convergence. (Did I really just say that?) Despite all of the queasy feelings those "market-tecture" terms give me, I don't quite know how else to define it. For me, 2009 was the year that I could get to my stuff whenever I liked, however I liked, through a multitude of channels.</p>
          
          <p>I wonder what the theme of 2010 will be?</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          All-Time Lineup
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/12/15/all-time-lineup/' />
    <updated>
      2009-12-15T06:14:09PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/12/15/all-time-lineup/
    </id>
    <content type='html'>
      <![CDATA[
          <p>A little while ago, I was encouraged to put together my "All-Time" baseball lineup. Now, personally I think the game is more difficult to compete in now than ever before. While the old-timers love to gripe about players in the Steroid Era, I don't think those guys had to play with such a uniformly strong level of competition under such high pressure. But that's just my gut feeling. I don't really have the evidence to back that up. I also think that baseball fans have a tendency to romanticize the players of baseball's so-called "Golden Era", making any rational debate even tougher.</p>
          
          <p>With the exception of Gehrig, I've purposely ignored anyone before the 50's. In my opinion, the game is just too different. I don't feel like I can trot Cy Young out as my starting pitcher just because of 511 wins. Those wins don't compare at all to wins in the 60's, 70's, 80's or 90's.</p>
          
          <p>I'm also not penalizing anyone for being part of the Steroid Era or for even having used PEDs. There are, no doubt, some effects of these substances on the game, but I don't see the evidence being as conclusive as some would have you believe. Did Barry Bonds cheat? Yeah, I'm pretty sure he did. He was a helluva ball-player before he started and he still would have put together a Hall of Fame career without them. Steroids (a rather inaccurate term for PEDs) don't make you see the ball any better or improve your hand/eye coordination. At best they allow athletes to recover faster from working out. They don't build muscle, they amplify the body's own healing process in order to work out more. You can call steroid users cheaters, but I wouldn't call them lazy.</p>
          
          <p>So this is my list. If you have a different one, I'd love to hear about it. So, without further ado, here's my list.</p>
          
          <h3>Catcher: Roy Campanella</h3>
          
          <p>Great all-around athlete, hit the crap out of the ball, threw runners out and worked well with pitchers. He was probably one of the most complete catchers to play in the majors.</p>
          
          <h3>First Base: Lou Gehrig</h3>
          
          <p>OK, I cheated a little bit here and dipped back in time further than I said I would go. But c'mon&mdash;it's <em>Lou Gehrig</em>.</p>
          
          <h3>Second Base: Jackie Robinson</h3>
          
          <p>They retired the number 42 for lots of reasons&mdash;those are the same reasons he's my starting second baseman.</p>
          
          <h3>Third Base: George Brett</h3>
          
          <p>Brett is the last guy to come close to hitting .400. He ended the 1980 season with a .390 average. What's even more impressive is that he had more <em>home runs</em> than <em>strikeouts</em> that year. He's got the longevity, the ring and the career to put him on my list.</p>
          
          <h3>Shortstop: Alex Rodriguez</h3>
          
          <p>Does A-Rod's admission to using PEDs damage is Hall of Fame credentials? Maybe, but as I contended earlier, I'm not convinced that they can carry a player to greatness. We love to dump on A-Rod's failures, but it's really only because he's been spectacularly successful in his career. Drugs or not, he's my starting shortstop. This, coming from a jilted M's fan too!</p>
          
          <h3>Left Field: Ted Williams</h3>
          
          <p>The Splendid Splinter. The greatest hitter of all time. Period.</p>
          
          <h3>Center Field: Willie Mays</h3>
          
          <p>Hard to find a better combination of offensive and defensive skills.</p>
          
          <h3>Right Field: Hank Aaron</h3>
          
          <p>How could I possibly leave Hank Aaron off the list?</p>
          
          <h3>Designated Hitter: Edgar Martinez</h3>
          
          <p>Edgar Martinez presents a serious conundrum to Hall of Fame voters. He's really the first "pure" designated hitter that voters will have to face. His career are numbers are impressive for the time he played, but he doesn't have some of the magic totals people like to see. That said, he's my vote for DH. Plus, I named my dog after him.</p>
          
          <h3>Starting Pitcher: Sandy Koufax</h3>
          
          <p>There's probably no roster spot that would engender more differences of opinion than starting pitcher. There are so many great ones to choose from. Koufax didn't have the career longevity like Satchel Paige or Tom Seaver, but at the height of his powers he was simply jaw-dropping amazing. His years from 1963 through 1966 are some of the <em>sickest</em> consecutive years a pitcher ever put together.</p>
          
          <h3>Relief Pitcher: Mariano Rivera</h3>
          
          <p>While there may be controversy over starters, the choice for reliever is pretty straight-forward. Seriously, is there any disagreement here?</p>
          
          <h3>Manager: Earl Weaver</h3>
          
          <p>He managed Hall of Fame players, he won a couple of rings, he wrote the seminal book on baseball strategy and he had a video game named after him. Yup, that fits my criteria.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Building a Knowledge Base
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/' />
    <updated>
      2009-12-11T16:39:09PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Many years ago, I had the fortune of working for a family friend who was a financial planner. Not only did I get to learn a lot about personal finances at an early age, but I also picked up some great professional habits too. One of the things she did was maintain a gigantic set of folders of things she found interesting or useful. She had a four-drawer filing cabinet filled with various tidbits of information she had collected. She had a pretty good index in her head of where these things were and was amazingly proficient in recalling where she had filed things.</p>
          
          <p>I always wanted a personal knowledge base like this, but I couldn't do it the way she had. First, I have never had the space to collect that much paper. I cannot have, and do not want, a giant filing cabinet of folders. Second, I don't have the kind of recall she did to find that stuff. I could certainly remember that I once filed something, but wouldn't have a clue <em>where</em> I filed it. Which brings me to the third issue, which is suffering with the restriction of filing information under a single hierarchy.</p>
          
          <p>When I first started using GMail I had a major epiphany about the differences between organizing information in folders versus tagging. These days that seems about as earth-shattering as realizing our galaxy is helio-centric, but it seemed like a pretty radical idea at the time. I flat-out love this style of organization. I may not remember <em>where</em> I filed something, but I'm pretty consistent when it comes to labeling things. With systems like GMail and Delicious, I just slap as many tags as I think are reasonable for a message or bookmark and I have a really good chance of finding it again when I need to.</p>
          
          <p>But email and bookmarks aren't a knowledge base. For me, they are a reference, but usually aren't in a succinct enough format to be a good reference. I want to boil down newly-acquired knowledge into some quick, efficient prose. What I needed was a system that:
          *  Works across multiple machines (e.g. work and personal)
          *  Is fast to add and edit content
          *  Is (relatively) searchable
          *  Has some structure
          *  &hellip;but not so much that I fight with it</p>
          
          <p>So over the last few years I've started building a personal knowledge-base in earnest. It's not overly complicated or too involved. I simply keep a set of text files (specifically, files compatible with <a href="http://orgmode.org/">org-mode</a>) in a special <a href="https://www.dropbox.com/">Dropbox</a> folder. Dropbox makes synchronizing stupid-easy. I just treat these files just like local files and they appear on both my work and personal machines.</p>
          
          <p>For a while I used <a href="http://flyingmeat.com/voodoopad/">VoodooPad</a>, which is a very cool program. But I like having a <em>little</em> structure in my notes and imparting that structure in VoodooPad took more effort than I wanted. Later, I discovered Emacs' org-mode, which turned out to be a perfect fit for me&mdash;it's a relatively lightweight structure on top of simple text-files. The only thing org-mode doesn't do well is handling non-text media. I've considered moving to something like OmniOutliner, but I've found that org-mode works surprisingly well.</p>
          
          <p>The technology isn't particularly interesting, nor is it what makes this work for me. Rather, it's the <em>discipline</em> of writing down little notes on various topics of interest. For example, I can never remember how to enable zombies for Cocoa debugging. I looked it up once, then added a section to my <code>xcode.org</code> file on <code>NSZombieEnabled</code>. I get two benefits out of this: first I've got it somewhere handy that I can easily look up again (via spotlight, <code>grep/ack</code>, whatever). Secondly, the very act of formulating a paragraph or two on the concept somehow reinforces it into my brain. In fact, it's very likely that I won't ever have to look up how to track zombies again.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Cleaning out the Closet
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/' />
    <updated>
      2009-11-07T22:12:45PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I've had a couple of nascent Ruby gems lurking in my Github account for what seems like ages. So, on a rainy Saturday afternoon, I did a little cleanup and pushed a couple of new gems out to <a href="http://gemcutter.org">Gemcutter</a>.</p>
          
          <p>The first, is a gem I started over a year ago, called <a href="http://gemcutter.org/gems/word-salad" target="_new"><code>word-salad</code></a>. It uses the built-in dictionary file to randomly pull words out. This is great when you just need to generate a bunch of English-like text, but don't want to fall back on the boring old "lorem ipsum&hellip;" routine.</p>
          
          <div class="highlight"><pre><span class="mi">3</span><span class="o">.</span><span class="n">words</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s1">&#39;draw&#39;</span><span class="p">,</span> <span class="s1">&#39;ameliorate&#39;</span><span class="p">,</span> <span class="s1">&#39;bonanza&#39;</span><span class="o">]</span>&#x000A;    <span class="mi">2</span><span class="o">.</span><span class="n">sentences</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s1">&#39;Shoot jonesing the make castle.&#39;</span><span class="p">,</span> <span class="s1">&#39;Blue murdered slight bastion.&#39;</span><span class="o">]</span>&#x000A;    <span class="mi">2</span><span class="o">.</span><span class="n">paragraphs</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s2">&quot;Brachypterous gastropod pheretrer overeager toploftily denaturalization stokesite demented benzalhydrazine archaeologic. Haverer hypophonous lenticularly brickliner urocele paucipinnate pik unprintably perhalogen. Subglenoid bearish gesticulative staircase gallop vesuvianite pneumatically overyear conterminous dreamish. Nonalliterated galliwasp superconfirmation Comandra entoil millionth parcellize rarefaction Cynoidea. Podolian metamorphosable nativeness integriously protonematoid undoctor stochastically dissatisfactory unchastity.&quot;</span><span class="p">,</span> <span class="s2">&quot;Increate unloquacious unsatisfiedly flareboard internuncio beguine equivocation snowshoe Rhynchonellacea. Parochially curliewurly vermix consistorial cond consciencelessness Anaxagorize recoct sempiternally Campanulatae. Scorpionida Castalides homoanisic semipenniform Novemberish assessor preterlethal acrotarsial knoller hartin. Procrastination boatwise canonize differentiate faunlike countermarriage obstinance dilatableness drumloid. Gerate squirr Silvanus Physostigma booting thyroarytenoid diminutival legpuller medisance radiobserver.&quot;</span><span class="o">]</span>&#x000A;    </pre>
          </div>
          
          
          <p>The second is a gem for automatically retrieving and locally storing sales reports from the iTunes Connect site. If you have an iPhone app in the App Store, you already know how much (anti-)fun it is to get reports from Apple's site. So I put the <a href="http://gemcutter.org/gems/itunes-connect" target="_new"><code>itunes-connect</code></a> gem together to help out. It's pretty basic for now, but will probably grow more capabilities as time goes on.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The Cleverest Git Maneuver I Ever Pulled Off
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/' />
    <updated>
      2009-10-09T15:44:04PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/
    </id>
    <content type='html'>
      <![CDATA[
          <p>So there I was, reviewing a series of commits, sucking air between my teeth and cringing when I came upon one of those lazy commits that has way too much stuff in it to reasonably digest. I needed a way to go back and split that commit into two or three separate commits. This is pretty easy to do with <code>git rebase</code>. You can just do a mixed reset of the last commit, stage the bits you want in one commit, stage the next bits and put that in a separate commit.</p>
          
          <p>This all works great&mdash;until it doesn't. The ability to stage parts of a file is one of my favorite features of <code>git</code>, but there are times when you have changes that <code>git</code> won't let you split apart. Usually I give up at this point and just abort the rebase.</p>
          
          <p>But yesterday I must have had too much coffee because I was <em>determined</em> to figure out how to do this. The changes that I wanted to split out were pretty easy to find. It was easy to remove them by hand and commit those. But I didn't want to have to manually add them <em>back</em>&mdash;that was too mistake-prone. What I needed was a way to invert the commit that removed those lines. What I needed was <code>git revert</code>. If I could revert my subtractions (in effect, <em>adding</em> the changes back), then I could squash the commits and rewrite history.</p>
          
          <p>So here's what I did:</p>
          
          <ol>
          <li>Started an interactive rebase session (<code>git rebase -i</code>)</li>
          <li>Marked the commit I wanted to split as an "edit"</li>
          <li>Manually removed the code I didn't want in the first commit, staged the changes and made a new commit</li>
          <li>Revert the subtraction with <code>git revert HEAD</code></li>
          <li>Complete that rebase with <code>git rebase --continue</code></li>
          <li>Start a new rebase and squash the original commit with the manual changes one</li>
          </ol>
          
          
          <p>Note that I didn't use <code>git reset</code> after step 2. It wouldn't have helped me because interactive staging wasn't working for me. I also marked all the commits in the second rebase as "edits", so I could fix the commit messages.</p>
          
          <p>Put another way, the commits transformed like this, from left to right:</p>
          
          <p><img src="/images/2009/10/git-revert.png" alt="git revert.png" /></p>
          
          <p>Maybe I'm overly fussy about clean commits. I'll admit that at times that my attention to cleanliness borders on the obsessive, but having the ability to go back and clean things up is one of my favorite things about <code>git</code>. Maybe I'm just not smart enough, but I usually don't know nearly as much at the beginning of a commit as I do at the end. With <code>git</code>, I can make it look like I do.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 1.0.2 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/' />
    <updated>
      2009-10-03T16:03:14PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why
          should you have to create a Hash, then create a parser, fill the Hash
          out then throw the parser away (unless you want to print out a usage
          message) and deal with a Hash? Why, for Pete's sake, should the parser
          and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>1.0.2 / 2009-10-02</h3>
          
          <ul>
          <li><p>Merged patches from Adam Salter:</p>
          
          <ul>
          <li>Added new "presence" method for options.</li>
          <li>Updated rspec usage to match the latest &amp; greatest syntax</li>
          <li>Make descriptions optional for flags and options</li>
          </ul>
          </li>
          <li><p><a href="http://clip.rubyforge.org">http://clip.rubyforge.org</a></p></li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The End of an Era
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/' />
    <updated>
      2009-10-02T21:55:55PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Well, this is it kids; the end of my time at <a href="http://evri.com">Evri</a>. While I have cultivated a long-standing antipathy towards the Grateful Dead, I'll co-opt one of their song titles and simply mutter, "what a long strange trip it's been". I started out at Evri when it was still just a twinkle in somebody's eye. Since then I've seen it grow and mutate in ways I would have never imagined. I got to work on a lot of cool stuff and learn a bunch of new things. The best part, like any good job, was having the opportunity to work with some really great people.</p>
          
          <p>But now it's time for a change. My professional clock is set to about three years&mdash;when that bell rings it's time for me to move on. This was as true at Evri as it has been anywhere else, with one major difference: I made a career-change along the way.</p>
          
          <p>OK, I haven't given up software to become a sous-chef or to take troubled kids out into the woods to teach them discipline. But I think I have reached the end of my professional Java programming career. This is kind of a "Big Deal", because I've been doing it for a <em>decade</em>. I know, I know: never say never. It's entirely possible that I'll eat my words a year or two down the road, but for now, I can't help but feel like I'm closing a major chapter in my professional life.</p>
          
          <p>I've been with that language for a long time. Lately I've made a sport of complaining about it a lot, but honestly that's simply contempt bred from familiarity. There is a lot of good about the language and, despite my railings, the baby needn't be thrown out with the bath-water. What it comes down to is that I simply don't <em>enjoy</em> it anymore. It used to be fun to put those pieces together, but not any longer. So I'm trading in my Java hat for my two new loves: Ruby and Objective-C.</p>
          
          <p><img src="/images/2009/10/IMG_1047-150x150.JPG" class="left"/></p>
          
          <p>I may be stupid, but I'm not foolish enough to think that these languages will be the only remaining languages of my career. First of all, I'm not in the habit of defining my identity from the particular technologies I work with. Secondly, these are simply the environments I'm in love with now. I'm a dedicated family-man when it comes to people, but when it comes to programming languages, tools and environments I'm as bad as Liz Taylor. But jeez, why not embrace change? I don't do this for the paycheck. I do it because I love it. Why spend my time on things that aren't making me happy anymore?</p>
          
          <p>With that question burning a hole in my brain, it became clear that, for now, the twisting road that is my professional career is going to take a long detour through Ruby and Objective-C. I hope it gets some time with Erlang too&mdash;I've only dabbled with it a little bit, but found myself quite attracted right away.</p>
          
          <p>As I realized that my time was at an end at Evri, the question of "what next?" loomed large. Was there someone out there that wanted someone with the skills I wanted to cultivate? If so, were they doing something cool? Was I going to go "indie"? What would that look like? Questions, questions, questions. Fortunately I stumbled across a gig that is going to let me scratch most, if not all, of those itches.</p>
          
          <p>I'm taking October off to continue and complete the series of <a href="http://peepcode.com/products/iphone-view-controllers-part-i">iPhone</a> <a href="http://peepcode.com/products/iphone-view-controllers-part-ii">screencasts</a> I've been writing for <a href="http://peepcode.com">PeepCode</a>. In November I'll pick up my full-time gig and kick off the next phase of my professional life. You can't imagine how humbled and fortunate I feel to be able to do this.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          iPhone Screencasts
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/' />
    <updated>
      2009-09-15T04:13:03PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/
    </id>
    <content type='html'>
      <![CDATA[
          <p><a href="https://peepcode.com/products/iphone-view-controllers-part-i" target="_new"><img src="http://peepcode.com/system/uploads/2009/iphone-cover.png">
          </a></p>
          
          <p>I'm pleased to announce the release of the first in a series of <a href="http://peepcode.com">PeepCode screencasts for the iPhone SDK</a> I've been co-writing with Geoffrey Grosenbach. The first one (done in two parts) covers View Controller basics. We decided to start with View Controllers because they are at the core of all "productivity"-style applications. Once you have them down, you can start to put some meat on the bones of your iPhone apps.</p>
          
          <p>Once we've covered those, we'll work our way through the entire MVC Holy Trinity, one bit at a time. Along the way we hope to deep-dive on a few ancillary topics like Core Location, Game Kit as well as provisioning and unit-testing. We also hope to look at visual technologies like Core Graphics and Core Animation, as well model-related APIs like Core Data and web service-related libraries.</p>
          
          <p>The iPhone SDK is huge and there's a ton of material out there to cover. We're very excited to kick off what we hope will be a useful and successful instructional series for perspective iPhone developers out there. Let us know what you want to see.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          EvriVerse 2.0
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/' />
    <updated>
      2009-08-19T16:27:18PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="/images/2009/08/photo-5.jpg" class="left"/></p>
          
          <p>I just wanted to make a quick announcement that the <a href="http://evriverse.evri.com">iPhone app</a> I've been building at <a href="http://evri.com">work</a> just released a major update today. It's in the App Store and it's free. Check it out.</p>
          
          <p>Working on this release was a <em>ton</em> of fun. We cleaned up a good bit of the mess from the earlier version and  added some cool new features. What was even more fun was <em>removing</em> functionality that either didn't work well or wasn't obvious to the user. My god, there is <em>nothing</em> I love as much as deleting code. I don't know why I don't look for more opportunities to do this. Not only is it personally and emotionally liberating, it's often the "right" thing to do.</p>
          
          <p>The features we pulled out really had no business being in there in the first place. Of course, we didn't know that until we released the first version, got feedback from folks and spent some time outside of the development process. Y'know, hindsight, 20/20, blah blah blah.</p>
          
          <p>I think it is exceedingly difficult to get perspective on your work while you're creating it. There's just too much personal investment in the activity, especially if you get any sort of "flow" going. Creative types <em>love</em> "flow" and hate giving it up for any reason, even if the work suffers as a result. I think that's fine, but that's why there's a separate process known as "editing". The trick, of course, is to balance satisfying your possibly-self-indulgent creative urges with creating something of value.</p>
          
          <p>Anyway, that's enough of my philosophical rambling. We also put together a little brochure site at <a href="http://evriverse.evri.com">http://evriverse.evri.com</a>, including a screencast with music composed by yours truly. That process was a whitepaper-grade case study in "stuff you can do with iLife". I grabbed all the footage using <a href="http://store.shinywhitebox.com/home/home.html">iShow U</a>, did all the music in Garage Band (on the bus using the computer keyboard no less) and glued it all together in iMovie. Super simple, super fun.</p>
          
          <p>All in all I'm pretty pleased with the result. It's free, so check it out and let me (or <a href="http://evri.com">Evri</a>) know what you think.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Cocoa's Ways of Talking
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/' />
    <updated>
      2009-06-25T01:53:32PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Getting objects to talk to one another in Objective-C is a easy as passing a message from one to the other. These messages are typically passed through the message-invocation mechanism of using the square-braces to bind a message and arguments to a receiver. Most of the time this is a perfectly reasonable way to communicate. However there are times when you need objects to communicate <em>without having explicit knowledge of one another.</em></p>
          
          <p>In this post we'll look at three ways to allow your objects to communicate with each other in a highly-decoupled manner using the Cocoa frameworks. Cocoa provides three common ways of connecting objects for messaging: Notifications, Key-Value Observation and delegate pattern.</p>
          
          <h3>Notifications</h3>
          
          <p>Both Cocoa and Cocoa Touch provide a notifications framework built on two classes: <code>NSNotificationCenter</code> and <code>NSNotification</code>. The former contains a singleton instance, (via the <code>defaultCenter</code> method) with which observers register themselves and observables post notifications. The latter is the "envelope" for the notification which can contain an <code>NSDictionary</code> instance of customized data as its payload.</p>
          
          <p><img src="/images/2009/06/nsnotificationcenter.png" alt="NSNotificationCenter.png" /></p>
          
          <p>When an object registers for notifications, it specifies a notification to listen for (as a <code>NSString</code>) and, optionally, a target object. If the target is set to an object, only notifications posted by that object will be received. If the target object is set to <code>nil</code>, <em>any</em> object posting that notification will be sent to the receiver. Senders can optionally include a <code>NSDictionary</code> instance filled with domain-specific objects. You can use this as a way to further parameterize a notification, or eschew it altogether.</p>
          
          <p>Consider the example below:</p>
          
          <div class="highlight"><pre><span class="k">@implementation</span> <span class="nc">Foo</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">init</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">=</span> <span class="p">[</span><span class="n">super</span> <span class="n">init</span><span class="p">])</span> <span class="p">{</span>&#x000A;        <span class="p">[[</span><span class="n">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="p">]</span> <span class="nl">addObserver:</span><span class="n">self</span>&#x000A;                                                 <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">didReceiveNote:</span><span class="p">)</span>&#x000A;                                                     <span class="nl">name:</span><span class="s">@&quot;TheBigNotification&quot;</span>&#x000A;                                                   <span class="nl">object:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">return</span> <span class="n">self</span><span class="p">;</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">didReceiveNote:</span><span class="p">(</span><span class="n">NSNotification</span> <span class="o">*</span><span class="p">)</span><span class="n">notification</span> <span class="p">{</span>&#x000A;      <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Hey, I got a notification with user info: %@&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">notification</span> <span class="n">userInfo</span><span class="p">]);</span>&#x000A;    <span class="p">}</span>&#x000A;    <span class="k">@end</span>&#x000A;    &#x000A;    <span class="err">@</span><span class="n">implementation</span> <span class="n">Bar</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">doSomething</span> <span class="p">{</span>&#x000A;      <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;I&#39;m up to something!&quot;</span><span class="p">);</span>&#x000A;      <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">stuff</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="s">@&quot;foo&quot;</span><span class="p">,</span> <span class="s">@&quot;bar&quot;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span>&#x000A;      <span class="p">[[</span><span class="n">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="p">]</span> <span class="nl">postNotificationName:</span><span class="s">@&quot;TheBigNotification&quot;</span>&#x000A;                                                          <span class="nl">object:</span><span class="nb">nil</span>&#x000A;                                                        <span class="nl">userInfo:</span><span class="n">stuff</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    <span class="k">@end</span>&#x000A;    </pre>
          </div>
          
          
          <p>Here the <code>Foo</code> class registers itself as a notification receiver for the notification named "TheBigNotification" on <em>any</em> object. The <code>Bar</code> class will post the same notification when the <code>doSomething</code> method is invoked.</p>
          
          <p>We could have been much more specific about which object to observe, but I think this violates one of the key features of notifications which is that the sender and receiver are decoupled. To me if the receiver is going to go to the trouble of listening for notifications from a specific object, you'd be better off declaring a custom protocol and using the delegate pattern (explained below).</p>
          
          <p>While at the 2009 WWDC, I had a chance to pick the brains of some Apple engineers and one of them told me that notifications are really intended for one-to-many broadcasts. I think that's a great rule of thumb, because the code can really feel like overkill for single object-to-object messages. However, I'd add one more clause to that rule which is that notifications work for one-to-one messages when you would otherwise have to pass instances around of delegates just to connect objects.</p>
          
          <p>As an example, consider an iPhone application with a stack of view controllers in a <code>UINavigationController</code> instance. If you have a view controller several steps removed from another view controller (i.e. one is a further up the stack in a tab bar controller) and it needs to call some method back to the view controller lower down in the stack, each intermediate object would need a reference to the delegate class just to pass it down the line. This seems like the worst kind of encapsulation breakage since you're forcing a bunch of otherwise-unrelated classes to have knowledge of a class they don't even use.</p>
          
          <p>Maybe it's my long track-record with Java, but I pay attention to the classes I import and I like to keep that list as short as possible. The more classes know about each other, the more difficult it is to modify them.</p>
          
          <p>There's one final thing worth knowing about the <code>NSNotificationCenter</code>, and that is how it works with threads. When one object posts a notification, that call blocks while the notification is delivered to <em>all</em> targets. This means that you want your notification-handling code in the receiving object to be as quick as possible. If you can live with deferred notifications and want to avoid the synchronous nature of notification delivery, you can use the <code>NSNotificationQueue</code> instead.</p>
          
          <h3>Key-Value Observation</h3>
          
          <p>When I first read about, and used Key-Value Observation (KVO) it seemed like magic. You simply point one object at another and say "I'd like to know when this attribute changes" and Cocoa handles all of the notifications and threading automatically. Genius!</p>
          
          <p>KVO also allows you to use a special syntax when specifying the attributes you want to observe so that you can register with an object and traverse its object graph. Let's look at the classic customer/orders/line items example. If you want to know when changes are made to any line items in an order you would observe changes in the order like so:</p>
          
          <div class="highlight"><pre><span class="n">Order</span> <span class="o">*</span><span class="n">order</span> <span class="o">=</span> <span class="p">[</span><span class="n">self</span> <span class="n">anyOrder</span><span class="p">];</span>&#x000A;    <span class="p">[</span><span class="n">order</span> <span class="nl">addObserver:</span><span class="n">self</span>&#x000A;            <span class="nl">forKeyPath:</span><span class="s">@&quot;lineItems&quot;</span>&#x000A;               <span class="nl">options:</span><span class="n">NSKeyValueObservingOptionNew</span> <span class="o">|</span> <span class="n">NSKeyValueObservingOptionOld</span>&#x000A;               <span class="nl">context:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;    </pre>
          </div>
          
          
          <p>Whenever you register for KVO, you <em>must</em> implement the method <code>- observeValueForKeyPath:ofObject:change:context:</code>. Unlike notifications, you don't get to specify a selector. This means that if you're object is observing several other objects, you will have to inspect the object given in the callback method and dispatch appropriately.</p>
          
          <p>Key paths have a ton of flexibility including the ability to traverse deep object graphs and observe aggregate functions on a collection (e.g. observe the max date of all of a customer's orders). Check out the <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">Key-Value Programming Guide</a> for details, which is an indispensable reference.</p>
          
          <p>KVO works like notifications in that the thread that invokes the change will block until all observers have been notified and their callback methods have been invoked. Unlike notifications, there is no built-in asynchronous KVO-triggering mechanism unless you explicitly mutate properties in another thread using something like the <code>detachNewThreadSelector:toTarget:withObject:</code> class method of <code>NSThread</code>.</p>
          
          <p>For classes to be key-value <em>observable</em> they must be, what the documentation calls, "key-value compliant". This generally means that each observable property exposes certain methods for accessing and mutating them. Again, <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">the KVO guide</a> is your go-to reference.</p>
          
          <p>KVO is structurally similar to notifications, but is really intended for fine-grained messaging, generally around your model classes. Notifications are intended for broader application-level events. Both mechanisms give you a way to decouple classes that would otherwise need more intimate knowledge of one another.</p>
          
          <p>Consider the simple case of managing a tabular view of line items in an order. When a user adds a line item, removes a line item or updates the quantity of a line item we want a field showing the total price to be updated. Without KVO we would need to add extra logic in our event-handing for the table view to also update the total field. With KVO our event-handling logic can simply focus on updating the underlying model. The total field will simply observe the total cost of the order and be updated appropriately. Now if we want to remove the total field or perhaps add another view of total information, we don't have to touch the original event-handing code.</p>
          
          <h3>Delegates</h3>
          
          <p>If you've spent any time with the Cocoa docs you'll run across The Delegate Pattern. This thing is like the quark&mdash;it is the fundamental building block of the Cocoa APIs. Conceptually, it's really pretty simple. A delegate is simply an object that provides custom behavior for another object, often by implementing a specific protocol.</p>
          
          <p>Let's return to our running example. A table view of line items in an order has to handle a lot of things such as rendering each cell, handling scrolling, managing user-generated events and so on. These features are common enough that they are simply part of the table view class itself. What is specific to your application is the <em>data</em> that goes in those cells and <em>the actions</em> to be taken for user-generated events. Cocoa solves this by providing protocols for delegating that behavior to custom classes. In the case of providing data, a data-oriented delegate would be queried by the table view for the total number of rows, appropriate object to put in each row, the column headers, etc. In the case of event-handling, the table view will forward events to the event-handling delegate.</p>
          
          <p>Notifications use the <code>NSNotificationCenter</code> (or by proxy, the <code>NSNotificationQueue</code>) as an intermediary between message-senders and message-receivers. KVO uses the observed object as the intermediary. In the delegate model there is no intermediate object, but you still have relatively decoupled code because the object that invokes methods on the delegate has no knowledge of what <em>class</em> of object it's dealing with. Put another way, you could remove all of the classes in your project that implement a particular delegate protocol, and the class that <em>uses</em> the delegate would still compile correctly.</p>
          
          <p>The delegate pattern isn't so much about decoupling which objects are communicating with each other, as much as decoupling the classes of those objects. This doesn't make it any less powerful than the other two methods. In a lot of cases a simple delegate model is much more straightforward and preferable the alternatives.</p>
          
          <p>The delegate pattern is Cocoa's version of dependency injection. The object receiving the injected dependency has no idea of the type (and by extension, the implementation) of the object it is receiving, only what it's capabilities are via a contract specified as a protocol. This is basic polymorphism where the interface and the implementation are separated to reduce coupling.</p>
          
          <p>Delegating is a popular alternative to sub-classing. It is a <em>preferred</em> alternative because it's less likely to break encapsulation. If customization is done through subclassing it can be difficult to know which methods to override and implement, and easy to break the parent class. This is why Java provides all sorts of safety features like marking methods <code>abstract</code> and <code>final</code>. However that is simply more of a headache to deal with and using polymorphism would be a much better design.</p>
          
          <p>So there you have it, three ways to keep your code flexible and loosely-coupled!</p>
          
          <h3>Resources</h3>
          
          <ul>
          <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html">Apple's Notification Programming Topics</a></li>
          <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">Apple's Key-Value Coding Programming Guide</a></li>
          <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html">Apple's Cocoa Fundamentals</a></li>
          <li><a href="http://www.mikeash.com/?page=pyblog/key-value-observing-done-right.html">Mike Ash's Well-Reasoned Critique of KVO Design</a></li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The iPhone and Web APIs
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/' />
    <updated>
      2009-05-27T03:57:39PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/
    </id>
    <content type='html'>
      <![CDATA[
          <h1>The iPhone Ecosystem</h1>
          
          <p>We live in a very interesting time for application development. The distinctions between desktop, browser and mobile applications are blurring more and more every day. "Ubiquitous platform" applications, like <a href="http://evernote.com">Evernote</a>, are where the future is because it reduces the major hurdle of access for users. As time goes on users are going to expect applications to be available in a bunch of different ways that all need to work together.</p>
          
          <p>The common way to do this is base the application on shared-state accessed via an HTTP-based API. This makes it relatively easy to create apps for various devices as well as offer up a public API for others to use. An interesting side-effect of this is that the API, the shared-state and data behind it become the differentiator between products. The end-user client software is simply the packaging, turning the stand-alone application market into something more akin to the "razors and razor-blades model".</p>
          
          <p>Okay, none of this should be earth-shattering news to anyone. You should be prepared to write more apps that are integrated with one (or possibly more) "backend services". These services will, as likely as not, be connected over HTTP. As an iPhone developer you should know how to do this in your sleep.</p>
          
          <p>The <a href="http://www.evri.com">Evri</a> API is absolutely crucial to the EvriVerse phone application. Without it, the app does <em>nothing</em> of interest on its own. Our iPhone application is merely one kind of presentation of our web APIs. I don't think that's unique. What good would Tweetie be without Twitter?</p>
          
          <h1>Dealing with Web APIs</h1>
          
          <p>An unfortunate fact of integrating with web APIs is that they are, relatively speaking, slow. We don't want the user to get frustrated and give up on our app because they have their flow continually disrupted by waiting for data.</p>
          
          <p>There are some things you can do to mitigate the latency costs, if you control the API such as using some sensible caching parameters. However, especially if you don't control the web API, the bulk of what you should focus on is <em>concurrency</em> within your application. The biggest arrow in your quiver is figuring out how to turn unnecessarily serial operations into parallel ones. Now keep in mind that the iPhone doesn't support true multi-core concurrency. What I'm talking about is taking advantage of the I/O wait times that are inherently part of working with a high-latency I/O source (the web).</p>
          
          <p>Coming from a Java background, using threads seemed like a pretty natural approach and after reading the docs on the <code>NSThread</code>class I felt pretty confident I knew how to make it work. However, I was surprised by how quickly the code complicated. There is a lot to like about Objective-C, but I sorely miss Ruby's blocks and even Java's inner-classes. In Objective-C you connect methods together dynamically by handing objects selectors. The problem with this is that it's difficult to tell the high-level methods from the low-level callback methods just by looking at your class definition. Yes, you can use special comments and the like, but if you've worked in a language that has <em>structural</em> support for this differentiation, moving to a language without it feels like losing an arm.</p>
          
          <p>So instead of managing your own threads, let Cocoa Touch do the work for you. The <code>NSURLConnection</code> class is inherently asynchronous&mdash;you can fire a request and immediately move one with your life. Now you just need a little structure for handling the response and getting it back into your views.</p>
          
          <h1>The EvriApi</h1>
          
          <p>We tried to push as much of the mechanics of URL-handling into a separate code-base we call <a href="http://github.com/evri/EvriApi">EvriApi</a>. A good bit of the design was inspired by Matt Gemmell's <a href="http://mattgemmell.com/2008/02/22/mgtwitterengine-twitter-from-cocoa">MGTwitterEngine</a>, so I can't claim that I came up with the whole idea myself.</p>
          
          <p>We wanted the API to be as simple to work with as possible. Each API call has the same structure:
          *  Each API method takes zero-or-more domain-specific parameters, a selector and a target object.
          *  Each API method returns a unique request identifier
          *  The target object will have the given selector called when the request completes, and will be given an instance of the <code>EvriAPIResponse</code> class.
          *  If the response is successful (check <code>[response success]</code>), the payload of the request is retrieved as a domain-object
          *  If the response is unsuccessful, check the error message on the response
          *  Requests can be cancelled by handing the request identifier back to the API
          *  Attempts to cancel already-completed requests do nothing</p>
          
          <p>The <code>NSURLConnection</code> class makes asynchronous requests by default, and uses the familiar delegate model for handling the response. When a client invokes an API method, it returns immediately with a unique identifier (as a <code>NSString</code> instance) and the request is initiated on another thread which is handled automatically by <code>NSURLConnection</code>. The client is responsible for keeping track of that and using it to cancel any outstanding requests.</p>
          
          <p>When the request completes, the body of the response is parsed using the <code>NSXMLParser</code> class. The parser is given one of our specialized XML handlers as a delegate. These handlers deal with the XML event-stream and produce a model object or collection of model objects. The framework then packages this up into an <code>EvriAPIResponse</code> instance and invokes the selector given in the original request on the target given in the original request.</p>
          
          <h1>Wiring it Up</h1>
          
          <p>The EvriVerse app is primarily a "productivity" style application. In <a href="http://developer.apple.com/iPhone/library/documentation/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html">Interface Guidelines</a>-parlance this means that we use a lot of hierarchical navigation. In general we have no more than one or two API calls associated with a particular view controller.</p>
          
          <p>The common pattern for handling a user-initiated action that requires an API call is:</p>
          
          <ol>
          <li>A new view-controller is instantiated and displayed, typically with an activity indicator visible</li>
          <li>User-interaction is disabled on the new view controller</li>
          <li>The new view controller is displayed (usually by pushing it on the navigation controller stack).</li>
          <li>A request is submitted to the <code>EvriApi</code>, setting the new view controller as the target and some special method as the target selector.</li>
          <li>The request ID from the <code>EvriApi</code> is given to the newly-created view-controller</li>
          <li>When the API request finishes, the handler method on the new view-controller executes, handling both success and failure cases. It also re-enabled user interaction on the view.</li>
          <li>If the user navigates back before the request has completed, any outstanding requests are cancelled. This is usually handled in the <code>viewWillDisapper:(BOOL)animated</code> method of the view controller.</li>
          </ol>
          
          
          <p>Stepping back, the actors and interactions look something like this:</p>
          
          <p><img src="/images/2009/05/evri-api.png" alt="evri-api.png" /></p>
          
          <p>In code (snippets) it might look something like this:</p>
          
          <div class="highlight"><pre>    <span class="c1">// our parent view controller</span>&#x000A;        <span class="k">@implementation</span> <span class="nc">ParentViewController</span>&#x000A;        <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">didSelectEntity</span> <span class="p">{</span>&#x000A;          <span class="n">ChildViewController</span> <span class="o">*</span><span class="n">cvc</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">ChildViewController</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;        &#x000A;          <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">navigationController</span> <span class="nl">pushController:</span><span class="n">cvc</span> <span class="nl">animated:</span><span class="n">NO</span><span class="p">];</span>&#x000A;        &#x000A;          <span class="n">NSString</span> <span class="o">*</span><span class="n">requestId</span> <span class="o">=</span> <span class="p">[</span><span class="n">EvriApi</span> <span class="nl">fetchEntityByURI:</span><span class="n">entity</span><span class="p">.</span><span class="n">uri</span>&#x000A;                                          <span class="nl">performSelector:</span><span class="err">@</span><span class="p">(</span><span class="nl">didReceiveEntityResponse:</span><span class="p">)</span>&#x000A;                                                 <span class="nl">onTarget:</span><span class="n">cvc</span><span class="p">];</span>&#x000A;        <span class="p">}</span>&#x000A;        <span class="k">@end</span>&#x000A;    &#x000A;    &#x000A;    &#x000A;        <span class="err">@</span><span class="n">interface</span> <span class="n">ChildViewController</span> <span class="o">:</span> <span class="n">UITableViewController</span> <span class="p">{</span>&#x000A;          <span class="n">NSString</span> <span class="o">*</span><span class="n">requestId</span><span class="p">;</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">retain</span><span class="p">)</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">requestId</span><span class="p">;</span>&#x000A;        <span class="k">@end</span>&#x000A;        &#x000A;        <span class="k">@implementation</span> <span class="nc">ChildViewController</span>&#x000A;        &#x000A;        <span class="k">@synthesize</span> <span class="n">requestId</span><span class="p">;</span>&#x000A;        &#x000A;        <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">didReceiveEntityResponse:</span><span class="p">(</span><span class="n">EvriAPIResponse</span> <span class="o">*</span><span class="p">)</span><span class="n">response</span> <span class="p">{</span>&#x000A;          <span class="c1">// TODO: hide the activity indicator</span>&#x000A;          <span class="c1">// TODO: re-enable user interaction</span>&#x000A;        &#x000A;          <span class="k">if</span> <span class="p">([</span><span class="n">response</span> <span class="n">success</span><span class="p">])</span> <span class="p">{</span>&#x000A;            <span class="n">Entity</span> <span class="o">*</span><span class="n">e</span> <span class="o">=</span> <span class="p">(</span><span class="n">Entity</span> <span class="o">*</span><span class="p">)[</span><span class="n">success</span> <span class="n">result</span><span class="p">];</span>&#x000A;             <span class="c1">// TODO: redisplay as necessary</span>&#x000A;          <span class="p">}</span>&#x000A;          <span class="k">else</span> <span class="p">{</span>&#x000A;            <span class="c1">// TODO: show an alert</span>&#x000A;          <span class="p">}</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">viewWillDisappear</span> <span class="p">{</span>&#x000A;          <span class="p">[</span><span class="n">EvriApi</span> <span class="nl">cancelRequest:</span><span class="n">requestId</span><span class="p">];</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="k">@end</span>&#x000A;    </pre>
          </div>
          
          
          <p>So there you have it, one developer's way of integrating the iPhone with web APIs. More to come. Stay tuned.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Peepcode meets MacRuby
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/15/peepcode-meets-macruby/' />
    <updated>
      2009-05-15T21:38:30PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/05/15/peepcode-meets-macruby/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I am pleased to announce the release of Peepcode's latest screencast about MacRuby written by yours truly with Geoffrey Grossenbach and technical editing by Laurent Sansonetti.</p>
          
          <p><a href="http://peepcode.com/products/meet-macruby" target="_new"><img src="https://peepcode.com/system/uploads/2009/macruby-title.png" alt="" /></a></p>
          
          <p>Ever since I saw Laurent's and Rich Kilmer's presentations about MacRuby and HotCocoa at RubyConf '08, I've been jazzed about what MacRuby brings to the world of Cocoa development. So check out the screencast for the coolest new Ruby on the block.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Incremental Find on the iPhone
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/15/typeahead-search-on-the-iphone/' />
    <updated>
      2009-05-15T04:55:38PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/05/15/typeahead-search-on-the-iphone/
    </id>
    <content type='html'>
      <![CDATA[
          <p>This is the first in a series of posts I'll be writing about my experiences developing the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=312716560=8">EvriVerse iPhone application</a> for <a href="http://evri.com">work</a>. Since the end of 2008 I've been getting more and more into Cocoa for both the iPhone and Mac. The more I work on it, the more fun I have. I've got several side-projects in mind so I'll be spending a lot more time in Cocoa-land and, as a result, blogging and tweeting about it a lot more.</p>
          
          <p>I wanted to kick this off with a little appetizer. We're going to look at how we implemented incremental find in EvriVerse. Evri has a huge database of structured entity data (people, places and things) and our users want to be able to search for any of them. After putting the initial prototype for EvriVerse on a few folks' phones, a lot of them wanted a search feature that worked more like our website.</p>
          
          <p><img src="/images/2009/05/picture-5.png" alt="Picture 5.png" /></p>
          
          <p>In the original implementation a user would type in the search field, then hit the "Search" button and then get their results back in the table view. This takes too many steps, and we wanted something that felt faster and more responsive.</p>
          
          <p><img src="/images/2009/05/picture-6.png" class="right"/></p>
          
          <p>So our incremental find solution needed the following properties:</p>
          
          <ul>
          <li>It should only send a search request when there is a measurable pause in input</li>
          <li>It should enable some kind of activity indicator while a search request is running</li>
          <li>A user should be able to modify the contents of the search field while a search request is in-progress</li>
          <li>It should not preclude the existing two-step search process</li>
          <li>If a search request is in process when another one starts, the first one should be cancelled and the new one should be the only request in-process</li>
          </ul>
          
          
          <p>At first I tried managing my own <code>NSThread</code> instance while tracking the timestamps of touch events in the <code>searchBar:textDidChange:</code> method (part of the <code>UISearchBarDelegate</code> protocol). If the the gap between time samples was big enough I'd cancel any outstanding request and start a new one. This seemed like a good approach at the whiteboard, but really fell apart in the implementation. I had race-conditions left and right and I had the sneaking suspicion that I was swimming upstream against "the Cocoa way".</p>
          
          <p>As an aside, if there's one thing I've learned in my brief time with Cocoa, it's that mucking about with your own threads is a pretty crummy way to do things asynchronously. Usually there's a much more elegant, built-in solution in the Cocoa APIs that will handle the threading for you. I'll riff on this theme in a later post.</p>
          
          <p>So back to the problem at hand. What to do? When I get stuck like this I often start thinking of how I'd do this in another language. This got me to thinking about how one would go about implementing this sort of thing in Javascript. This is standard Web-2.0 kind of stuff&mdash;right after drop-shadows and rounded corners, you learn about type-ahead search at AJAX School.</p>
          
          <p>See, Javascript has this very nifty little function named <code>setTimeout</code> where you hand it a function and tell it how long you want to wait until that function is executed, and it returns you a reference identifier. There is a companion function, <code>clearTimeout</code> that allows you to cancel any previously-created "timeout" function by handing it the reference identifier you got earlier from <code>setTimeout</code>.</p>
          
          <p>In the common AJAX-ified dynamic search that you often see, an event-handler observes the search field in a web form for key presses. Each key press cancels any existing timeout function, and starts a new one that will execute in whatever time-interval was chosen as the "quiescence period". The trick is that because you're scheduling future tasks, <em>and</em> you cancel any outstanding ones when you kick off a new one, you get the "measurable pause" feature in a simple, elegant solution.</p>
          
          <p>Cocoa provides a very similar mechanism, through the <code>NSTimer</code> class. In my view-controller, the code ended up looking something like this:</p>
          
          <div class="highlight"><pre><span class="k">@implementation</span> <span class="nc">FindViewController</span>&#x000A;    <span class="c1">// much implementation code has been elided for demonstration purposes</span>&#x000A;    &#x000A;    <span class="c1">// observe text-field changes and fire the scheduled task</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">searchBar:</span><span class="p">(</span><span class="n">UISearchBar</span> <span class="o">*</span><span class="p">)</span><span class="n">searchBar</span> <span class="nl">textDidChange:</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="n">searchText</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">([</span><span class="n">searchText</span> <span class="n">length</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="n">timer</span><span class="p">)</span> <span class="p">{</span>&#x000A;          <span class="p">[</span><span class="n">timer</span> <span class="n">invalidate</span><span class="p">];</span>&#x000A;          <span class="n">self</span><span class="p">.</span><span class="n">timer</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>&#x000A;        <span class="p">}</span>&#x000A;        <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">info</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="n">searchText</span><span class="p">,</span> &#x000A;                              <span class="s">@&quot;Text&quot;</span><span class="p">,</span> &#x000A;                              <span class="nb">nil</span><span class="p">];</span>&#x000A;        <span class="n">self</span><span class="p">.</span><span class="n">timer</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSTimer</span> <span class="nl">scheduledTimerWithTimeInterval:</span><span class="mi">1</span>&#x000A;                                                      <span class="nl">target:</span><span class="n">self</span>&#x000A;                                                    <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">submitSearchRequest:</span><span class="p">)</span>&#x000A;                                                    <span class="nl">userInfo:</span><span class="n">info</span>&#x000A;                                                     <span class="nl">repeats:</span><span class="n">NO</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="c1">// The method that runs in the NSTimer--equivalent to the function </span>&#x000A;    <span class="c1">// we&#39;d pass to Javascript&#39;s &quot;setTimeout&quot; function</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">submitSearchRequest:</span><span class="p">(</span><span class="n">NSTimer</span> <span class="o">*</span><span class="p">)</span><span class="n">aTimer</span> <span class="p">{</span>&#x000A;      <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">info</span> <span class="o">=</span> <span class="p">[</span><span class="n">aTimer</span> <span class="n">userInfo</span><span class="p">];</span>&#x000A;      <span class="n">NSString</span> <span class="o">*</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">info</span> <span class="nl">objectForKey:</span><span class="s">@&quot;Text&quot;</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">activityIndicator</span> <span class="n">startAnimating</span><span class="p">];</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">requestId</span> <span class="o">=</span> <span class="p">[</span><span class="n">EvriApi</span> <span class="nl">fetchEntitiesMatchingPrefix:</span><span class="n">text</span>&#x000A;                                            <span class="nl">performSelector:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">didReceiveEntitiesDynamically:</span><span class="p">)</span>&#x000A;                                                   <span class="nl">onTarget:</span><span class="n">self</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="c1">// The callback from our API class, included for completeness</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">didReceiveEntitiesDynamically:</span><span class="p">(</span><span class="n">EvriApiResponse</span> <span class="o">*</span><span class="p">)</span><span class="n">response</span> <span class="p">{</span>&#x000A;      <span class="p">[</span><span class="n">timer</span> <span class="n">invalidate</span><span class="p">];</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">timer</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>&#x000A;      <span class="p">[</span><span class="n">activityIndicator</span> <span class="n">stopAnimating</span><span class="p">];</span>&#x000A;      <span class="k">if</span> <span class="p">([</span><span class="n">response</span> <span class="n">success</span><span class="p">])</span> <span class="p">{</span>&#x000A;        <span class="p">[</span><span class="n">entities</span> <span class="n">removeAllObjects</span><span class="p">];</span>&#x000A;        <span class="p">[</span><span class="n">entities</span> <span class="nl">addObjectsFromArray:</span><span class="p">(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)[</span><span class="n">response</span> <span class="n">responseObject</span><span class="p">]];</span>&#x000A;        <span class="p">[</span><span class="n">tableView</span> <span class="n">reloadData</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">else</span> <span class="p">{</span>&#x000A;        <span class="n">UIAlertView</span> <span class="o">*</span><span class="n">error</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UIAlertView</span> <span class="n">alloc</span><span class="p">]</span> &#x000A;                              <span class="nl">initWithTitle:</span><span class="s">@&quot;Uh oh&amp;hellip;&quot;</span>&#x000A;                              <span class="nl">message:</span><span class="s">@&quot;Sorry, we were unable to execute your request. Please try again.</span>&#x000A;    <span class="s">&quot;</span>&#x000A;                              <span class="nl">delegate:</span><span class="nb">nil</span>&#x000A;                              <span class="nl">cancelButtonTitle:</span><span class="s">@&quot;OK&quot;</span>&#x000A;                              <span class="nl">otherButtonTitles:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;        <span class="p">[</span><span class="n">error</span> <span class="n">show</span><span class="p">];</span>&#x000A;        <span class="p">[</span><span class="n">error</span> <span class="n">release</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="k">@end</span>&#x000A;    </pre>
          </div>
          
          
          <p>In the <code>searchBar:textDidChange:</code> method we check to see if our instance field, <code>timer</code>, points at an existing <code>NSTimer</code> instance. If it does we cancel it, clear the reference, and start a new timer instance. That timer is configured to run in one second and will execute our <code>submitSearchRequest:</code> method. This makes a call to our API and designates the <code>didReceiveEntitiesDynamically:</code> method as the callback for that asynchronous operation.</p>
          
          <p>Finally, the <code>didReceivedEntitiesDynamically:</code> method handles the UI by disabling the wait indicator, dealing with any error cases and populating our table view if our request was successful. I'll write another post later about how the <code>EvriApi</code> class works and its design.</p>
          
          <p>So that's it. Simple and elegant. One of the things I love about working on several different programming languages is figuring out how to apply the best tricks of one language to another.</p>
          
          <p>That's all for now, but stay tuned! More iPhone posts to come&hellip;</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Introducing the EvriVerse
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/12/introducing-the-evriverse/' />
    <updated>
      2009-05-12T17:28:15PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/05/12/introducing-the-evriverse/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="/images/2009/05/graph.jpg" class="left"/></p>
          
          <p>After several months of work, I'm pleased to announce the release of Evri's EvriVerse for the iPhone. We've tried to capture the unique things we do at Evri into the awesomeness that is the iPhone. I won't spill all the details here, so check out out the "official" company <a href="http://blog.evri.com/index.php/2009/05/11/welcome-to-the-evriverse-evris-iphone-app/">post</a>.</p>
          
          <p>I've been working on this thing for a few months, mostly on a part-time basis. We have a 20% time program at Evri where devs can pitch ideas they want to spend one day a week on. I was <em>dying</em> to write an iPhone app and jumped at the opportunity to turn it into a 20% project. After some early prototypes I got enough attention that I was given a solid two-week sprint to finish it off.</p>
          
          <p>This was a ton of fun to work on and I have five or six posts on some things I discovered while working on it.</p>
          
          <p>It's free in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=312716560=8">App Store</a> now. We'd love to hear any feedback you may have, which you can post on the <a href="http://blog.evri.com/index.php/iphone-application-support/">Evri Support Page</a>.</p>
          
          <div style="clear: both;"></div>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The Great Git Setup
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/08/the-great-git-setup/' />
    <updated>
      2009-05-08T04:17:14PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/05/08/the-great-git-setup/
    </id>
    <content type='html'>
      <![CDATA[
          <p>One of the best ways to really learn the ins and outs of anything is to immerse yourself in all the gory details. Not only do you learn what works, what doesn't, what's elegant and what sucks, but you also start to grok the inner-workings. I just spent the last two weeks getting our own internal Git infrastructure up and running at work and I feel like Git and I have a new level of intimacy that we previously lacked. What follows is a review of the process and the solution that we've implemented.</p>
          
          <p>For most of us at work, our primary Git experience is with GitHub. This is a good way to learn how Git's distributed model works, but GitHub provides some nice infrastructure that you simply don't have with a stock Git install. You have to cobble-together the rest from a variety of sources. <strike>So GitHub guys&mdash;if you're listening&mdash;it would be <em>fantastic</em> if you provided real white-label GitHub solution for organizations to install locally. You guys have really spoiled us.</strike> (oops, nevermind. Checkout <a href="http://fi.github.com/tour.html">GitHub:fi</a>). But until then, we have to roll our own&hellip;</p>
          
          <h1>The Goals</h1>
          
          <p>First, let's review what exactly we were trying to accomplish. We wanted a solution that:
          *  easily converted existing Subversion repositories to Git
          *  provided a usable web view over all repos that was equal to, or exceeded, the stock SVN/DAV model
          *  allowed us to designate a set of "authoritative" repositories
          *  provided for "developer" repositories to allow developers to publish their changes
          *  allowed for patch reviews (if teams decide to do that)</p>
          
          <h1>The Solution</h1>
          
          <p>Right away we knew that we wanted two different types of repositories: authoritative and developer. Authoritative repos are ones that host the "official" source code and from which we create release builds from. When a developer wants to start working on a project, these are the repos they clone to get started.</p>
          
          <p>The other type of repository belongs to an individual developer. Developers have read/write access to their own repos, but others only have read-only access. This allows developers to share changes in a pull-request model similar to how GitHub works.</p>
          
          <h2>Permissions &amp; Connectivity</h2>
          
          <p>Developers connect to these repositories in two different ways. We use the built-in <code>git://</code> protocol (with <code>git-daemon</code>) for read-only access and <code>ssh://</code> for read-write access. Developers clone authoritative repos and other developers' repos using the read-only <code>git://</code> protocol. Developers have a remote reference to their developer repository using ssh.</p>
          
          <p>For each project, we designated one or more maintainers that have write-access to the authoritative repositories. These folks accept patches from other developers, test and integrate them on their local machines, and push final changes to the authoritative repositories. We manage the authoritative repos using <a href="http://eagain.net/gitweb/?p=gitosis.git">gitosis</a>. Check out <a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">this great tutorial</a> for details on setting up gitosis.</p>
          
          <h2>gitosis</h2>
          
          <p>On our central "git box" we create a "git" user which owns both the <code>gitosis-admin</code> repository as well as all the authoritative repositories. Gitosis is bootstrapped  with a single SSH public key that gives the associated user the ability to write to that Git repo over SSH. That user can then add more keys and configuration allowing other users to manage projects. Gitosis works a bit like the CVSROOT project in CVS&mdash;it is a special Git repo that allows us to configure other Git repositories. We use gitosis to configure our designated maintainers for each project.</p>
          
          <p>Our authoritative repos are housed in <code>/home/git/repositories</code>. Our developer repositories are located in <code>/opt/repos</code>, where each developer has their own directory to put Git repos in.</p>
          
          <h2>git daemon</h2>
          
          <p>We run <code>git daemon</code> to allow for anonymous read-only access. We configured <code>git daemon</code> to serve up all Git repositories found in the <code>/opt/repos</code> directory with read-only access. We also symlink the authoritative repositories (<code>/home/git/repositories</code>) into this directory so that we can serve up read-only access to authoritative repositories also.</p>
          
          <h2>gitweb</h2>
          
          <p>For all the power Git has, there sure are a lot of half-baked web interfaces for it. We did our best to vet the tools listed on the <a href="http://git.or.cz/gitwiki/InterfacesFrontendsAndTools">Git site</a>. A good number of the them were either abandoned or simply didn't work. In the end we went with the venerable old <a href="http://git.or.cz/gitwiki/Gitweb">gitweb</a>.</p>
          
          <p>Gitweb has a ton of functionality&mdash;including all kinds of search capability, different views (by tag, by commit, by tree) and even serves up an Atom feed of changes&mdash;but it is definitely a designed-by-developers-for-developers</code>. (NB: In case you missed the markup, that is considered an epithet on my team).</p>
          
          <p>Frankly I was amazed that somebody hadn't built a Rails app to manage this stuff. Yes, we  looked at <a href="http://gitorious.org/projects/gitorious">gitorious</a> and even tried to set it up. After three hours I still didn't have a working installation and my patience had run out. While gitorious appears to be a nice turn-key solution, I don't think it's actually that great of a fit for us. So gitweb it is. Sigh.</p>
          
          <h2>The Flow</h2>
          
          <p>With me so far? Maybe not. Let's look at a picture then&hellip;</p>
          
          <p><img src="/images/2009/05/98ee3ae7-c4f4-4d1d-b49b-dcc230ea7459.jpg" alt="98EE3AE7-C4F4-4D1D-B49B-DCC230EA7459.jpg" /></p>
          
          <p>In this picture the authoritative and developer repos are drawn in separate boxes (since they're logically separate), but they are located on the same machine in reality. Let's cover a couple of common scenarios:</p>
          
          <h2>New Developer, Old Project</h2>
          
          <p>A developer starts by cloning an authoritative repo using the <code>git://</code> protocol (remember, read-only). This will create, by default, a remote reference named <code>origin</code> that points back to the authoritative repo.</p>
          
          <p>The next step is for them to create a developer repo in their directory for the same project on the central git machine. They also want to a remote reference to their developer repo so that they can push changes to that. That would looks something like:</p>
          
          <div class="highlight"><pre>git remote add alex ssh://git/opt/repos/alex/circus/clown-car&#x000A;    </pre>
          </div>
          
          
          <p>If this user is also a maintainer, they need to add a <em>third</em> remote reference which gives them read/write access to the authoritative repository. The way that gitosis works is by accepting SSH keys on behalf of the git user. So if you're properly configured, you can push changes over SSH by logging in as the <code>git</code> user. A maintainer would add a read/write reference like so:</p>
          
          <div class="highlight"><pre>git remote add main ssh://git@git/home/git/repositories/circus/clown-car&#x000A;    </pre>
          </div>
          
          
          <p>Because of the way gitosis configures the SSH keys in <code>/home/git/.ssh/authorized_keys</code> and the fact that the default protocol is ssh, this remote reference could also be added like this:</p>
          
          <div class="highlight"><pre>git remote add main git@git:circus/clown-car&#x000A;    </pre>
          </div>
          
          
          <p>Now because there are number of steps involved here, we wrote a little command-line tool (as a RubyGem) that takes care of these steps all in one go. Right now, it's <em>very</em> specific to our setup at Evri, but I can see how we might extract a common tool (oh boy&hellip;another side-project&hellip;)</p>
          
          <h2>Old Developer, New Project</h2>
          
          <p>When it's time to create a new project, a developer usually starts out by creating a new Git repo on their local box while they're building out the initial version. Once it's time to share, that developer can create a new developer repo on our central Git machine just by SSH'ing in and making the appropriate directory, adding the remote ref to their local repo and pushing changes. Again, our internal tools sets this up all in one go.</p>
          
          <p>Once that project is ready to have an authoritative repo, a gitosis-enabled user will pull the latest changes for the <code>gitosis-admin</code> project. They'll edit the <code>gitosis.conf</code> file to add the new project (and members) and commit the changes. Then the developer adds a new remote ref (a read/write one as the <code>git</code> user) and pushes changes out to the main repo.</p>
          
          <h2>Sharing Patches</h2>
          
          <p>The most common flow is when developers share patches with each other. There are a couple of ways to do it. Developers keep their developer repository up-to-date and email requests to their teammates to pull changes from their repo (a la GitHub). Developers may also choose to share patches via email using <code>git format-patch</code>, <code>git send-mail</code> and <code>git am</code>.</p>
          
          <p>Ultimately the maintainers are responsible for gathering patches from developers and integrating them back into the authoritative repositories.</p>
          
          <p><img src="/images/2009/05/git-cycle.png" alt="git-cycle.png" /></p>
          
          <p>For folks used to version control systems like CVS or Subversion this feels like an awful lot of hoop-jumping. One part that I can't diagram or explain as a series of technical bullet-points is the stewardship the pro-Git folks have to take on. People who are switching to Git get frustrated by the byzantine nomenclature and steep learning curve, so a big part of the change and setup is simply helping people out when they get stuck.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Using Git as a Safety Net
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/03/14/using-git-as-a-safety-net/' />
    <updated>
      2009-03-14T18:11:32PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/03/14/using-git-as-a-safety-net/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I spent the last week on a top-secret iPhone application at work. It has been a blast, in part, because it's been so fun to learn so much new information so quickly. That has meant trying out lots of ideas and, more often than not, rolling them back and trying again. The problem is that doing this kind of experimentation can be an absolute productivity-killer in terms of managing your changes&mdash;unless you have a good tool to manage large chunks of changes, you can spend a lot of time trying to do it manually (and probably screwing it up in the process).</p>
          
          <p>While doing Java development, I've often used Eclipse's file history feature to roll things back. The downside is that it's file-by-file and not easy to tag the current state of your entire project in one go. It appears that Xcode has this feature, but since I'm using Git for my SCM, I figured why not use that instead?</p>
          
          <p>So my new flow has been to stage changes to the index whenever I make <em>any</em> progress and the app is still in a working state. This is different from a commit, which I still like to think of as a succinct, whole change around a particular feature. The incremental staging is more like dribbling micro-changes to the next stage prior to committing. It can take several attempts to get to a real, first-class commit.</p>
          
          <p>I like using <a href="http://zagadka.vm.bytemark.co.uk/magit/">magit</a>, so I keep Emacs running in the background. When I get to a good checkpoint, I stage hunks or entire files to the index. When I get enough to make a full commit, I commit them. If you're running git exclusively on the command-line, this would be the equivalent of using <code>git add -i</code>.</p>
          
          <p>When I first started using Git, I couldn't see the value in Git's stage-commit-push workflow. Now I get it. Like most Git tricks, this one is probably obvious to a lot of folks, but for me it's been a real life-saver on this project. I've been able to be much more cavalier with experimentation because I can easily revert changes with a single keystroke. Nifty!</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          What Jersey Means To Java
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/03/04/what-jersey-means-to-java/' />
    <updated>
      2009-03-04T18:42:49PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/03/04/what-jersey-means-to-java/
    </id>
    <content type='html'>
      <![CDATA[
          <p>In the last few days at <a href="http://evri.com">work</a> I've been migrating a home-grown REST framework over to the <a href="https://jersey.dev.java.net/">Jersey project</a> (the reference implementation of JSR-311 or, JAX-RS). Previously I had done some work moving JRuby into the VM and launching Merb. It was satisfying to figure out how to do that, but involved an awful lot of wiring and special-casing.</p>
          
          <p>As anyone who has read this blog recently knows, the luster is coming off of Java for me in a big way. These days my goals are simply to co-exist with it in a way that keeps me happy. I'm not going to be able to toss Java overboard so my working-life becomes a question of how to be happy with the situation.</p>
          
          <p>While our home-grown framework has worked well for us, I'd much rather see us using something with wider adoption and use. So I took a look at Jersey and came away pretty impressed. Looking at how the API is built and what you need to do to build REST-ful web services in Java I couldn't help but feel like Java has learned some lessons from the rest of the world.</p>
          
          <p>The original Servlet API is what could be termed a "classic" Java API, wherein consistency and type-safety are the rules. In the Servlet API, you interact with requests and responses as monolithic objects. Each type of HTTP method (i.e. GET, POST, PUT and DELETE) has their own method which takes a <code>ServletRequest</code> and a <code>ServletResponse</code> object.</p>
          
          <p>It's a reasonable first solution, but it breaks down quickly. The primary issue is that by packing all possible request-related data into a single request object, and all possible response-related data into a single response object the classes themselves start to feel bloated. A more sinister second-order effect is that these classes, especially the response object, have some hidden state and "gotchas" because they are so general.</p>
          
          <p>As an example, consider the case where you want to return a response with a non-200 response code, an entity body and some headers. The order in which you set these on the response object is important because of how it's implemented. You need to set the status and headers <em>before</em> you write any output to the stream. This make sense because you want a stream-oriented interface which means not storing the entire response in memory and then flushing. But, due to the strict order of HTTP response messages, you need to flush the header information prior to sending the body. It's not a particularly difficult thing to remember, but it is unnecessary mental overhead that is an artifact of the implementation.</p>
          
          <p>The request object is its own special brand of fun to deal with. Again its broad coverage makes for a rather clunky API to deal with. You want request parameters? You have to grovel through <code>String</code> arrays if you want to capture all of them. When implementing a Servlet, often what you want is some combination of request parameters, cookies and header; rarely do you need all of them at once. However what you get is one big &uuml;ber-object that has everything. Enjoy!</p>
          
          <p>One final beef with the <code>ServletRequest</code> class is that getting path parameters out is an absolute nightmare. If you're building REST resources you really really care about the path as it is <em>the</em> way to identify resources. The poor support the <code>ServletRequest</code> class provides for this is simply shocking. Here's a <code>String</code> &mdash; you parse it and figure out what the hell the segments are.</p>
          
          <p>In contrast, Jersey has a much looser philosophy with how requests and responses are handled. First, the monolithic request and response objects go away. Instead your methods provide the narrowest possible interface, expressing only what they need in exacting terms. This is done by making extensive use of Java annotations to mark up simple method parameters. For example, if you have a resource that needs a request parameter, use the <code>@QueryParam</code> annotation. Need a header? Just use <code>@HeaderParam</code>. Interested in cookies? Use the <code>@CookieParam</code> annotation. Here's an example:</p>
          
          <div class="highlight"><pre><span class="kd">public</span> <span class="n">MyResult</span> <span class="nf">getMyResult</span><span class="o">(</span><span class="nd">@QueryParam</span><span class="o">(</span><span class="s">&quot;name&quot;</span><span class="o">)</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>&#x000A;        <span class="o">...</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>This does away with a tremendous amount of "busy-work". You want the "name" parameter? By god you're going to get it&mdash;no intermediate objects to reach into and pull stuff out of.</p>
          
          <p>A really nice side-effect of this is that writing tests for your resources become <em>so much</em> cleaner than using the more general Servlet API. Instead of setting up the monolithic request and response objects, you simply pass in the bits you want.</p>
          
          <p>What about the response side? I think that it's in this area that we really see a fundamental philosophical shift emerge. In an earlier time the textbook answer to how to design an API like this would be to have each request method return some kind of superclass or interface. This would allow us to use polymorphism to vary the response, but keep our type-safety.</p>
          
          <p>Jersey takes a different approach based on real-world needs. Whereas the Servlet API is intended to keep everyone equally happy by making sure everyone suffers the same amount of pain, Jersey lets you vary what you return&mdash;no special markers, no special configuration. If you have a simple case where you want to serialize an object as the entity response, just return the object.</p>
          
          <p>What if you need to fiddle with the response some more? Maybe set some headers or alter the status code? In this case your method returns a <code>Response</code> instance. Now this may sound monolithic and perhaps, under the covers, it is. What saves it from degenerating into the Servlet API is the fact that you build a <code>Response</code> object with only as much as you need.</p>
          
          <p>In the Servlet API you might have to set a moderately complicated response like this:</p>
          
          <div class="highlight"><pre><span class="kd">public</span> <span class="kt">void</span> <span class="nf">doGet</span><span class="o">(</span><span class="n">HttpServletRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpServletResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="o">{</span>&#x000A;      <span class="c1">// do some stuff</span>&#x000A;      <span class="n">resp</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">&quot;Expires&quot;</span><span class="o">,</span> <span class="n">computeExpires</span><span class="o">());</span>&#x000A;      <span class="n">resp</span><span class="o">.</span><span class="na">setStatus</span><span class="o">(</span><span class="mi">201</span><span class="o">);</span>&#x000A;      <span class="n">writeResponse</span><span class="o">(</span><span class="n">resp</span><span class="o">.</span><span class="na">getWriter</span><span class="o">(),</span> <span class="k">new</span> <span class="n">MyStuff</span><span class="o">());</span>&#x000A;    <span class="o">}</span>&#x000A;    &#x000A;    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">writeResponse</span><span class="o">(</span><span class="n">Writer</span> <span class="n">writer</span><span class="o">,</span> <span class="n">MyStuff</span> <span class="n">stuff</span><span class="o">)</span> <span class="o">{</span>&#x000A;      <span class="c1">// do whatever you have to do to serialize your object</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>In Jersey it looks like this:</p>
          
          <div class="highlight"><pre><span class="kd">public</span> <span class="n">Response</span> <span class="nf">getMyStuff</span><span class="o">()</span> <span class="o">{</span>&#x000A;      <span class="n">MyStuff</span> <span class="n">stuff</span> <span class="o">=</span> <span class="k">new</span> <span class="n">MyStuff</span><span class="o">();</span>&#x000A;      <span class="k">return</span> <span class="n">Response</span><span class="o">.</span><span class="na">created</span><span class="o">(</span><span class="n">stuff</span><span class="o">).</span><span class="na">expires</span><span class="o">(</span><span class="n">computeExpires</span><span class="o">()).</span><span class="na">build</span><span class="o">();</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>The amount of code probably comes out to be the same, but the fact that you can build the response in a single line feels really good to me. The amount of vertical space dedicated to response-building is much more proportional to it's conceptual space in the method in Jersey than the Servlet API.</p>
          
          <p>Now I realize that comparing Jersey to the Servlet API is perhaps unfair. The Servlet API is really designed to operate a layer below where Jersey plays. But I think the same arguments apply to a majority of the other popular web frameworks. The models are all essentially the same.</p>
          
          <p>So here's where the philosophical sea-change comes in. To vary the response type to do the right thing means that after a decade of existence, people are finally embracing Java's reflection capabilities. Up until pretty recently this was considered the domain of the lunatic fringe.</p>
          
          <p>The primary argument against reflection has always been that it's too slow. While it's true that their can be a penalty <em>under certain circumstances</em>, the modern perspective is that it's an acceptable price to pay for a kinder, gentler API. Simply put, this level of dynamism is essential for reducing the amount of boilerplate and busywork.</p>
          
          <p>I think if other frameworks like Rails, Django and Merb hadn't gained so much traction in the last few years Java would have continued on it merry way. However I think the popularity of those alternatives has forced the Java greybeards to learn a thing or two. Strict static type-safety can become a burden and using reflection to vary behavior instead of polymorphism can make for some very clean APIs.</p>
          
          <p>After spending a few days with Jersey I find myself a little re-energized to work with Java again. We're even considering <a href="http://groovy.codehaus.org/">Groovy</a>  as a way to cut down Java's chubby syntax for another small productivity win. Of course, my personal preference would be to do this JRuby since I, personally, don't find Groovy to be terribly compelling on its own. But since Jersey is <em>so</em> dependent on annotations, using JRuby is a non-starter.</p>
          
          <p>Who knows? This could be a complete fiasco and another frustrated attempt at tilting windmills. I'm already a little suspicious of the "enterprisey" way this thing gets configured. However if nothing else, it's refreshing to see some new ideas make their way into Java after all these years.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          You Put Merb In My Jetty!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/02/11/you-put-merb-in-my-jetty/' />
    <updated>
      2009-02-11T23:31:53PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/02/11/you-put-merb-in-my-jetty/
    </id>
    <content type='html'>
      <![CDATA[
          <p>In the latest update of <em>The Chronicles of Stuff Alex Figures out at Work,</em> our intrepid hero figures out how to run Merb inside an embedded Jetty instance!</p>
          
          <p>Now you may ask yourself, "for the love of God, why would you want to do something like this?" Well, at <a href="http://www.evri.com%20Evri!">work</a> we do a lot of internal web services. For my particular team, we've found a real sweet-spot by using an embedded Jetty server sitting right next to a BDB instance. There are no extra processes or packages to manage (e.g. apache or a RDBMS). However we were becoming dissatisfied with our current web layer which is a homegrown REST framework that sits on top of the Servlet API. So in a fit of rage, I decided to see if I could stuff Merb in the middle of this mess.</p>
          
          <p>You may also be asking yourself, "why not use the <a href="http://blog.nicksieger.com/articles/2008/05/08/introducing-jruby-rack%20JRuby-Rack">jruby-rack</a> gem directly?" The answer is that the jruby-rack gem makes a lot of assumptions about how you want to run your application. First it assumes that you're cool with packaging things up as a WAR (which I'm not) and, secondly, that your application is <em>primarily</em> a Rails/Merb application. In my case, for better or worse, our app is really a BDB application with a Merb app glommed onto the side for web visibility.</p>
          
          <h1>The Solution</h1>
          
          <p>I can't take complete credit for this solution. If I hadn't found <a href="http://www.trampolinesystems.com/blog/machines/2008/11/27/rails-22-jruby-jetty-win/%20rails%202.2%20+%20jruby%20+%20jetty%20=%20win">Jan Berkel's post on putting Rails in Jetty</a> I would have <em>never</em> figured out how to stuff Merb in there. To give yourself some context, take a look at that post first. Then take a look at the "Merb-ified" version of the same recipe below. Both solutions assume that you're configuring Jetty within JRuby.</p>
          
          <div class="highlight"><pre><span class="n">server</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">mortbay</span><span class="o">.</span><span class="n">jetty</span><span class="o">.</span><span class="n">Server</span><span class="o">.</span><span class="n">new</span>&#x000A;    <span class="n">thread_pool</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">mortbay</span><span class="o">.</span><span class="n">thread</span><span class="o">.</span><span class="n">QueuedThreadPool</span><span class="o">.</span><span class="n">new</span>&#x000A;    <span class="n">thread_pool</span><span class="o">.</span><span class="n">min_threads</span>  <span class="o">=</span> <span class="mi">5</span>  <span class="c1"># adjust as needed</span>&#x000A;    <span class="n">thread_pool</span><span class="o">.</span><span class="n">max_threads</span>  <span class="o">=</span> <span class="mi">50</span>&#x000A;    <span class="n">server</span><span class="o">.</span><span class="n">set_thread_pool</span><span class="p">(</span><span class="n">thread_pool</span><span class="p">)</span>&#x000A;    <span class="n">context</span> <span class="o">=</span> <span class="no">Context</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="kp">nil</span><span class="p">,</span> <span class="s2">&quot;/&quot;</span><span class="p">,</span> <span class="no">Context</span><span class="o">::</span><span class="no">NO_SESSIONS</span><span class="p">)</span>&#x000A;    <span class="n">context</span><span class="o">.</span><span class="n">add_filter</span><span class="p">(</span><span class="s2">&quot;org.jruby.rack.RackFilter&quot;</span><span class="p">,</span> <span class="s2">&quot;/*&quot;</span><span class="p">,</span> <span class="no">Handler</span><span class="o">::</span><span class="no">DEFAULT</span><span class="p">)</span>&#x000A;    <span class="n">context</span><span class="o">.</span><span class="n">set_resource_base</span><span class="p">(</span><span class="no">Environment</span><span class="o">.</span><span class="n">resolve</span><span class="p">)</span>&#x000A;    <span class="n">context</span><span class="o">.</span><span class="n">add_event_listener</span><span class="p">(</span><span class="no">MerbServletContextListener</span><span class="o">.</span><span class="n">new</span><span class="p">)</span>&#x000A;    <span class="n">context</span><span class="o">.</span><span class="n">set_init_params</span><span class="p">(</span><span class="n">java</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">HashMap</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;merb.root&#39;</span><span class="o">=&gt;</span><span class="p">;</span> <span class="no">Environment</span><span class="o">.</span><span class="n">resolve</span><span class="p">,</span>&#x000A;        <span class="s1">&#39;merb.environment&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;production&#39;</span><span class="p">,</span>&#x000A;        <span class="s1">&#39;public.root&#39;</span> <span class="o">=&gt;</span> <span class="no">Environment</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="s1">&#39;public&#39;</span><span class="p">),</span>&#x000A;        <span class="s1">&#39;gem.path&#39;</span> <span class="o">=&gt;</span> <span class="no">Environment</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="s1">&#39;gems&#39;</span><span class="p">),</span>&#x000A;        <span class="s1">&#39;org.mortbay.jetty.servlet.Default.relativeResourceBase&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;/public&#39;</span><span class="p">,</span>&#x000A;        <span class="s1">&#39;jruby.max.runtimes&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;1&#39;</span><span class="p">))</span>&#x000A;    <span class="n">context</span><span class="o">.</span><span class="n">add_servlet</span><span class="p">(</span><span class="no">ServletHolder</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="no">DefaultServlet</span><span class="o">.</span><span class="n">new</span><span class="p">),</span> <span class="s2">&quot;/&quot;</span><span class="p">)</span>&#x000A;    <span class="n">server</span><span class="o">.</span><span class="n">set_handler</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>&#x000A;    <span class="n">server</span><span class="o">.</span><span class="n">start</span>&#x000A;    </pre>
          </div>
          
          
          <h1>Tweaking</h1>
          
          <p>At first blush our performance seemed to be pretty lacking. This required two tweaks: putting Merb in "production" mode and dealing with poor I/O due to logging. In the previous snippet you will notice that we set the <tt>merb.environment</tt> to <tt>production</tt>. Yes we lose the quick dev turnaround, but since there is a lot of Java in this project we usually have to recompile anyway which requires a restart anyway (phooey).</p>
          
          <p>As for the I/O issue, a <a href="http://www.nabble.com/JRuby-vs-MRI---Petstore-shootout-td12211276.html%20JRuby%20vs%20MRI">little digging</a> revealed that shutting up Merb as much as possible would help reduce the amount of JRuby-level IO. In our <tt>config/init.rb</tt> we configure logging like so:</p>
          
          <div class="highlight"><pre><span class="no">Merb</span><span class="o">::</span><span class="no">Config</span><span class="o">.</span><span class="n">use</span> <span class="p">{</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:environment</span><span class="o">]</span>         <span class="o">=</span> <span class="s1">&#39;production&#39;</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:framework</span><span class="o">]</span>           <span class="o">=</span> <span class="p">{},</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:log_level</span><span class="o">]</span>           <span class="o">=</span> <span class="ss">:warn</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:log_file</span><span class="o">]</span>            <span class="o">=</span> <span class="no">Merb</span><span class="o">.</span><span class="n">root</span> <span class="o">/</span> <span class="s2">&quot;logs&quot;</span> <span class="o">/</span> <span class="s2">&quot;merb.log&quot;</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:use_mutex</span><span class="o">]</span>           <span class="o">=</span> <span class="kp">false</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:session_store</span><span class="o">]</span>       <span class="o">=</span> <span class="s1">&#39;cookie&#39;</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:session_id_key</span><span class="o">]</span>      <span class="o">=</span> <span class="s1">&#39;_facet-store_session_id&#39;</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:session_secret_key</span><span class="o">]</span>  <span class="o">=</span> <span class="s1">&#39;49411912879b879e13f89a9280c0f6aaa2e3ab58&#39;</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:exception_details</span><span class="o">]</span>   <span class="o">=</span> <span class="kp">true</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:reload_classes</span><span class="o">]</span>      <span class="o">=</span> <span class="kp">false</span><span class="p">,</span>&#x000A;      <span class="n">c</span><span class="o">[</span><span class="ss">:reload_templates</span><span class="o">]</span>    <span class="o">=</span> <span class="kp">false</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>Here we set the environment to "production" again (yes, you need to do both). Also we upped the log level to "warn" which significantly reduced the amount of logging merb does. With these tweaks in place we found that the Merb port of our service was operating within about 80% of the level of performance we were getting from our pure-Java solution.</p>
          
          <p>Benchmarking was done by running <a href="http://www.hpl.hp.com/research/linux/httperf/%20httperf%20%20it's%20so%20not%20JMeter!">httperf</a> tests against the resources we expose and comparing both the number of requests per second and the average response time. Given that the options for generating XML, HTML and JSON were all so much easier than what we were doing in the servlet version, we were willing to live with the performance hit.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Rewriting History with Git
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/31/rewriting-history-with-git/' />
    <updated>
      2009-01-31T20:04:13PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/31/rewriting-history-with-git/
    </id>
    <content type='html'>
      <![CDATA[
          <p>This past week I spent some quality time with git's history-rewriting capabilities. Over the past few weeks I had been working on a rather long-lived branch full of JRuby and Merb patches. Some of the fixes and changes were ready to go in the next release, others were still a wee bit experimental and so my plan was to split the patches in two. The ones that were ready would get pushed upstream while the not-ready-for-primetime stuff stayed on a local branch.</p>
          
          <p>That seemed like a great plan until I realized just how tangled some of the patches were. It isn't difficult for this to happen. As you extend the functionality of a system, you often refine earlier work. This was especially true in my case since we were introducing JRuby to a previously Java-only project and so there was a lot of experimentation and refinement. What I was really trying to do was re-write my commit history to separate the changes. Small cleanup commits could be collapsed with others to make the entire commit-set something that my teammates could easily understand.</p>
          
          <h1>Getting Started</h1>
          
          <p>The most basic kind of re-writing you can do is simply amending your last commit. On the command line this is accomplished with <tt>git commit --amend</tt>. The bigger rewrite-hammer is <tt>git rebase -i <ref></tt>. This command will pop off all of your commits to the point specified by <tt><ref></tt>, provide you with a control file to edit and then re-apply your patches as directed.</p>
          
          <p>The control file (a term I just made up) looks kinda like this:</p>
          
          <div class="highlight"><pre>pick 1cea777 Initial introduction of Merb.&#x000A;    pick 5fe7a19 Favor XML over HTML as the <span class="s2">&quot;default&quot;</span> content-type.&#x000A;    pick 6791134 Cleaned up the <span class="s1">&#39;views&#39;</span> directory, out with the old, in with the new.&#x000A;    pick ae6adac Put lots of back-navigation links to make it nice <span class="s1">&#39;n&#39;</span> easy to use.&#x000A;    pick 1da31ca Removed last vestiges of the RestServlet-related configuration and code.&#x000A;    pick b9fe3b9 Added error views, updated error-handling and improvised content dispatch.&#x000A;    pick bf92292 Routing cleanup. This is much more pleasant to read.&#x000A;    pick ec74c63 An attempt to get RSpec working with Maven and JRuby.&#x000A;    &#x000A;    <span class="c"># Rebase 92ddc87..ec74c63 onto 92ddc87</span>&#x000A;    <span class="c">#</span>&#x000A;    <span class="c"># Commands:</span>&#x000A;    <span class="c">#  p, pick = use commit</span>&#x000A;    <span class="c">#  e, edit = use commit, but stop for amending</span>&#x000A;    <span class="c">#  s, squash = use commit, but meld into previous commit</span>&#x000A;    <span class="c">#</span>&#x000A;    <span class="c"># If you remove a line here THAT COMMIT WILL BE LOST.</span>&#x000A;    <span class="c"># However, if you remove everything, the rebase will be aborted.</span>&#x000A;    </pre>
          </div>
          
          
          <p>The top section lists all of your patches, one per line. You can edit this section to do any of the following:
          *  Reorder the commits (just move lines up or down)
          *  Edit a commit (replace "pick" with "edit" or simply "e")
          *  Remove a commit (just remove the line)
          *  Merge with a previous commit (replace "pick" with "squash" or "s")</p>
          
          <p>Think of this list like a program of execution. Once you save the file and return control to git, it will attempt to execute this program. I say <em>attempt</em> here because sometimes git runs into conflicts when it comes to re-ordering patches.</p>
          
          <h1>Editing Commits</h1>
          
          <p>When you mark a commit for editing (with "edit" or "e") git will attempt to apply all patches up to, and including that commit, and stop. This threw me at first because for some reason I had the unreasonable expectation that somehow the changes in the last commit would only be applied to the working tree and, perhaps, the index. Instead, that commit is fully applied, but all commits past that are pending. To add to my confusion, there isn't an easily accessible marker to indicate that you are in the middle of rebase (unless you frequently scan the <tt>.git</tt> directory as a matter of habit). At this point you could <em>amend</em> the commit (with <tt>git commit --amend</tt>) or insert other commits.</p>
          
          <p>Sometimes I use this just to fix up the commit message. When I'm working on a new feature that has a lot of trial-and-error I tend to mark the first commit message with "WIP" to remind myself to review that patch and the ones following to see if I can clean them up. This is an area where git really shines. In a system like Subversion your audience (other coders who look at your changes) end up walking through whatever little mini-epic you've composed as you try things out, add things and remove things. This makes for some difficult reading for consumers of those patches and so a lot of folks tend to stack up big changes and then send in the big über-commit.</p>
          
          <p>The problem with building the mega-patch is that you don't have a lot of scaffolding under you while you are building it. If you go off and explore something that doesn't turn out right, you generally have to do a lot of manual reverting. This simply sucks and is a waste of time. With git I can work in lots of incremental commits, then go back and edit them into something sensible once I'm ready to push changes.</p>
          
          <p>Once you've finished doing whatever edit you want to do for that commit, simply type <tt>git rebase --continue</tt> and the remainder of the "script" will execute. If any other "edits" are in the pipeline, the process will repeat itself until the rebase is completed.</p>
          
          <h1>Squashing Commits</h1>
          
          <p>I <em>looooove</em> squashing commits in git. For any moderately complicated work, it's rare that I get it right the first time. Usually as I go along I find some mistake I made or find a refinement that cleans up the original work. As often as not, it's usually a couple of commits away so amending the last commit isn't going to help me. But hey, no worries! I simply commit the change and leave a log message for myself to merge it with another commit. Then, when I run the interactive rebase, I can simply move this commit up the list and change it from "pick" to "squash" (or "s") and let git merge the two commits.</p>
          
          <p>When rebasing encounters a "squash" it will apply the changes in both commits. If successful, git will prompt you with a commit message file that includes the original commit messages of <em>both</em> commits. You can choose either, both or neither of these and save the file to continue.</p>
          
          <h1>Resolving Conflicts</h1>
          
          <p>Sometimes when applying a commit, git will run into conflicts and bail out on a merge. Whenever this happens to me I always have a little moment of panic as if I've broken something, but fear not&mdash;you can fix this. When this happens git tries to stage as many of the changes as it can. Any conflicts are left unstaged and need to be edited (look for the standard conflict markers), and then re-staged into the index. When you commit, git should show you the original commit message of the patch it was attempting to apply, which you can edit or keep. Once the commit succeeds, rebasing should automatically continue.</p>
          
          <h1>The Big Red Button</h1>
          
          <p>Sometimes you may just give up on a rebase. Either you can't commit the time to it, you don't really want to go through with it, or your patience has reached its limit. At any point, before the rebase has completed, you can execute <tt>git rebase --abort</tt> and your working tree, index and commit-log will all be returned to the state prior to starting the rebase. Think of this as the big red "stop" button for rebasing.</p>
          
          <h1>Playing Fast and Loose with Branches</h1>
          
          <p>If you come from other SCM systems like Subversion, you tend to treat branches as expensive and something you only use on occasion. With git, branches are cheap and easy like drinks in Tijuana. Be fearless! Not sure about some exploration? Make a branch!</p>
          
          <p>If rebasing makes you nervous, and you're not entirely confident that aborting will save you, I suggest creating a branch on which to rebase. Simply create a new branch from where you're at with <tt>git checkout -b <branch></tt>. You'll be immediately switched to that branch with your commit log looking exactly like the branch you came from. Here you can rebase, edit, remove, add and generally go crazy with your commits.</p>
          
          <p>Once you've got your commits where you want them it's simply a matter of getting them back into whatever you consider your "main" branch to be and pushing any changes upstream. This works really well when you have rendez-vous point like a Github repo or an SVN server (we do a lot of git on top of Subversion at work). Assuming that you've been adding changes on your master branch, you might create a new branch off of <tt>master</tt> that you might call <tt>exp</tt>. On the <tt>exp</tt> branch you might rebase and wreak all sorts of havoc on the commit log. Once you have your commits where you want them, switch back to your <tt>master</tt> branch and reset it to point to the head of your upstream repo. If you're using git all the way, simply merge your <tt>exp</tt> branch over. If you're running git on top of Subversion, simply cherry-pick the commits on the <tt>exp</tt> branch (in order!!!) and push the changes upstream.</p>
          
          <p>It's hard to stress how important it is to shift your mindset into thinking in terms of sharing patches. Treat your commits like individual, digestible changes. Even if you're working by yourself or in a small team, I still think there's value in being disciplined with your commits.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Opening The Gates&#8230;of Hell!!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/' />
    <updated>
      2009-01-27T06:01:11PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/
    </id>
    <content type='html'>
      <![CDATA[
          <p>&hellip;umm, no, actually not so much.</p>
          
          <p><img src="/images/2009/01/hellboy.jpg" class="left"/></p>
          
          <p>Instead, this is just a humble little notice about a <a href="http://github.com/alexvollmer/daemon-spawn/tree/master%20daemon-spawn">humble little gem</a> I put together today. It's called <em>daemon-spawn</em> and despite its simply terrifying name, it's really here to help all mankind. You see, I've been working like mad to stuff Merb smack-dab in the middle of an embedded Jetty project I've been working on. One of the last things I needed was a decent daemon-launcher/management gem-thingie to make it happen.</p>
          
          <p>I cast about for an existing solution and found each a little lacking. The <a href="http://daemons.rubyforge.org/%20Ruby%20Daemons">daemons</a> gem had the executable name hard-wired to the output log name and didn't give me a clean way to specify additional arguments to JRuby (unless I wrote <em>another</em> wrapper script, to which I say "boo, hiss"). Then I looked at <a href="http://simple-daemon.rubyforge.org/%20simple-daemon">simple-daemon</a> which seemed really promising. It was really really close to what I wanted but didn't extend very well as it required more and more class-methods. Yuck. I looked at <a href="http://kylemaxwell.typepad.com/everystudent/2006/08/after_writing_r.html%20daemon_generator">daemon_generator</a>, but it was very Rails-y and wanted to generate a bunch of code for me, which I didn't need. So I did what any honest, hard-working Ruby-dork does, and <em>made my own!</em></p>
          
          <p>It's simple&mdash;dead simple. Wanna see how simple? Here's a real-live echo server with daemon support:</p>
          
          <div class="highlight"><pre><span class="c1">#!/usr/bin/env ruby</span>&#x000A;    &#x000A;    <span class="nb">require</span> <span class="s1">&#39;daemon-spawn&#39;</span>&#x000A;    <span class="nb">require</span> <span class="s1">&#39;socket&#39;</span>&#x000A;    &#x000A;    <span class="k">class</span> <span class="nc">EchoServer</span> <span class="o">&lt;&lt;</span> <span class="no">DaemonSpawn</span><span class="o">::</span><span class="no">Base</span>&#x000A;    &#x000A;      <span class="kp">attr_accessor</span> <span class="ss">:server_socket</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>&#x000A;        <span class="n">port</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">empty?</span> <span class="p">?</span> <span class="mi">0</span> <span class="p">:</span> <span class="n">args</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">to_i</span>&#x000A;        <span class="nb">self</span><span class="o">.</span><span class="n">server_socket</span> <span class="o">=</span> <span class="no">TCPServer</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;127.0.0.1&#39;</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span>&#x000A;        <span class="n">port</span> <span class="o">=</span> <span class="nb">self</span><span class="o">.</span><span class="n">server_socket</span><span class="o">.</span><span class="n">addr</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span>&#x000A;        <span class="nb">puts</span> <span class="s2">&quot;EchoServer started on port </span><span class="si">#{</span><span class="n">port</span><span class="si">}</span><span class="s2">&quot;</span>&#x000A;        <span class="kp">loop</span> <span class="k">do</span>&#x000A;          <span class="k">begin</span>&#x000A;            <span class="n">client</span> <span class="o">=</span> <span class="nb">self</span><span class="o">.</span><span class="n">server_socket</span><span class="o">.</span><span class="n">accept</span>&#x000A;            <span class="k">while</span> <span class="n">str</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">gets</span>&#x000A;              <span class="n">client</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">str</span><span class="p">)</span>&#x000A;            <span class="k">end</span>&#x000A;          <span class="k">rescue</span> <span class="no">Errno</span><span class="o">::</span><span class="no">ECONNRESET</span> <span class="o">=&gt;</span> <span class="n">e</span>&#x000A;            <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Client reset connection&quot;</span>&#x000A;          <span class="k">end</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nf">stop</span>&#x000A;        <span class="nb">puts</span> <span class="s2">&quot;Stopping EchoServer...&quot;</span>&#x000A;        <span class="nb">self</span><span class="o">.</span><span class="n">server_socket</span><span class="o">.</span><span class="n">close</span> <span class="k">if</span> <span class="nb">self</span><span class="o">.</span><span class="n">server_socket</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="no">EchoServer</span><span class="o">.</span><span class="n">spawn!</span><span class="p">(</span><span class="ss">:working_dir</span> <span class="o">=&gt;</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">),</span> <span class="s1">&#39;..&#39;</span><span class="p">),</span>&#x000A;                      <span class="ss">:log_file</span> <span class="o">=&gt;</span> <span class="s1">&#39;/tmp/echo_server.log&#39;</span><span class="p">,</span>&#x000A;                      <span class="ss">:pid_file</span> <span class="o">=&gt;</span> <span class="s1">&#39;/tmp/echo_server.pid&#39;</span><span class="p">,</span>&#x000A;                      <span class="ss">:sync_log</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">,</span>&#x000A;                      <span class="ss">:singleton</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>But what if you have non-Ruby code you want to daemonize? Well my friends, that's what <code>Kernel#exec</code> is for and it works like a champ. See the README for the full details. And of course to view the README, you have to install the gem which means you have <em>daemon-spawn</em> in the bowels of your machine! Mwaaa haa haa haa! Oops&hellip;I've said too much&hellip;</p>
          
          <p>In all seriousness though, I would like to thank the powers-that-be at <a href="http://www.evri.com%20Evri!!">work</a> who were very gracious to let me open-source this. You should start seeing more of this kind of stuff from Evri soon. As always, your feedback, comments, critiques and patches are welcome.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Ruby Threads Suck&#8230;Just Not The Way You Think They Do
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/26/ruby-threads-suckjust-not-the-way-you-think-they-do/' />
    <updated>
      2009-01-26T01:47:24PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/26/ruby-threads-suckjust-not-the-way-you-think-they-do/
    </id>
    <content type='html'>
      <![CDATA[
          <p>At <a href="http://www.evri.com%20Evri!!">work</a>, we do a lot of scheduled tasks in which we process a "chunk" of data within a particular time-period. For example, we may tail log files, parse the lines and publish summary statistics "up-stream" on a fixed schedule of, say, ten minutes. Similarly, last week we were working on a Ruby wrapper script that launches <a href="http://www.danga.com/memcached/%20memcached">memcached</a> and maintains a registration lease within a home-grown registration service we run. The script needs to launch memcached, then periodically check it and renew its registration lease.</p>
          
          <p>We have a RubyGem written to handle registration and renewal that hides the HTTP and XML message bodies away from the user. You simply create a client, setup your initial registration and tell it to keep you registered.</p>
          
          <div class="highlight"><pre><span class="nb">require</span> <span class="s2">&quot;rubygems&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;radar_love&quot;</span>&#x000A;    <span class="n">client</span> <span class="o">=</span> <span class="no">Radar</span><span class="o">::</span><span class="no">Client</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&quot;http://radar-dev&quot;</span><span class="p">)</span>&#x000A;    <span class="n">service</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="s1">&#39;foobar&#39;</span><span class="p">,</span> <span class="s1">&#39;http://foobar:1234&#39;</span><span class="p">)</span>&#x000A;    <span class="n">service</span><span class="o">.</span><span class="n">keep_registered</span> <span class="c1"># fires up background thread</span>&#x000A;    </pre>
          </div>
          
          
          <p>That last line is implemented with a Ruby thread that loops indefinitely, sleeping and then renewing the registration lease. But a funny thing happened while implementing this. When we just fired up <code>irb</code> and tried to run this part (without doing any other work), the re-registration thread <em>never</em> executed. Man, I had heard that MRI threads were "broken", but this is completely non-functioning!</p>
          
          <p>Then I remembered a <a href="http://spec.ruby-doc.org/wiki/Ruby_Threading%20Ruby%20Threading%20Spec">very handy page</a> I ran across once about MRI Threading. This page is worth spending a little time with, but essentially because MRI threads are so-called "green threads" they aren't really giving you true concurrent processing. Instead they are merely a context-switching mechanism, and the circumstances under which those switches can happen are described in that spec page.</p>
          
          <p>In the case of our little <code>irb</code> session, the re-registration thread only began executing when we did something in the main thread. We weren't executing anything in the main thread that triggered one of these context-switches (remember, we're merely sitting at an irb prompt waiting for the next line). So getting the runtime to execute a context-switch merely required us to do <em>something</em> in the main thread:</p>
          
          <div class="highlight"><pre><span class="kp">loop</span> <span class="k">do</span>&#x000A;      <span class="nb">puts</span> <span class="s2">&quot;Howdy!&quot;</span>  &#x000A;      <span class="nb">sleep</span> <span class="mi">5</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>You may shake your head and mutter something derisive about this "hack". However, in reality, requiring your main thread to do something isn't terribly burdensome. If you didn't have any work to do in your main thread, you'd have to ask yourself why you created a separate thread in the first place!</p>
          
          <p>You may also think that since MRI threads don't provide true concurrency, they're worthless. One major limitation of green threads in MRI is that no matter how many you start, they will only execute on one processor. If you have a large multi-core machine, MRI threads will <em>not</em> be able to take advantage of them.</p>
          
          <p>However, that doesn't mean threads don't have their place in MRI environments. In the first example I mentioned (tailing logs and publishing summaries) we use a separate thread for the publishing activity. We <em>could</em> have done this entire action in a single loop, but the major downside is that we would essentially be relying on new lines in our log to appear to "crank" the mechanism forward. If we go a long time before we see another log line, our summary task will fail to execute.</p>
          
          <div class="highlight"><pre><span class="no">IO</span><span class="o">.</span><span class="n">popen</span><span class="p">(</span><span class="s2">&quot;tail -F /var/log/some.log&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>&#x000A;      <span class="n">update_statistics</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>&#x000A;      <span class="k">if</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span> <span class="o">&gt;=</span> <span class="n">next_report_time</span>&#x000A;        <span class="c1"># we might not get here for a while unless the</span>&#x000A;        <span class="c1"># log lines keep coming</span>&#x000A;        <span class="n">report_statistics</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>It would certainly be possible to read from the file with a timeout that is based on how much time is left before the next reporting period. However at that point the code starts to get a little cluttered, so we go with the threaded approach only to take advantage of its context-switching properties. In our case, this is a perfect solution for what we're trying to accomplish.</p>
          
          <p>If you come from a Java or .NET background, you may find that MRI threads fail to measure up to threading in those environments. It's absolutely true that MRI does not provide the same robust threading mechanisms that those languages do (<a href="http://spec.ruby-doc.org/wiki/JRuby_Threading%20JRuby%20Threading">JRuby</a>, and perhaps IronRuby, being special cases). It doesn't mean that threads in MRI are worthless, you just need to <a href="http://www.infoq.com/news/2007/05/ruby-threading-futures%20Ruby%20Threading">understand them</a> properly to know when to use them.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Meet Magit!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/18/meet-magit/' />
    <updated>
      2009-01-18T20:58:06PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/18/meet-magit/
    </id>
    <content type='html'>
      <![CDATA[
          <p>In the spirit of Geoffrey Grossenbach's <a href="http://peepcode.com/products/meet-emacs%20Meet%20Emacs">Meet Emacs Peepcode Screencast</a>, I put together my own humble little screencast this weekend on <a href="http://zagadka.vm.bytemark.co.uk/magit/magit.html%20Magit">magit</a>, a fantastic <a href="http://git-scm.com%20Git">git</a> mode for Emacs.</p>
          
          <p><object width="400" height="300" data="http://vimeo.com/moogaloop.swf?clip_id=2871241&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash"></object>
          <a href="http://vimeo.com/2871241">Meet Magit</a> from <a href="http://vimeo.com/alexvollmer">Alex Vollmer</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
          
          <p>It's not meant to be an exhaustive survey of magit (check the <a href="http://zagadka.vm.bytemark.co.uk/magit/magit.html%20Magit%20User%20Manual">docs</a> for all the details), but to show off some of the cool features this mode has. I found that spending just a little time with docs and learning this mode has already paid off in terms of increasing my productivity. Enjoy!</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 1.0.1 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/07/clip-version-101-has-been-released/' />
    <updated>
      2009-01-07T02:58:13PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/07/clip-version-101-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why
          should you have to create a Hash, then create a parser, fill the Hash
          out then throw the parser away (unless you want to print out a usage
          message) and deal with a Hash? Why, for Pete's sake, should the parser
          and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>1.0.1 / 2009-01-06</h3>
          
          <ul>
          <li>Fixed a bug where generating help resulted in an infinite-loop</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          ActiveRecord, Associations and Counters
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/04/activerecord-associations-and-counters/' />
    <updated>
      2009-01-04T22:39:21PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/04/activerecord-associations-and-counters/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Maybe this is old hat to all you grizzled vets out there, but today I thought I'd post about my experience with ActiveRecord's counter caches and the tricks I had to pull to get it working. Let me first set the stage with what I was trying to accomplish.</p>
          
          <p>In <a href="http://moochbot">moochbot</a>, your main transaction screen has a standard tabbed-interface. Each tab is a different view of all your transactions. In a tabbed display you can only show one view at a time so it helps the user when you can provide some hints in the non-selected tabs. Anything that helps them figure out whether or not they want to click on something <em>without actually having to click on it</em> is, in my opinion, a great help.</p>
          
          <p><img src="http://img.skitch.com/20090104-xi79khd8e9242dhbf5yes6nmg6.jpg" alt="Moochbot Tabs" /></p>
          
          <p>So I wanted to add a number in the tab to indicate how many items were there. The most na&iuml;ve way to implement this would be to issue three different SQL statements for the counts. However somewhere, in the back of my mind, I remembered that ActiveRecord has a feature known as the <em>counter cache</em>. The basic idea is to hook some additional code into the lifecycle of ActiveRecord's associations to update a single column in the parent record as you add and remove child records.</p>
          
          <p>Like an iceberg, the bulk of this feature lay deep below the surface. The actual view-layer changes were minimal, but I had to jump through some hoops to get the counter-cache working correctly.</p>
          
          <p>In moochbot, a <code>User</code> model object has multiple <code>Transaction</code> records. Each <code>Transaction</code> points at two separate <code>User</code> records: one for the lender and one for the borrower. All of a user's transactions are stored in the <code>TRANSACTIONS</code> table, each record differentiated by the <code>STATE</code> column.</p>
          
          <p>In ActiveRecord-land we express these relationships in the model with <em>three</em> <code>has_many</code> relations for the <code>User</code>: one for items they are lending, one for items they are borrowing and all closed transactions. The first two are fairly straight-ahead:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>&#x000A;    &#x000A;      <span class="n">has_many</span><span class="p">(</span><span class="ss">:lent_items</span><span class="p">,</span>&#x000A;               <span class="ss">:class_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;Transaction&quot;</span><span class="p">,</span>&#x000A;               <span class="ss">:foreign_key</span> <span class="o">=&gt;</span> <span class="s2">&quot;lender_id&quot;</span><span class="p">,</span>&#x000A;               <span class="ss">:conditions</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s2">&quot;state IN (?)&quot;</span><span class="p">,</span>&#x000A;                               <span class="sx">%w(started lent returned overdue disputed)</span><span class="o">]</span><span class="p">)</span>&#x000A;    &#x000A;      <span class="n">has_many</span><span class="p">(</span><span class="ss">:borrowed_items</span><span class="p">,</span>&#x000A;               <span class="ss">:class_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;Transaction&quot;</span><span class="p">,</span>&#x000A;               <span class="ss">:foreign_key</span> <span class="o">=&gt;</span> <span class="s2">&quot;borrower_id&quot;</span><span class="p">,</span>&#x000A;               <span class="ss">:conditions</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s2">&quot;state IN (?)&quot;</span><span class="p">,</span>&#x000A;                               <span class="sx">%w(started lent returned overdue disputed)</span><span class="o">]</span><span class="p">)</span>&#x000A;    &#x000A;      <span class="n">has_many</span><span class="p">(</span><span class="ss">:completed_items</span><span class="p">,</span>&#x000A;               <span class="ss">:class_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;Transaction&quot;</span><span class="p">,</span>&#x000A;               <span class="ss">:finder_sql</span> <span class="o">=&gt;</span> <span class="s1">&#39;SELECT * &#39;</span> <span class="o">+</span>&#x000A;               <span class="s1">&#39;FROM transactions &#39;</span> <span class="o">+</span>&#x000A;               <span class="s1">&#39;WHERE state IN (\&#39;aborted\&#39;, \&#39;finished\&#39;) AND &#39;</span> <span class="o">+</span>&#x000A;               <span class="s1">&#39;(borrower_id = #{id} OR lender_id = #{id})&#39;</span><span class="p">)</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>However the third relationship requires some custom SQL because we want all records that are in either the "finished" or "aborted" state <em>and</em> where the user is <em>either</em> the lender or the borrower. I looked into doing this with a simple <code>:conditions</code> option on the <code>has_many</code> relationship, but couldn't figure out how to specify the ID of the user.</p>
          
          <p>One <em>really important</em> thing to recognize here is that the SQL is quoted with single-quotes. If the SQL is specified in double-quotes, the interpolation is evaluated <em>too early</em> and the id value is <em>not</em> the user record. Putting it in single-quotes defers evaluation until the proper time. I wish this were documented a little better because I was completely stuck until I stumbled across <a href="http://railsblaster.wordpress.com/2007/08/27/has_many-finder_sql/%20has_finder%20SQL">this post</a> on the <a href="http://railsblaster.wordpress.com%20RailsBlaster">RailsBlaster</a> blog. I had to enable debug-level logging for ActiveRecord to see that I was getting skooky IDs in my final SQL string.</p>
          
          <p>To add a counter cache to the User record, you declare a <code>:counter_cache</code> option on the reciprocal <code>belongs_to</code> relationship. This seemed counter-intuitive to me since if I didn't already have one in place, I'd have to add one. It seemed more obvious to me to put it in the <code>has_many</code> relationship but that ain't the way ActiveRecord rolls. So the next step was to update the <code>belongs_to</code> mappings in the <code>Transaction</code> class:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">Transaction</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>&#x000A;    &#x000A;      <span class="n">belongs_to</span><span class="p">(</span><span class="ss">:lender</span><span class="p">,</span>&#x000A;                 <span class="ss">:class_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;User&quot;</span><span class="p">,</span>&#x000A;                 <span class="ss">:foreign_key</span> <span class="o">=&gt;</span> <span class="s2">&quot;lender_id&quot;</span><span class="p">,</span>&#x000A;                 <span class="ss">:counter_cache</span> <span class="o">=&gt;</span> <span class="ss">:lent_items_count</span><span class="p">)</span>&#x000A;    &#x000A;      <span class="n">belongs_to</span><span class="p">(</span><span class="ss">:borrower</span><span class="p">,</span>&#x000A;                 <span class="ss">:class_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;User&quot;</span><span class="p">,</span>&#x000A;                 <span class="ss">:foreign_key</span> <span class="o">=&gt;</span> <span class="s2">&quot;borrower_id&quot;</span><span class="p">,</span>&#x000A;                 <span class="ss">:counter_cache</span> <span class="o">=&gt;</span> <span class="ss">:borrowed_items_count</span><span class="p">)</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>The final step was to create a migration that would add the counter cache columns to the <code>USERS</code> table. Note that not only do we add the columns, but we also update everyone's counters.</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">AddCounterCacheToUsers</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span>&#x000A;      <span class="no">COLUMNS</span> <span class="o">=</span> <span class="o">[</span><span class="ss">:lent_items_count</span><span class="p">,</span>&#x000A;                 <span class="ss">:borrowed_items_count</span><span class="p">,</span>&#x000A;                 <span class="ss">:completed_items_count</span><span class="o">]</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">up</span>&#x000A;        <span class="no">COLUMNS</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">add_column</span> <span class="ss">:users</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="ss">:integer</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="mi">0</span>&#x000A;        <span class="k">end</span>&#x000A;    &#x000A;        <span class="no">User</span><span class="o">.</span><span class="n">reset_column_information</span>&#x000A;    &#x000A;        <span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="ss">:all</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span>&#x000A;          <span class="no">User</span><span class="o">.</span><span class="n">update_counters</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>&#x000A;                               <span class="ss">:lent_items_count</span> <span class="o">=&gt;</span> <span class="n">user</span><span class="o">.</span><span class="n">lent_items</span><span class="o">.</span><span class="n">length</span><span class="p">,</span>&#x000A;                               <span class="ss">:borrowed_items_count</span> <span class="o">=&gt;</span> <span class="n">user</span><span class="o">.</span><span class="n">borrowed_items</span><span class="o">.</span><span class="n">length</span><span class="p">,</span>&#x000A;                               <span class="ss">:completed_items_count</span> <span class="o">=&gt;</span> <span class="n">user</span><span class="o">.</span><span class="n">completed_items</span><span class="o">.</span><span class="n">length</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">down</span>&#x000A;        <span class="no">COLUMNS</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">remove_column</span> <span class="ss">:users</span><span class="p">,</span> <span class="n">c</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>So there it is. Hopefully that helps the next poor sod that runs into that same problem.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The Fast and the Quick
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/01/01/the-fast-and-the-quick/' />
    <updated>
      2009-01-01T16:39:38PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2009/01/01/the-fast-and-the-quick/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img alt="Walter Payton" src="http://media-2.web.britannica.com/eb-media/91/95591-004-36D62DDD.jpg" class="left"/></p>
          
          <p>I've been a football fan since I was about five years old. I have studied this game for almost thirty years, so forgive me if I bore you all with a trite football analogy. This is the old saw known as "fast vs. quick". Players like Barry Sanders or Walter Payton were "quick", but not necessarily fast. In general, "fast" guys are wide receivers and corner-backs (the guys that cover the receivers). Receives generally have further to run than running backs, so they need what is called "breakaway speed" which is enough raw power to get away from the defender covering them.</p>
          
          <p>Running backs however, need a combination of strength and the ability to move their bodies very quickly in a very small space. The difference between a gain of one or two yards and a breaking-off a twenty-yard run is usually a matter of inches. The runner has to be in just the right place at just the right moment and get just the right kind of blocking from his teammates. Quickness is the ability to shift weight, turn the body and plant a foot just a fraction of second faster than the next guy. It's what separates the good from the truly great.</p>
          
          <p>Hall of Fame running backs rarely survive on pure speed alone. Heck, most backs that were "burners" in college are usually forced to play another position at the professional level. Those that try to rely on pure brawn to break tackles generally don't last long (see, Eddie George, Priest Holmes or any back that has played in Denver in the last decade). The really great ones have that ethereal quality known as "quickness".</p>
          
          <p>So, I was thinking lately about "agile" in the software world and what it really means. The term <em>agile</em>, isn't clear enough&mdash;it could be fast or it could be quick. But which really matters? Which is the quality you really want to have?</p>
          
          <p>My answer? You want the agility associated with <em>quickness</em>, not raw speed. Being "quick" in software might look like:
          *  New requirements are handled in-stride and rarely, if ever, with The Big Re-Write
          *  The time to produce a meaningful feature is measured in hours or days, not weeks
          *  The time to produce a meaningful <em>release</em> is measured in days or weeks, not months
          *  The system almost <em>never</em> looks like the original design</p>
          
          <p>OK, so what would "fast" look like? Well&hellip;
          *  Releases are buggy
          *  Few if any tests
          *  Code diarrhea
          *  Quality is inconsistent
          *  There are lots of dependencies
          *  New requirements are an exercise in hammering reality into fixed model</p>
          
          <p>Actually, none of those sound particularly "fast" to me.</p>
          
          <p>When folks complain about the ineffectiveness of "Agile", I sometimes wonder if they aren't simply confusing fast with quick. There isn't any methodology or toolset I know of that will make you <em>faster</em>. Your raw speed is determined more or less by the skill of your team. Each member transfers a concept into code at a relatively consistent rate, so you simply aren't going to go any faster unless you change your team. However I think you <em>can</em> acquire new skills to improve your quickness.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Flaccid Attitudes
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/23/flaccid-attitudes/' />
    <updated>
      2008-12-23T05:47:54PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/23/flaccid-attitudes/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Today I had an impromptu conversation with a total stranger at my local caf&#233; that got me thinking. He saw that I was working on some code and asked me what I was doing. I gave him the thirty-second whirlwind tour of Ruby and briefly explained what I was working on.</p>
          
          <p>He came from the .net side of things and had been doing contracting for quite awhile. Recently though, his shop closed up and he was between gigs. He hadn't been exposed to Ruby and thought it sounded kind of interesting. He was, as he put it, "a Windows-guy", but basically apologized for it saying that "everyone around here" runs Windows. <em>Really? You mean like the four-out-of-five-laptops that are Macs in this caf&#233;??!!! (</em>Note to self: this fella doesn't seem too observant.)</p>
          
          <p>So while I was trying to politely end the conversation to get back to my hacking and an IRC-meeting, he rambled on about his personal work philosophy. God knows how long he droned on, but his M.O. essentially boiled down to <em>"Hey I don't care what I work on. Languages are all the same, why fuss over this one or that one?"</em></p>
          
          <p>It stopped me in my tracks.</p>
          
          <p>Are you kidding me?</p>
          
          <p>Look, there is something laudable (in a kind of John-and-Yoko-stay-in-bed-for-peace way) about The Big World view where all the geeks get along and sing side by side at the great binary campfire. At a certain level arguing over this language vs. that language or this tool or that operating system is frivolous waste of time. Much of our "values" in these things are based merely on opinions, aesthetics and feelings. It's like mailing list arguments over whether or not the Enterprise could defeat the Galactica. <em>Ladies and Gentleman on your left is Dork City&#8230;</em></p>
          
          <p>But what this really told me more than anything else was that this guy was simply <em>indifferent</em>. You don't have to agree with my way of doing things, but when we talk about them I at least expect you to have an opinion and to be able to back that up with some reasoning. This guy's indifference stemmed from the fact that he treated this like a <em>job.</em></p>
          
          <p>"Passion" is a word that is overused in this biz. Every time I'm in a debrief about some candidate and the notion of "passion" comes up I started checking the room for forks to shove in my eyes. I don't care about passion for The Company or The Idea. That's rah-rah B.S. that I have no stomach or patience for. What I <em>do</em> want to see in a co-worker is someone who cares about what they work on and how they do it. <em>This</em> is your day-to-day existence. <em>This</em> is what you spend a lot of waking hours doing, being away from your loved ones. You damn-well better care about how you want to spend that time.</p>
          
          <p>If you wanted to fail spectacularly in a job interview with me, one way to score a boat-load of demerit-points quickly is give an indifferent answer to the question, "What do you like to work on?" When people shrug their shoulders and say, "Oh, I'll work on anything", it tells me that they don't care. The pay is the same, so why fuss over the details?</p>
          
          <p>Now I understand that some interviewees won't give me a straight answer because they <em>expect</em> that I want the answer an automaton would give. There are certainly plenty of shops that just want "human capital" in much the same way generals in WWI wanted troops (see fodder, cannon). But even so, I'm not sure that's the kind of person I want on my team. Show a little back-bone for pete's sake! Do you do this job just because it pays the bills? Are you so beaten-down by the industry and your experiences that you have no hope of it ever getting better? Are you just trudging forward in your profession because you don't know what else to do?</p>
          
          <p>I don't care so much whether or not we agree on tools, languages or operating systems, but I hope to God you care about how you spend your time on this earth in this profession. Don't sleepwalk through it.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Burning My Ships
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/21/burning-my-ships/' />
    <updated>
      2008-12-21T03:40:56PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/21/burning-my-ships/
    </id>
    <content type='html'>
      <![CDATA[
          <blockquote><p> When Columbus reached the New World, he burned his ships. As a result his men were well-motivated.</p></blockquote>
          
          <p><a href="http://www.amazon.com/Hunt-Red-October-Blu-ray/dp/B001AII4SQ%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB001AII4SQ"><img src="http://ecx.images-amazon.com/images/I/51x%2B1Yxrb9L._SL160_.jpg" class="left"/></a></p>
          
          <p>This quote comes from the character of Marko Ramius, as played by Sean Connery, from one of my all-time favorite films, "The Hunt for Red October". I love that quote in particular because I always think of it whenever I decide to tweak my process, my work environment or my tools. For all but the most trivial changes, you usually have to immerse yourself in it. So I usually "burn my ships" by leaving behind the old way of doing things to really burn the new way into my brain.</p>
          
          <p>Sometimes the new way turns out to not be so great. That's fine because that's a satisfactory result of the experiment. If the "new way" turns out to suck, there's just as much to learn (if not more) from a real crash-and-burn than success.</p>
          
          <p>The first big "ship-burning" I did was very early in my career. I had been a few months into my professional developer career doing Java and decided that I really liked this Unix thing. So I completely wiped out my Windows NT work box and put one of the first versions of Red Hat on there. I figured if I was going to get good at Linux I was going to have to just jump in the deep end of the pool and learn to swim.</p>
          
          <p>It turned out to be an absolutely wonderful decision. Throughout the years I moved through several distributions: Red Hat to Mandrake to Gentoo to Ubuntu. Each new distribution taught me something more about Linux than I knew before (especially true for Gentoo).</p>
          
          <p>I've done the same trick with editors too. When I first started out I used <em>vi</em> for my Java development. I tried using the first IDEs (JBuilder, etc.) but they were all terrible. Plus, at that time a serious Java IDE for Linux was still a twinkle in Erich Gamma's eye. I had a co-worker who was an XEmacs power-user and it looked like he got a lot done so I figured I'd give it a go&#8212;especially since I had on-site technical support. This was my first experience with Emacs and I never really got beyond basic editing. I wrote a couple of macros but that was about it.</p>
          
          <p>Then NetBeans rolled around and I was more than happy to start using it. I had a decent intellisense feature and built-in Ant integration, both of which were a significant step forward to me. I ran with that for a couple of years until I started a new job where everyone was using this new-fangled thing called Eclipse. I tried to hold-out with NetBeans for a while, but after watching some others pull off some seriously cool tricks in Eclipse I knew it was time to give it a go. I've ridden that Eclipse horse for damn-near six years and I'd be willing to put my knowledge of Eclipse-editing arcana up against anyone.</p>
          
          <p>Several years laster, on the operating system front, another big change was coming. I had been a die-hard Linux fan since my switch back in the Old Days, but by winter of 2005 I had run into a tangled knot of Linux-related headaches that really sapped the fun out of it for me. Between home servers and 64-bit laptop (in 2005!) I spent more time just trying to keep my machines up to date and running than actually getting anything productive done. However, it wasn't until I went to my first Seattle Ruby Brigade meeting (when everyone there had a Mac) that I seriously considered switching operating systems.</p>
          
          <p>This was the same time that I discovered Ruby. What attracted me to the language was not only the beauty of the syntax, but the underlying philosophies of pragmatism, simplicity and no-bullshit attitude. There seemed to be a similar attitude in Mac users and I found this approach appealing. This is not a knock on Linux. I <em>love</em> Linux, I just don't want to use it for my desktop OS anymore. I don't have the patience to fiddle with things that much anymore. I have lots of ideas and I'll never get anywhere if I get bogged-down with irrelevant minutiae and yak-shaving.</p>
          
          <p>When I switched to the Mac I got myself a license for TextMate which has definitely been the editor-of-choice for lots of Rubyists. However, <a href="http://livollmers.net/index.php/2008/10/06/back-to-myemacs/%20Back%20to%20My%20Emacs">as I blogged about before</a>, it's now time to get off the TM-train and switch (back) to Emacs.</p>
          
          <p>So what's the point of all of this? Am I just thrashing? Am I desperately throwing myself at each and every new tool on the block? You might think so, but I actually have <em>some</em> discriminating taste. I do try out <em>a lot</em> of tools because I'm always looking for some kind of edge, anything that I can leverage to get stupid busy-work out of the way. As I get older I have less and less patience for this sort of thing for <em>productivity taxes</em>. I just want to get something important done.</p>
          
          <p>So, from time to time, a little alarm goes off inside my brain to remind me that it's time for a change. Sometimes it's something as simple as changing my terminal or editing font. Other times it's things like learning a <a href="http://erlang.org/%20Erlang">new</a> <a href="http://developer.apple.com/cocoa/%20Cocoa">language</a>. Regardless, all of these things keep me from getting mentally lazy. Once I get mentally complacent, it's game over. So consider if perhaps it's time to "burn some ships" just keep things interesting.</p>
          
          <p><img alt="Changed my keys around to Dvorak" src="http://farm4.static.flickr.com/3006/3113807315_77d2aa278c_m.jpg" class="right"/></p>
          
          <p>Good heavens, some day I may even do something as crazy as switch to a Dvorak keyboard layout. That just might make my head explore&#8212;in a good way.</p>
          
          <div style="clear: both;"></div>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          A Tale of Sandwiches and Happiness
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/18/a-tale-of-sandwiches-and-happiness/' />
    <updated>
      2008-12-18T18:44:11PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/18/a-tale-of-sandwiches-and-happiness/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="http://farm4.static.flickr.com/3228/3096590905_8ccb3341e4_m.jpg" class="left"/></p>
          
          <p>Yesterday the city of Seattle was paralyzed by the fear of snow (which arrived today). As a result downtown was a ghost-town. That meant that we could get sandwiches from <a href="http://www.salumicuredmeats.com/%20Salumi!%20Yum!">Salumi</a> (one of Seattle's culinary gems) in less than the usual hour-long wait.</p>
          
          <p>Even on a "quiet" day, the process still took about thirty minutes to order, receive and pay for our sandwiches. As we walked back to the office we started chatting about ways they could be faster. They could make sure that people are paying as quickly as they are getting their sandwiches made. They could make sure that the full menu is displayed further back in the line so customers know what they want as they arrive.</p>
          
          <p>We even ranked some of the local sandwich shops in terms of speed. If you want an incredible sandwich and have the time, Salumi is hard to beat. Next up would be our beloved <a href="http://www.tatsdeli.com/%20Cheesesteaks%20in%20Seattle!">Tat's</a>. Finally, you can go to a chain place, like Jimmy John's, and get a decent corporate sandwich in unbelievable time.</p>
          
          <p>So then I asked myself the question, "why doesn't Salmui try to go any faster?" Wouldn't their customers be happier? The lines are ridiculous at times and you can blow a whole lunch-hour just on getting a sandwich. The place is tiny too. It's near-impossible to eat it there because of the wait for a table. Wouldn't they like a bigger location to service more customers?</p>
          
          <p>And then it hit me: they don't go any faster and they don't grow any bigger because it wouldn't make them any <em>happier</em> to do so. The folks behind the counter clearly love what they're doing. It's not that they're indifferent to their customers, it's that they seem to be doing quite well the way things are and don't feel a need to "grow". I think there's something very laudable in that attitude.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Just Having Fun
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/16/just-having-fun/' />
    <updated>
      2008-12-16T06:04:28PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/16/just-having-fun/
    </id>
    <content type='html'>
      <![CDATA[
          <p>After spending nearly all of my spare hours on <a href="http://moochbot.com%20moochbot%20%E2%80%94%20track%20what%20you%20lend%20and%20borrow">moochbot</a>, it was fun to take a lighter turn this week. Today I put up <a href="http://isthatfreedomrock.com%20Freedom%20Rock!!">http://isthatfreedomrock.com</a>. If you are lucky enough to have watched cable in the late 80's you might remember a TV ad in which two hippies sit in front of a VW bus doing their best Cheech &amp; Chong routine. One hippy says to another, "is that freedom rock? Then turn it up!" I don't know why, but that has <em>always</em> been funny to me. It's just so&#8230;stupid. Can you imagine the ad execs sitting around the table thinking this one up?</p>
          
          <p>Anyway, one day it occurred to me that it would be funny (to me at least) to have a very simple, <a href="http://kottke.org/08/02/single-serving-sites">single-serving site</a> that told you whether a certain song or artist was, in fact, Freedom Rock. Note the capital letters. I'm not talking Toby Keith "freedom rock" with waving flags in the background and lots of shiny pickup trucks. I'm talking about the rather odd, rag-tag collection of songs that made it to this album. Try playing with the site a bit, then check out the <a href="http://www.urbandictionary.com/define.php?term=Freedom+Rock%20Freedom%20Rock">Urban Dictionary's entry on Freedom Rock</a>.</p>
          
          <p>This leads to one of the pillars of my personal philosophy:</p>
          
          <blockquote><p>Amuse yourself first, worry about your audience later.</p></blockquote>
          
          <p>I wrote this primarily because it make me laugh&#8230;a lot. I don't know why. It's dumb, it's juvenile and it's <em>totally</em> worth the $10 I paid to register the domain-name.</p>
          
          <p>But stupid-hippy jokes don't make up the whole picture. The other half of this fun little excursion was figuring out how to do this with as little code as possible. At first I wrote this as a flat <a href="http://merbivore.com/%20Merb">Merb</a> application. Unfortunately I wanted to host this on Dreamhost and they are still on Ancient Ruby (read, 1.8.5) and the newest Merb wants 1.8.6. That was a deal-breaker. So then I took a look at <a href="http://sinatra.rubyforge.org/%20Sinatra!">Sinatra</a>, and just like the bobby-soxers of the 40's I fell in love. Sigh&#8230;</p>
          
          <p>If you haven't had a chance to look at Sinatra, you should do yourself a favor and check it out. They call it a DSL for the web, <em>not</em> a framework. It has the nice terse syntax of <a href="http://camping.rubyforge.org/files/README.html%20Camping">Camping</a>, but has source that gives me half a chance to comprehend. It's short and sweet and gives enough things that will make sense to Rails-veteran, but with little extra cruft. The source is up on <a href="http://github.com/alexvollmer/freedomrock/tree/master%20GitHub%20repo">GitHub</a> (with a shocking number of commits for such a simple project).</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          This Evening's moochbot Lessons
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/11/this-evenings-moochbot-lessons/' />
    <updated>
      2008-12-11T05:27:15PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/11/this-evenings-moochbot-lessons/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Tonight's post-get-the-kid-to-bed hacking time was a mad dash to cleanup a handful of bugs that some of you fine folks found with <a href="http://moochbot.com">moochbot</a>. In no particular order is a list of this evening's "a-ha" moments:</p>
          
          <ul>
          <li>Receiving email works much much better when you configure your MX records correctly</li>
          <li>Mixing ERb and HAML is a really really bad idea</li>
          <li>I'm probably using RubyGems in my Rails app in about the stupidest way possible</li>
          <li>Good dynamic form validation with JavaScript is actually quite tricky</li>
          <li>Squashing commits in Git is still pretty damn cool.</li>
          </ul>
          
          
          <p>That's all for now. Good night and good luck.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          moochbot is out
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/10/moochbot-is-out/' />
    <updated>
      2008-12-10T06:29:02PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/10/moochbot-is-out/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img alt="moochbot" src="http://moochbot.com/images/logo.png" class="left"/></p>
          
          <p>The secret side-project that I've been referring to in various posts finally reached its Version One milestone tonight. I closed out the remaining V1 issues off of my to-do list and suddenly realized that I could turn it loose on the world. So, without further ado, I present to you: <a href="http://moochbot.com%20moochbot%20%20track%20what%20you%20lend%20and%20borrow">moochbot</a>. Check it out and see what I've been up to all this time.</p>
          
          <p>I'd love to hear any feedback folks have; what you love and what you hate. I have a ton of V2 features planned so moochbot will certainly continue to evolve. It's running on a single Slicehost slice so it's not real high-powered. Your patience is appreciated.</p>
          
          <p>I'll have plenty of blog-material from this experience to write up later, but for now I'm just going to enjoy the satisfying feeling of getting something done. Enjoy!</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Code Personification
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/12/09/code-personification/' />
    <updated>
      2008-12-09T04:31:19PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/12/09/code-personification/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Today I had a conversation with co-worker about the two software components we were trying to integrate in the system we work on. In that conversation I noticed that we both kept referring to the software components as "you" and "I". If you had been within earshot of this conversation you would have heard phrases like "&#8230;<em>you</em> should send the dates in GMT so that <em>I</em> can search correctly&#8230;" I don't think this conversational style is uncommon among developers. Clearly it's not logically correct&#8212;it's not <em>me</em> sending dates, it's <em>my code</em>. It's not <em>him</em> who is searching, it's <em>his code</em>. Why do we do this?</p>
          
          <p>For some reason I've always been a little bothered by this and have always felt like it should be avoided. I dislike this way of speaking about a system because of how easy it is to personalize code that someone has written. I think it's simply too easy to make a statement that sounds like a criticism of the <em>person</em> instead of the <em>work.</em> A criticism of the latter can be hard enough to take, but when it's misconstrued with a personal critique it's very easy for feelings to get hurt and team morale to take a nose-dive. In my experience it takes far longer to gain the trust of your teammates than it does to lose it.</p>
          
          <p>The other reason I don't like it is that it reinforces ownership boundaries around particular parts of the code. In an ideal world your team members would be able to move fluidly about the codebase depending on the features to be implemented. In reality this can become difficult, but like a lot of thinks in life I think it's a good "stretch-goal". So when we speak in personal pronouns instead of component names it seems to reinforce these barriers (or maybe it simply highlights them.)</p>
          
          <p>I've found that it's difficult to avoid talking about systems in these terms. I have to make a conscious effort to not do this in much the same way I have to remember to floss. Both seem like unnatural activities that require a lot of discipline to maintain. I can understand why I might be inclined to forget flossing regularly, but it's not as clear to me why all of us developers want to personify code in our daily speech. Any ideas?</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Asynchronous Mail with DelayedJob, God &#38; Daemons
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/11/06/asynchronous-mail-with-delayedjob-god-daemons/' />
    <updated>
      2008-11-06T05:14:42PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/11/06/asynchronous-mail-with-delayedjob-god-daemons/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Slowly but surely I've been pecking away at a little Rails-based side-project for the last four or five months. I'm <em>this close</em> to flipping the <em>on</em> switch&mdash;but in the meantime I've still got some "i"s to dot and "t"s to cross. One of those was switching from in-request mail delivery to asynchronous mail delivery. The app I've been working on involves two parties marching a particular transaction through a variety of state transitions, each of which usually sends an email to either or both parties.</p>
          
          <p>Like a good boy I started out with the simplest thing that could work which was to simply call mailers in my model. However, I wanted to limit the number of activities performed during a request to keep the app feeling responsive. So I decided that asynchronous mail delivery was a "pre-launch" feature that I had to have.</p>
          
          <p>I looked at a variety of background processing tools, including Bj, Starling/Workling, Spawn and AP4R. Each had its strengths and weaknesses but none of them felt like the right fit. My research criteria included:
          *  Job persistence via the database
          *  Something that could get a Rails environment cheaply
          *  Runs outside of the Rails processes
          *  Minimum fuss to get it running</p>
          
          <p>In the end the one that hit the sweet-spot best was <a href="http://github.com/tobi/delayed_job%20GitHub%20Repo">delayed_job.</a> It had the DB persistence I was looking for, but didn't source the Rails environment for each worker and it was extremely simple to plumb it into my app.</p>
          
          <h2>Refactoring</h2>
          
          <p>The first step was creating the <code>DelayedJob</code> worker classes; one for each mail action. At first this turned into a big pile of five-line classes, so to keep things organized I put these all in <code>app/models/jobs</code> and put each class in the Jobs module namespace. This was better, but not good enough so the final step was putting <em>all</em> of the worker classes in a single file, <code>app/models/jobs.rb</code>.</p>
          
          <p>The second step was to find every place in the model where I called my mailer classes directly and replace them with calls to enqueue the appropriate worker job.</p>
          
          <p>Here is what things looked like at first:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">UserObserver</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Observer</span>&#x000A;      <span class="k">def</span> <span class="nf">after_create</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">unless</span> <span class="n">user</span><span class="o">.</span><span class="n">current_state</span> <span class="o">==</span> <span class="ss">:latent</span> <span class="ow">or</span> <span class="n">user</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Admin</span><span class="p">)</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_signup_notification</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nf">after_save</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">current_state</span> <span class="o">==</span> <span class="ss">:promoted</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_signup</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">else</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_activation</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> <span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">recently_activated?</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>Then the UserObserver was refactored like this:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">UserObserver</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Observer</span>&#x000A;      <span class="k">def</span> <span class="nf">after_create</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">unless</span> <span class="n">user</span><span class="o">.</span><span class="n">current_state</span> <span class="o">==</span> <span class="ss">:latent</span> <span class="ow">or</span> <span class="n">user</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Admin</span><span class="p">)</span>&#x000A;          <span class="no">Delayed</span><span class="o">::</span><span class="no">Job</span><span class="o">.</span><span class="n">enqueue</span><span class="p">(</span><span class="no">Jobs</span><span class="o">::</span><span class="no">UserNotifierSignupNotificationJob</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">))</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nf">after_save</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">current_state</span> <span class="o">==</span> <span class="ss">:promoted</span>&#x000A;          <span class="no">Delayed</span><span class="o">::</span><span class="no">Job</span><span class="o">.</span><span class="n">enqueue</span><span class="p">(</span><span class="no">Jobs</span><span class="o">::</span><span class="no">UserNotifierSignupNotificationJob</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">))</span>&#x000A;        <span class="k">else</span>&#x000A;          <span class="no">Delayed</span><span class="o">::</span><span class="no">Job</span><span class="o">.</span><span class="n">enqueue</span><span class="p">(</span><span class="no">Jobs</span><span class="o">::</span><span class="no">UserNotifierActivationJob</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">))</span> <span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">recently_activated?</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>With the following workers (abridged):</p>
          
          <div class="highlight"><pre><span class="k">module</span> <span class="nn">Jobs</span>&#x000A;      <span class="k">class</span> <span class="nc">UserNotifierDisconnectJob</span> <span class="o">&lt;</span> <span class="no">Struct</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:user_id</span><span class="p">)</span>&#x000A;        <span class="k">def</span> <span class="nf">perform</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_disconnect</span><span class="p">(</span><span class="n">user_id</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">class</span> <span class="nc">UserNotifierResetPasswordJob</span> <span class="o">&lt;</span> <span class="no">Struct</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span>&#x000A;        <span class="k">def</span> <span class="nf">perform</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_reset_password</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">class</span> <span class="nc">UserNotifierSignupNotificationJob</span> <span class="o">&lt;</span> <span class="no">Struct</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span>&#x000A;        <span class="k">def</span> <span class="nf">perform</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_signup_notification</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="k">class</span> <span class="nc">UserNotifierStartDisconnectJob</span> <span class="o">&lt;</span> <span class="no">Struct</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:user_id</span><span class="p">)</span>&#x000A;        <span class="k">def</span> <span class="nf">perform</span>&#x000A;          <span class="no">UserNotifier</span><span class="o">.</span><span class="n">deliver_start_disconnect</span><span class="p">(</span><span class="n">user_id</span><span class="p">)</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <h2>Testing</h2>
          
          <p>Prior to switching to asynchronous processing, mail delivery was triggered within my models, either via Observers or as Procs attached to state transitions (I'm using the <code>acts_as_state_machine</code> plugin). Therefore my tests had loads of assertions that various state changes in the model resulted in direct email delivery. In the asynchronous model of course, that changes slightly. While the state change ultimately ends in mail delivery, it only happens indirectly.</p>
          
          <p>So here I had a big pile of tests that asserted that poking the model in certain ways resulted in a mail delivery. In my unit-tests I really just wanted to test the interaction between the models and <code>DelayedJob</code>. After all, if something went hay-wire during mail delivery the culprit would likely be my new worker classes, <em>not</em> my model.</p>
          
          <p>However, for my integration tests I still wanted to keep the assertions about actual mail delivery since that was an important part of the stories. I could easily do this by monkey-patching the <code>DelayedJob::enqueue</code> method to call the worker's <code>perform</code> method directly. In my unit-tests I monkey-patched the <code>DelayedJob::enqueue</code> method to work more like a mock object which added some inquiry methods to check that it had been invoked correctly.</p>
          
          <p>In isolation this worked great, but running all the tests together resulted in a number of random failures. I've run into this enough times to recognize that some tests were somehow poisoning the run-time environment for the others. It turns out that my two approaches were incompatible with each other unless I was very diligent about cleaning everything up properly. I will admit with red-faced shame that I punted. I did the lamest thing one could possibly do and redefined <code>DelayedJob::enqueue</code> for <em>all</em> of my tests and kept all of my original assertions. I'm not proud of it, but it does work.</p>
          
          <h2>Running in Production</h2>
          
          <p>The next trick was getting this all running in a production environment and I needed to figure out how one or more workers would be started and kept running. While it's great to have this decoupled from the Rails environment, it means that it's a separate process that needs to be managed.</p>
          
          <p>My solution was to use the <code>daemons</code> gem to create a couple of scripts. Then I used Tom Preston-Warner's <code>god</code>, to monitor my process. The scripts look like this:</p>
          
          <div class="highlight"><pre><span class="c1">#!/usr/bin/env ruby</span>&#x000A;    &#x000A;    <span class="k">unless</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span>&#x000A;      <span class="vg">$stderr</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;USAGE: </span><span class="si">#{</span><span class="mi">0</span><span class="si">}</span><span class="s2"> [environment]&quot;</span>&#x000A;      <span class="nb">exit</span> <span class="mi">1</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="no">RAILS_ENV</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">first</span>&#x000A;    <span class="nb">require</span> <span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;/../config/environment&#39;</span>&#x000A;    &#x000A;    <span class="no">Delayed</span><span class="o">::</span><span class="no">Worker</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">start</span>&#x000A;    </pre>
          </div>
          
          
          <p>The "control" script looks like this:</p>
          
          <div class="highlight"><pre><span class="c1">#!/usr/bin/env ruby</span>&#x000A;    &#x000A;    <span class="nb">require</span> <span class="s2">&quot;rubygems&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;daemons&quot;</span>&#x000A;    &#x000A;    <span class="k">def</span> <span class="nf">running?</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>&#x000A;      <span class="c1"># Check if process is in existence</span>&#x000A;      <span class="c1"># The simplest way to do this is to send signal &#39;0&#39;</span>&#x000A;      <span class="c1"># (which is a single system call) that doesn&#39;t actually</span>&#x000A;      <span class="c1"># send a signal</span>&#x000A;      <span class="k">begin</span>&#x000A;        <span class="no">Process</span><span class="o">.</span><span class="n">kill</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">pid</span><span class="p">)</span>&#x000A;        <span class="k">return</span> <span class="kp">true</span>&#x000A;      <span class="k">rescue</span> <span class="no">Errno</span><span class="o">::</span><span class="no">ESRCH</span>&#x000A;        <span class="k">return</span> <span class="kp">false</span>&#x000A;      <span class="k">rescue</span> <span class="o">::</span><span class="no">Exception</span>&#x000A;        <span class="c1"># for example on EPERM (process exists but does not belong to us)</span>&#x000A;        <span class="k">return</span> <span class="kp">true</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="k">if</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="s2">&quot;status&quot;</span>&#x000A;      <span class="n">pidfile</span> <span class="o">=</span> <span class="s2">&quot;/var/run/delayed_job_worker.pid&quot;</span>&#x000A;      <span class="k">if</span> <span class="no">File</span><span class="o">.</span><span class="n">exists?</span><span class="p">(</span><span class="n">pidfile</span><span class="p">)</span>&#x000A;        <span class="n">pid</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">pidfile</span><span class="p">)</span><span class="o">.</span><span class="n">readlines</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">strip</span><span class="o">.</span><span class="n">to_i</span>&#x000A;        <span class="k">if</span> <span class="n">running?</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>&#x000A;          <span class="nb">puts</span> <span class="s2">&quot;delayed_job_worker is running (</span><span class="si">#{</span><span class="n">pid</span><span class="si">}</span><span class="s2">)&quot;</span>&#x000A;        <span class="k">else</span>&#x000A;          <span class="nb">puts</span> <span class="s2">&quot;delayed_job_worker is NOT running (</span><span class="si">#{</span><span class="n">pid</span><span class="si">}</span><span class="s2">)&quot;</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">else</span>&#x000A;        <span class="nb">puts</span> <span class="s2">&quot;delayed_job_worker is NOT running (none)&quot;</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">else</span>&#x000A;      <span class="no">Daemons</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;/delayed_job_worker&#39;</span><span class="p">,</span>&#x000A;                  <span class="ss">:backtrace</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">,</span>&#x000A;                  <span class="ss">:log_output</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">,</span>&#x000A;                  <span class="ss">:dir</span> <span class="o">=&gt;</span> <span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;/../tmp/pids&quot;</span><span class="p">,</span>&#x000A;                  <span class="ss">:dir_mode</span> <span class="o">=&gt;</span> <span class="ss">:normal</span><span class="p">,</span>&#x000A;                  <span class="ss">:multiple</span> <span class="o">=&gt;</span> <span class="kp">false</span><span class="p">)</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>The first script is merely the smallest amount of chrome required to start a worker. Note that I'm using <a href="http://github.com/jbarnette/delayed_job/tree%20jbarnette's%20GitHub%20Repo">John Barnette's version of delayed_job</a> which gives us that nice little worker riff. The second script is essentially the <code>daemons</code> wrapper around my worker. For a little extra goodness I added my own "status" command which can be handy for debugging.</p>
          
          <p>Getting those to work properly took a little bit of testing by hand. Fortunately, the entire solution is really a series of layers applied on top of each other. Once you convince yourself that an inner-layer is working correctly you can move on to build the outer layers.</p>
          
          <p>The next step was to create a proper god configuration. I have more than one thing to monitor on my setup so I have a master god configuration that includes sub-configurations. My "main" configuration is a simple one-liner:
          <code>God.load "/etc/god/*.god"</code>
          My application-specific configuration looks like this (with a few edits for public consumption):</p>
          
          <div class="highlight"><pre><span class="no">RAILS_ROOT</span> <span class="o">=</span> <span class="s2">&quot;/var/www/moochbot/current&quot;</span>&#x000A;    &#x000A;    <span class="no">God</span><span class="o">::</span><span class="no">Contacts</span><span class="o">::</span><span class="no">Email</span><span class="o">.</span><span class="n">message_settings</span> <span class="o">=</span> <span class="p">{</span>&#x000A;      <span class="c1"># your config goes here</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="no">God</span><span class="o">::</span><span class="no">Contacts</span><span class="o">::</span><span class="no">Email</span><span class="o">.</span><span class="n">server_settings</span> <span class="o">=</span> <span class="p">{</span>&#x000A;      <span class="c1"># your config goes here</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="no">God</span><span class="o">.</span><span class="n">contact</span><span class="p">(</span><span class="ss">:email</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;      <span class="c1"># your config goes here</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>After setting up some default notification details, we get into the meat of defining our "watch":</p>
          
          <div class="highlight"><pre><span class="no">God</span><span class="o">.</span><span class="n">watch</span> <span class="k">do</span> <span class="o">|</span><span class="n">w</span><span class="o">|</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;delayed_job_worker&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">10</span><span class="o">.</span><span class="n">seconds</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">start</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">RAILS_ROOT</span><span class="si">}</span><span class="s2">/script/delayed_job_worker_control start -- production&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">stop</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">RAILS_ROOT</span><span class="si">}</span><span class="s2">/script/delayed_job_worker_control stop&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">restart</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">RAILS_ROOT</span><span class="si">}</span><span class="s2">/script/delayed_job_worker_control restart&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">start_grace</span> <span class="o">=</span> <span class="mi">10</span><span class="o">.</span><span class="n">seconds</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">restart_grace</span> <span class="o">=</span> <span class="mi">10</span><span class="o">.</span><span class="n">seconds</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">pid_file</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">RAILS_ROOT</span><span class="si">}</span><span class="s2">/tmp/pids/delayed_job_worker.pid&quot;</span>&#x000A;    &#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">uid</span> <span class="o">=</span> <span class="s2">&quot;deploy&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">gid</span> <span class="o">=</span> <span class="s2">&quot;root&quot;</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">behavior</span><span class="p">(</span><span class="ss">:clean_pid_file</span><span class="p">)</span>&#x000A;    </pre>
          </div>
          
          
          <p>Next we need to define our transitions. My first attempt at this failed because I was missing these and my watched process was stuck in the "unmonitored" state. It's worth spending some time reading the docs on the <a href="http://god.rubyforge.org/">homepage</a> since at first glance the configuration wasn't obvious to me.</p>
          
          <div class="highlight"><pre>  <span class="c1"># determine the state on startup</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">transition</span><span class="p">(</span><span class="ss">:init</span><span class="p">,</span> <span class="p">{</span> <span class="kp">true</span> <span class="o">=&gt;</span> <span class="ss">:up</span><span class="p">,</span> <span class="kp">false</span> <span class="o">=&gt;</span> <span class="ss">:start</span> <span class="p">})</span> <span class="k">do</span> <span class="o">|</span><span class="n">on</span><span class="o">|</span>&#x000A;        <span class="n">on</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:process_running</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">running</span> <span class="o">=</span> <span class="kp">true</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="c1"># determine when process has finished starting</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">transition</span><span class="p">(</span><span class="o">[</span><span class="ss">:start</span><span class="p">,</span> <span class="ss">:restart</span><span class="o">]</span><span class="p">,</span> <span class="ss">:up</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">on</span><span class="o">|</span>&#x000A;        <span class="n">on</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:process_running</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">running</span> <span class="o">=</span> <span class="kp">true</span>&#x000A;        <span class="k">end</span>&#x000A;    &#x000A;        <span class="c1"># failsafe</span>&#x000A;        <span class="n">on</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:tries</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">times</span> <span class="o">=</span> <span class="mi">5</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">transition</span> <span class="o">=</span> <span class="ss">:start</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="c1"># start if process is not running</span>&#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">transition</span><span class="p">(</span><span class="ss">:up</span><span class="p">,</span> <span class="ss">:start</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">on</span><span class="o">|</span>&#x000A;        <span class="n">on</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:process_exits</span><span class="p">)</span>&#x000A;      <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>Finally I specify some resource-consumption boundaries to make sure that my little worker daemon doesn't take over my box:</p>
          
          <div class="highlight"><pre>  <span class="n">w</span><span class="o">.</span><span class="n">restart_if</span> <span class="k">do</span> <span class="o">|</span><span class="n">restart</span><span class="o">|</span>&#x000A;        <span class="n">restart</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:memory_usage</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">above</span> <span class="o">=</span> <span class="mi">100</span><span class="o">.</span><span class="n">megabytes</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">times</span> <span class="o">=</span> <span class="o">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="o">]</span>&#x000A;        <span class="k">end</span>&#x000A;    &#x000A;        <span class="n">restart</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:cpu_usage</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">above</span> <span class="o">=</span> <span class="mi">50</span><span class="o">.</span><span class="n">percent</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">times</span> <span class="o">=</span> <span class="mi">5</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    &#x000A;      <span class="n">w</span><span class="o">.</span><span class="n">lifecycle</span> <span class="k">do</span> <span class="o">|</span><span class="n">on</span><span class="o">|</span>&#x000A;        <span class="n">on</span><span class="o">.</span><span class="n">condition</span><span class="p">(</span><span class="ss">:flapping</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">to_state</span> <span class="o">=</span> <span class="o">[</span><span class="ss">:start</span><span class="p">,</span> <span class="ss">:restart</span><span class="o">]</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">times</span> <span class="o">=</span> <span class="mi">5</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">within</span> <span class="o">=</span> <span class="mi">5</span><span class="o">.</span><span class="n">minute</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">transition</span> <span class="o">=</span> <span class="ss">:unmonitored</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">retry_in</span> <span class="o">=</span> <span class="mi">10</span><span class="o">.</span><span class="n">minutes</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">retry_times</span> <span class="o">=</span> <span class="mi">5</span>&#x000A;          <span class="n">c</span><span class="o">.</span><span class="n">retry_within</span> <span class="o">=</span> <span class="mi">2</span><span class="o">.</span><span class="n">hours</span>&#x000A;        <span class="k">end</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Election Infographics Redux
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/11/05/election-infographics-redux/' />
    <updated>
      2008-11-05T05:43:36PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/11/05/election-infographics-redux/
    </id>
    <content type='html'>
      <![CDATA[
          <p>With Election Night coming to a close and Senator Barack Obama declared as President-elect, I figured I'd spend a little time <a href="http://livollmers.net/index.php/2008/02/05/a-survey-of-super-tuesday-infographics/">re-surveying the infographics</a> of some of the major online publishers. This is by no means comprehensive, and doesn't consider a lot of the interesting visualizations that some folks are doing. I consciously stuck with the mainstream to see how design innovation was trickling down into conservative publishers.</p>
          
          <p>So without further ado, let's start with the <a href="http://nytimes.com%20The%20New%20York%20Times">New York Times:</a></p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811041829.jpg" alt="200811041829.jpg" /></p>
          
          <p>If you remember my original post, I favored the tabular displays generally over map-based views. My favorite part of this is the electoral vote tally on the left-hand side. To me, the most important information is the electoral vote tally and the Times has done a good job of highlighting this both by making it a larger font and putting it on the left-hand side. Then as my eye moves to the right I can drill down to state-by-state detail. The color codes provide a nice way to get a "feel" for the state of things at a glance.</p>
          
          <p>Next stop, <a href="http://www.cnn.com%20CNN">CNN</a>:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811041832.jpg" alt="200811041832.jpg" /></p>
          
          <p>What you don't see here is the completely unnecessary animation of the left-hand counters like some alarm-clock from the seventies. The other three panels "flip" to various local races. Instead of using space show multiple data-points, CNN chose to use time. This feel like a real waste of space and <em>my time</em>. When compared with the Times site, there is really no contest.</p>
          
          <p>Let's move on to <a href="http://www.msnbc.msn.com/%20MSNBC">MSNBC</a>. These guys get bonus points for including the Senate races in aggregated form&#8212;a nice touch if you want to take the pulse of all the races. This is a nice tight display of a lot of information.</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811041949.jpg" alt="200811041949.jpg" /></p>
          
          <p>Again, I could do without the map. It's not that I don't like maps (I like them quite a bit), but they don't tell me the most <em>important</em> information&#8212;the electoral college votes. It's <em>interesting</em> to see the geographic proclivities but it's <em>essential</em> that I know the electoral college votes. The geographically large, but sparsely-populated states in Big Sky Country and the Midwest distort our initial perception of the data. Their size belies their actual value in the race and so we have to constantly look elsewhere for electoral college vote totals. Unfortunately, this graph doesn't tell that story. I can't look at Ohio in this chart and understand its value in the race.</p>
          
          <p>Next, the <a href="http://www.washingtonpost.com/%20The%20Washington%20Post">Washington Post</a>:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811042112.jpg" alt="200811042112.jpg" /></p>
          
          <p>This is pretty uninspiring and uninformative. Oh look! Pictures! Just in case you forgot what the candidates looked like. However, if we start clicking the tabs, we get a little more meat:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/2008110421121.jpg" alt="200811042112.jpg" /></p>
          
          <p>I'm not sure why the map is all-gray, but the I like the bar at the top. This seems to be the new trend this year in info-graphics. I think for highlighting the changes in the balance-of-power, the line chart does a good job.</p>
          
          <p>Now we move onto <a href="http://www.usatoday.com/%20USA%20Today">USA Today</a>&#8230;</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811042118.jpg" alt="200811042118.jpg" /></p>
          
          <p>That's it folks. That's all you get on the front page, up in the right-hand corner. I think that pretty much sums up the estimation the editors of McPaper have of their audience. Let's, for a moment, try to treat this with a serious eye. Could somebody please explain what the blue boxes on the right-hand side are for? Do you click them? What do they do? Why are they the only ones shown? Can you see others? This is what Edward Tufte would call "chart junk".</p>
          
          <p>On to the once-venerable <a href="http://online.wsj.com/public/us%20Wall%20Street%20Journal">Wall Street Journal</a>&#8230;</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/11/200811042121.jpg" alt="200811042121.jpg" /></p>
          
          <p>Same old map, so few details. I can't tell if the lack of titles on the shapes indicates that the Journal's editors assume their audience can actually tell the states apart, or that they just couldn't be bothered. Like the Washington Post we get the candidate's faces. While it fits the Journal's famous stodgy etchings theme, it doesn't bring much information to the table. Oh yeah, just in case you lack the skill to compare numbers, the big checkbox next to Obama's name serves to tell you who won. Sheesh.</p>
          
          <p>One interesting note is that this is the first infographic of the major sites I surveyed that included results for any of the other candidates. It's interesting to note that just the simple quantity of <em>digits</em> gives you some idea of the magnitude of the votes the two major-party candidates get.</p>
          
          <p>Check back in four years and we'll do it again!</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Proportional Code
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/10/26/proportional-code/' />
    <updated>
      2008-10-26T23:53:14PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/10/26/proportional-code/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Few things are less sexy than command-line parsing. It is one of the most mundane tasks a programmer has to execute in their career. But, it surprises just how much code is required to do basic command-line parsing in a lot of languages, including Ruby. So I got to thinking, <em>why does this bug me so much?</em> I think the answer is that requiring so much code for such a relatively trivial task violates my sense of <em>proportionality</em> in the code. I hate having to say so much more about this teeny little task than I do about the "theme" of my code. I think it distorts the narrative of the code.</p>
          
          <p>Let's say that the processing of writing your program is like launching spacecraft. Ideally you would like to get from launch to cruising around in space as quickly as possible. The Star Trek universe solves this quite elegantly with the transporter. We don't put you in a box and launch it, we break your atoms apart and transmit them to another location! That's pretty cool, but maybe we're just not quite that cool yet. Another solution is one proffered by the Star Wars universe. A ship like the Millenium Falcon can leave just about any planetary atmosphere any time it damn well pleases without the use of special equipment. It just flies away. Not bad.</p>
          
          <p><img alt="Atlantis (STS-125)"
          src="http://farm4.static.flickr.com/3173/2958037544_26e7973f17_m.jpg"
          class="left"/></p>
          
          <p>However, here on earth, our primitive space craft need a tremendous amount of disposable apparatus to reach escape-velocity. The proportion of useful vehicle (the shuttle) to the orbit-busting mechanism (the rocket boosters and fuel tanks) is a staggering 5.4:1 (based on liftoff weight).</p>
          
          <p>Command-line parsing in code exhibits a similar disproportion. The interesting part of your app isn't the command-line parsing. Why should it take up such a disproportionate amount of space in your code? Those boosters quickly become "space-junk", once the launch vehicle has left Earth; expensive trash that is never to be used again.</p>
          
          <p>Space-junk is dangerous for the next guy that wants to launch into space. It's also dangerous for the folks on the ground as it may decide to come crashing back down to earth. And those boosters have also been responsible for one of the worst disasters in NASA's history. If we could only get rid of those damn things the whole space program just might be a little better off. Unfortunately physics, and our current space-flight capabilities currently require them.</p>
          
          <p>But our code is a different story. We don't have such physical barriers that handicap us. Any barriers we run into are usually of our own making. So why not try to reduce those as much as possible? Why say in more code, what you could say in less? Wouldn't that cut down on bugs? Wouldn't that ease the burden of maintenance? Wouldn't that reduce the amount of information overhead you have to maintain each time you revisit that code?</p>
          
          <p>Command-line parsing is a stupid, menial task that should require very little attention. By extension, it should only be given a stupid, menial amount of code to make it work. We have big ideas! They shouldn't get bogged down by handling command-line options!</p>
          
          <p>This is why I wrote <a href="https://github.com/alexvollmer/clip/tree%20Clip%20on%20GitHub">Clip</a>. Clip is an expression of the need to make the simple things simple, but no simpler. If you have modest command-line parsing needs, Clip rewards you with minimal investment. If you need something trickier, Clip allows you to say a little more to it and gain more benefits from it. You get to decide how much you want to engage&mdash;not the library.</p>
          
          <p>This is one of the things I like about Ruby. The language is extremely flexible which gives me a lot of ways to "pack" ideas into code in a variety of ways. Having more than one way to do things isn't all that useful by itself. But it's <em>essential</em> when you want to write <em>expressive</em> code. Things like object literals, or one-line control-structure alternatives help me keep the lines of code proportional to the ideas they express.</p>
          
          <p>This is also something I find challenging to do in Java. In languages like Java, even just creating a collection of objects requires quite a bit of code:</p>
          
          <div class="highlight"><pre><span class="kn">import</span> <span class="nn">java.util.*</span><span class="o">;</span>&#x000A;    &#x000A;    <span class="kd">public</span> <span class="kd">class</span> <span class="nc">Designer</span> <span class="o">{</span>&#x000A;      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">makeItWork</span><span class="o">(</span><span class="n">List</span><span class="o">&lt;</span><span class="n">Trash</span><span class="o">&gt;</span> <span class="n">trash</span><span class="o">)</span> <span class="o">{</span>&#x000A;        <span class="c1">// today&#39;s challenge: convert trash to wearable garments</span>&#x000A;        <span class="n">List</span><span class="o">&lt;</span><span class="n">Garment</span><span class="o">&gt;</span> <span class="n">garments</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">Garment</span><span class="o">&gt;(</span><span class="n">trash</span><span class="o">.</span><span class="na">size</span><span class="o">());</span>&#x000A;        <span class="k">for</span> <span class="o">(</span><span class="n">Trash</span> <span class="n">t</span> <span class="o">:</span> <span class="n">trash</span><span class="o">)</span> <span class="o">{</span>&#x000A;          <span class="n">Garment</span> <span class="n">g</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Garment</span><span class="o">(</span><span class="n">t</span><span class="o">.</span><span class="na">getName</span><span class="o">());</span>&#x000A;          <span class="n">garments</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">g</span><span class="o">);</span>&#x000A;        <span class="o">}</span>&#x000A;    &#x000A;        <span class="n">submitToJudges</span><span class="o">(</span><span class="n">garments</span><span class="o">);</span>&#x000A;      <span class="o">}</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
          </div>
          
          
          <p>In Java we often solve this by pushing all of that code into a private method that is named something meaningful. This works pretty well, but does tend to result in an explosion of "helper methods". Sometimes folks take the "cheap" route and simply prefix these riffs with explanatory comments like "convert each Trash into a Garment". I'm not a real big fan of this. Generally I don't care about the object conversion in the first place because the rest of the code is presumably doing something interesting with the <em>Garments</em> and I don't give a damn about the <em>Trash</em>.</p>
          
          <p>So let's look at it in Ruby:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">Designer</span>&#x000A;      <span class="k">def</span> <span class="nf">make_it_work</span><span class="p">(</span><span class="n">trash</span><span class="p">)</span>&#x000A;        <span class="n">submit_to_judges</span><span class="p">(</span><span class="n">trash</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span> <span class="no">Garment</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="p">})</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>By my count there are five lines in the Java example (including the comment) just to convert trash to garments. In contrast I boiled that down to one line in Ruby. OK I could have done this in two lines if you think that's too much of a long-train. But I think there are couple of important points here:
          *  The importance of the concept being expressed diminishes from left to right
          *  The attention-span of the reader diminishes from top to bottom</p>
          
          <p>The Ruby example beats Java on both counts. I don't waste a lot of the reader's attention span up-front on book-keeping details (in the vertical space) and I state the important thing I'm trying do (submit my top Foos) quickly (on the left). The details of <em>which </em>Garments I'm dealing with are merely a qualification of <em>what</em> I'm trying to do.</p>
          
          <p>How you handle these two dimensions is greatly affected by both the language you use and the APIs you deal with. This is one of the reasons that I do <em>not</em> find the use of scripting languages for Java's Swing API all that compelling. Scripting languages like JRuby or Jython help me with the horizontal space, but don't do a damn thing for the vertical requirements. With an awful API like Swing I have to say a <em>lot</em> of words to make it go, regardless of the language I do it with.</p>
          
          <p>Getting back to my dumb example, being on such a small scale this may not seem like a large impact. But multiplied several times over to match the size of most projects, this kind savings can really pile up. The difference in the amount of code required by these two approaches is manifested in a savings in cognitive investment required to grok these projects. This is the very <em>essence</em> of maintainability and sustainability. Anytime you can do more with less, you come out ahead.</p>
          
          <p>At great peril to my own geek cred, I will say that this is why I find <em>The Lord of the Rings</em> to be such an awful piece of writing. It is so full of peripheral and non-essential information that finding the real story or characters requires extraordinary patience and concentration on the part of the reader. If Tolkien had been more concerned with the story and less with "world-building" I'll bet he could have gotten that story boiled down to a single book.</p>
          
          <p>Now I realize that a lot of folks <em>love</em> the Tolkien books for the very reasons I criticize it. That's fine, <em>that</em> is an argument about aesthetics, not facts. However I would strongly argue that "world-building" in your code is a <em>bad idea</em>. I think you're much more likely to build a decent piece of software if you pack your ideas tightly like a William Gibson novel than as a sprawling "trilogy" of epic code. Go ahead, prove me wrong. I double dog-dare ya.</p>
          
          <p>OK, so by this point any credibility I may have had is gone. Look at the size of a post about saying more with less. In the hope that you might be lazy and like to skip to the end:
          <em>Do as much as you can&hellip;with as little as possible.</em></p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Back To My...Emacs
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/10/07/back-to-myemacs/' />
    <updated>
      2008-10-07T03:36:51PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/10/07/back-to-myemacs/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Emacs. Love it or hate it, it is undeniably a monument of software engineering. At best it's an amazingly customizable work environment that can be shaped to your every whim. At worst it's a giant time-sink where productivity is skewered by endless "fiddling".</p>
          
          <p>Since switching to the Mac over a year and half ago, I've used <a href="http://macromates.com/%20TextMate">TextMate</a> as my non-Java editor. TextMate is <em>great</em> text editor. It's relatively simple to extend, has a very active community and only takes a little investment before a user gets productive. But I'll admit that in the last month or so my eyes started wandering from TextMate&#8212;I felt like maybe I was ready to go back to Emacs.</p>
          
          <p>Perhaps it's worth a little history first. Back in the Dark Ages of Java Development (anyone remember Gnu Server Pages?), I was a pretty hard-core XEmacs guy for my Java dev. At the time Java IDEs were painful exercises in waiting and crash-recovery. JBuilder, early NetBeans, Visual Cafe were all valiant attempts but terrible failures. So I rode with XEmacs until the IDEs caught up.</p>
          
          <p>Then one day I met Eclipse. Unlike any other Java editing tool, Eclipse was much more than a text-editor. Rather than treating your code like text to be manipulated, Eclipse actually <em>understood your code</em>. This allows you to think in terms of manipulating Java syntax and symbols instead of simple text tokens and lines. For a static language like Java this is incredibly powerful since you can determine up-front all of the possible things you might want to write. This is why a full-on "intelli-sense" feature for dynamic languages is hard to do as well in static, compiled languages.</p>
          
          <p>I spent the next five years learning just about every nook and cranny of Eclipse and would put my raw Java-writing skills up against anyone. Even now, I still use Eclipse for Java and I can't imagine going back to a plain text-editor&#8212;even a souped-up hot-rod like Emacs. This says less about the deficiencies of any text editors as it does about the requirements for developing in Java. Writing Java without all of the code-completion and refactoring tools an IDE like Eclipse has would simply exceed my pain threshold. So while Eclipse has become quite bloated lately and, when coupled with tools like Maven, is an exercise machine-servitude, it will be a cold day in hell before I give it up for Java. (NB: I plan on giving up Java-dev first.)</p>
          
          <p>Now I'm writing a lot more non-Java than I did a year ago. That's what brought me to TextMate. The integration for Ruby, HTML, CSS, JavaScript and shell was outstanding. I bought the <a href="http://www.amazon.com/TextMate-Power-Editing-Pragmatic-Programmers/dp/097873923X%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D097873923X">TextMate book</a> and was on my way to editor ass-kicking.</p>
          
          <p>Unlike my Java days, now I identify myself less with a single language. Back in the day I was a Java Programmer&#8482; dad-gummit. It was The One Language To Rule Them All and it served me well. Do you remember those days? Yeah, that was also the time when certified Oracle dudes were writing their own checks. But as time went on, I noticed that those Oracle guys pretty much knew how to do one thing and if and when the Day of Database Reckoning ever came, these guys were gonna be left standing in the cold wondering what the hell happened. I think that day has come and those dudes are becoming the equivalent of COBOL programmers&#8212;relegated to propping up legacy systems and talking wistfully about "the good ol' days".</p>
          
          <p>So it got me to thinking about what I needed to do to survive in this business. Clearly I was going to have to evolve. So I started looking around for some inspiration and came across Ruby. Right now it's my favorite language, but it's not the only game in town. Ruby borrows a lot of features from other languages and a lot of other Ruby-ists are also spending time with other languages like Haskell, Erlang, io, and Lisp just to get exposure to other ideas. Moving away from a single-language focus to broader interests has been an important part of moving from rookie to journeyman. Evolve or die, right?</p>
          
          <p>So how does this relate to Emacs? Well, like a lot of folks, I've been interested in learning more about functional programming. The problem is, I simply haven't had the time to crack open the <a href="http://www.amazon.com/Programming-Erlang-Software-Concurrent-World/dp/193435600X%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D193435600X">Erlang book</a> and bend my brain in new ways. Don't get me wrong, it's on the list, but it's going to be a while before I get to it. So I was eager to dip my toe in FP without a major commitment. Enter ELisp.</p>
          
          <p>Before I dropped out of college, my brief career in academic computer science was spent with Scheme. My time in school didn't end well and so I've associated Scheme (and by extension, Lisp) with that particularly unpleasant time in my life. I've only recently overcome the shakes when I see <code>car</code> or <code>cdr</code>. But a little time and some professional success has healed old wounds. In my first go-round with Emacs, I was really just using it as a power-editor. The internals of Emacs pretty much escaped me and in my mind there was a pretty major barrier between an ELisp user and an ELisp <em>writer.</em></p>
          
          <p>This time I've made a concentrated effort to learn more about how Emacs works. I've been racing through the <a href="http://www.amazon.com/Learning-Elliot-Raymond-Rosenblatt-Cameron/dp/B001E3G45M%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB001E3G45M">O'Reilly Emacs book</a> and this time <em>it makes sense</em>. I don't know what the hang-up was before, but this time it all seems so logical! The entire editor is simply a collection of ELisp functions and variables built on top of other functions and variables. It's all self-documented and incredibly dynamic. Wanna try something out? Just put a little Lisp in your <code>*scratch*</code> buffer and evaluate that sucker. Hell, in Eclipse I'd have to download the freakin' source and compile it or swim in XML writing an extension. That's <em>incredibly</em> powerful&#8212;the barrier to "trying stuff out" is mind-bogglingly low.</p>
          
          <p>So while I've definitely take a short-term hit by trading in TextMate for Emacs, but I'm reaching productivity-parity pretty quickly. A couple of modes/libraries I've found that I've really liked are:</p>
          
          <ul>
          <li><a href="http://code.google.com/p/js2-mode/%20js2%20Mode">Steve Yegge's JS2 mode</a></li>
          <li><a href="http://rinari.rubyforge.org/%20Rinari%20Is%20Not%20a%20Rails%20IDE">Rinari,</a> for Rails</li>
          <li><a href="http://orgmode.org/%20Org-mode">Org-mode</a></li>
          <li><a href="http://zagadka.vm.bytemark.co.uk/magit/magit.html%20Magit">Magit</a> for Git integration</li>
          </ul>
          
          
          <p>I plan on spending some quality time with some of the various snippets libraries too to port over some of the templates that TextMate uses. For something like Rails development, which is about the most idiomatic programming I can imagine, having short-hand snippets is a major productivity boost.</p>
          
          <p>So why go through this? After all, switching editors can be like converting from Catholicism to Judaism for some. Well, I think I'm doing this because:</p>
          
          <ul>
          <li>I've already overcome the initial steep-learning curve of basic editing in Emacs</li>
          <li>I get a nice, no-commitment introduction to functional programming</li>
          <li>I get a great environment to learn new stuff in</li>
          <li>With a little effort and a willingness to learn, I can make this sucker to <em>anything</em></li>
          <li>Emacs has quite a track-record. It's close association with Unix is no accident.</li>
          <li>Emacs customization is <em>easy</em> to write and a snap to track in SCM</li>
          </ul>
          
          
          <p>I can't say that I'll use Emacs for <em>everything</em>. I'm getting into Cocoa development too and it looks like doing that outside of XCode is a fool's errand. But that's okay. I don't need a single tool to do everything for me, just a handful of tools that help me get a variety of things done. That said, I'm pretty sure I'll be solving a lot more problems in Emacs than I ever did in any other single tool.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          A Philosophy of Testing
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/10/02/a-philosophy-of-testing/' />
    <updated>
      2008-10-02T16:44:27PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/10/02/a-philosophy-of-testing/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Did you hear that? Did you feel it? I did. Agile just took another punch to the gut. The Agile Backlash is picking up a full head of steam. Rather than becoming a term to embrace, it's become a term of ridicule. I think it's probably deserved. As a guy who picked up the first <a href="http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0321278658%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0321278658">Extreme Programming</a> book as soon as it was released and is a long-time practitioner, I feel qualified to comment on this.</p>
          
          <p>The second-generation acolytes turned a very pragmatic set of principles and practices into an esoteric scripture that could never meet the needs of reality. The "agile" moniker makes me cringe almost as much as "best practices". Both are cavalier substitutes for critical thinking, too often thrown about in the hopes that their mere mention will work magic. Ugh.</p>
          
          <p>A real unfortunate side-effect of the backlash is the disregard some have for automated testing. Before I go any further, let me be the first to say that, like any other recommendation or practice, automated testing is <em>not</em> a panacea. I shouldn't have to say this. It's painfully obvious, like explicitly stating up front that I am against beating up defenseless children. Who <em>is</em>?</p>
          
          <p>However, just because automated testing isn't a cure-all doesn't mean that:</p>
          
          <ul>
          <li> testing isn't worth doing</li>
          <li> testing isn't hard</li>
          <li> sometimes testing is so hard that it isn't worth doing</li>
          </ul>
          
          
          <p>Note that last point. That there is what we in the biz call <em>pragmatism</em>. Yes kids, there are times when the cost of getting sufficient test-coverage is enormously expensive. Assuming that economics are part of your project somehow, you need to pay attention to this (which is why code coverage metrics can be dangerous in the hands of the nuance-free thinker).</p>
          
          <p>Critics of automated testing like to point out that if developers write buggy code, how can they not write buggy tests? Assuming that it's as impossible to write perfect tests as it is to write perfect code, is there a point to writing the test? There is if the benefits you get from testing exceed the cost of developing and maintaing them.</p>
          
          <h1>Test-Driven Design/Behavior-Driven Design</h1>
          
          <p><img alt="Marysville Falls" src="http://farm4.static.flickr.com/3084/2906603525_eea04c7769_m.jpg" class="left"/></p>
          
          <p>The TDD/BDD philosophies are nearly as abstract and misunderstood as the entire concept of testing itself. So rather than parrot the original manifestos, let me break down the tangible benefits of driving your code with tests. The first misconception is the notion that you write all the tests first then you write all the code. This works almost as well as gathering all the requirements up front first and then writing all the code. I believe the technical term is "Waterfall". This is just dumb. Honestly folks, use your brains. Only a complete rookie would think that's a sensible practice to adopt.</p>
          
          <p>Putting testing before writing code provides no magical effect that radically increases the quality of your code. Where testing <em>does</em> improve your code is when you use them as part of the code-building process. I like to use unit-tests as a form of mental scaffolding while I develop.</p>
          
          <h1>Breaking It Down</h1>
          
          <p>Any non-trivial problem needs to be broken down in some way. Few of us have the mental capacity to keep an entire solution in our heads. Even if we could, it generally doesn't last beyond the period in which the solution is developed. And even if you could do this, chances are few of your teammates would be able to. So at worst, breaking a problem down is a pro-social practice; at best it's a tool to ensure that you really understand what's going both now and in the future.</p>
          
          <p>Generally when you break a problem down, you get into the business of assigning responsibilities to various components. This is a fractal pattern that starts at the highest-level architecture and repeats itself all the way down to the lowest-level classes, modules and functions of your system. It must be an inherent part of human-nature&#8212;we simply love putting things in boxes. Perhaps this is because that in doing so, we can hang a simple tag on a collection of related concepts as a form of shorthand. That shorthand allows us to talk about things in an efficient way. Imagine a design conversation where you couldn't name anything, but had to describe a piece over and over by its details. Yuck. So yeah, boxes are important.</p>
          
          <p>So where does testing fit in? Testing allows you to write automated assertions about each of those boxes. It's like a logic game where you can start draw conclusions based on what you already know. It's like being able to say, "If this test is passing and that test is passing, the only thing that could torpedo this is if <em>that</em> doesn't work". I'll come back to this later when I talk about troubleshooting.</p>
          
          <p>What unit-testing does <em>not</em> cover here, are the connections between the boxes. It should be obvious that it's entirely possible to have a totally sweet set of unit-tests that never fail that cover each piece of your solution in full and <em>still</em> have bugs or represent and incorrect solution.</p>
          
          <p>This is because unit-tests only cover the boxes, not the connections.</p>
          
          <p>Tests that cover the entire system are the best way to exercise the connections. They cover the boxes too, but they cover the <em>integration</em> (hence the name) of the boxes and connections. Since unit-tests can't cover the system as a whole, are they still worth writing? You bet. Keep reading&#8230;</p>
          
          <h1>Efficient Troubleshooting</h1>
          
          <p>When something goes wrong, you enter a different frame of mind from programming. Now you're in the detective business. You start with some scraps of information (stack traces, error messages, late-night pages) and with a combination of logic, guile and intuition (hopefully) find the root cause.</p>
          
          <p>I could do an entire post on root-cause analysis, but let it suffice to say that most folks don't ask enough questions when troubleshooting. Often the conclusion people come to is an observation of a symptom rather than a thoughtful, system-aware diagnosis. In these situations it's a good idea to consider the <a href="http://en.wikipedia.org/wiki/5_Whys%20The%205%20Whys">5 Whys Approach</a>.</p>
          
          <p>How do unit-tests help with troubleshooting? Like I said earlier, unit-tests are really good at testing the boxes, but not the connections. Let's assume that your unit-test accurately covers the box that you believe is the root of the issue you're seeing. Given that, there is a handful of conclusions you can draw:
          *  The problem isn't really in this box
          *  The problem is the connection coming into or going out of this box
          *  Your understanding of the box is incorrect</p>
          
          <p>That's it. It <em>has</em> to be one of those. Unit-tests allow you to confirm that your box is working correctly. If it's being invoked or interacted with in a way you didn't expect, it's generally a trivial exercise to write a test that <em>does</em> use your box in that way. If it passes then you probably need to keep looking.</p>
          
          <p>If you're pretty confident that your box is good, then checking the connections is the next thing to look at. It's just as likely that the output of your box is being misused as the input to it. Integration tests are usually the best mechanism to catch this, but are generally much more expensive to write and maintain. For this reason they generally don't exhaust all of the possibilities. But with a real-world bug you now have a candidate for a new integration test.
          I can't stress enough the benefits of using bugs as opportunities to strengthen your test-suites. This is as true for integration tests as it is for unit-tests. It's generally not practical to write tests for <em>every</em> situation. So we use our intellect to make educated guesses that cover the most likely situations. When you observe funny behavior in your system, consider it a gift to your understanding. It's a golden opportunity to add a test for a real behavior, not a speculative one that may or may not occur.</p>
          
          <p>So let's consider a world in which we have <em>no</em> tests. When something goes haywire you have to start from first principles <em>every time</em>. You have no mechanisms to get any leverage on the issue. Instead we have to rely on understanding the entire solution and holding it in our head at once. What do you think the chances are that we'll effectively troubleshoot an issue under these conditions?</p>
          
          <h1>Finding Smells</h1>
          
          <p>It is simply no fun to work on low-quality code day after day. As anyone who has every read <a href="http://www.amazon.com/Zen-Art-Motorcycle-Maintenance-Inquiry/dp/0061673730%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0061673730">Zen &amp; The Art of Motorcycle Maintenance</a> can attest, "quality" is a pretty squishy word. But in concrete terms, quality code means:
          *  You enjoy working on it (or at least don't hate it)
          *  You can expand its capabilities with reasonable effort
          *  Somebody else can work on it too</p>
          
          <p>I find the process of test-driving the development of code is a great opportunity to find "smells" in your code. These "smells" generally detract from code quality. The best catalog of these smells that I've encountered is the <a href="http://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Technology/dp/0201485672%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0201485672">Refactoring</a> book by Fowler and Beck. You don't need to read the book for a detailed description of the mechanics of refactoring, but it is worth reading to learn the terminology of "code smells".</p>
          
          <p>At a minimum tests are the first "customers" of your code. If it's painful to test your code, you probably haven't factored it very well. Paying attention to this while your test-driving the development is a great way to keep your code high-quality. To really benefit from this, you need experience, a highly-developed sense of aesthetics and intuition. If you keep at it, you will gain these.</p>
          
          <p>Note that I don't equate code quality with "success". There are plenty of systems out there that are successful that are <em>not</em> built on what I would call quality code. That's fine. I've made a conscious choice not to work on those systems. I spend an awful lot of my waking hours working on code&#8212;personally I don't want to waste that time being frustrated. I want a sense of accomplishment and satisfaction when I'm done for the day. Honestly, I'd trade success for quality code just about anytime. I expect to be doing this for a long time, so why not enjoy it?</p>
          
          <h1>Safety Net for Refactoring</h1>
          
          <p>When you need to extend or enhance a system, having automated tests serve as a great safety-net for refactoring. If you're confident in the efficacy of your unit-tests, you can be confident when you make changes and your tests still pass. You can refactor with a higher level of confidence when your tests keep passing. Of course there are no guarantees that you <em>haven't</em> introduced some kind of regression bug. But let's face it folks, the testing game is one of probabilities. It's too expensive to make sure you're right all of the time&#8212;instead shoot for being right <em>most</em> of the time.</p>
          
          <p>There will <em>always</em> be times when something goes wrong and the only way to diagnose and fix it is to walk through the code painstakingly, line by line. No amount of testing will ever make that go away. My goal is to <em>reduce</em> that as much as possible. It's inevitable, but it doesn't have to be the norm.</p>
          
          <p>Consider the case where you <em>don't</em> have any tests while you refactor. Your code/build/test/debug cycle gets a whole lot longer and more expensive. Because of that, you do it less often. Which means that when you do go through the cycle you have more things that can go wrong and more stuff you have to hold in your head. That increases both the likelihood that you will mis-diagnose a problem and that you will write more bad code to fix the latest bug.</p>
          
          <p>I think this is how really twisted code is born. It almost reads like a blow-by-blow account of the developer's mounting frustration. The pace and phrasing of the code gets more and more frenetic: more odd comments, more TODOs and FIXMEs littered throughout, more long procedural stanzas. It becomes obvious that they were trying to get this done as quickly as possible, and that's generally not the path to quality.</p>
          
          <h1>Confidence</h1>
          
          <p>When it comes human-nature and software I'm a pessimist. I think we're really good at the intuitive parts and achieving the "ah-ha" moment. We are <em>not</em> good at holding giant complicated systems in our heads. There <em>are</em> people who can do that, but it's not the norm. For this reason, I think it's extremely foolish to build a software organization that relies on raw mental capacity. This definition of "smart" is one that can't scale and is unsustainable.</p>
          
          <p>Automated testing is one teeny-tiny way we can offload the need for that capacity to a better long-term storage mechanism. While I write tests my mind is very focused on a particular part of the system. As I flesh out the tests I fill out my understanding of the problem-space <em>at that time</em>. Now that it's written down in code, I can safely leave it there and let my mind free up that space to do other things.</p>
          
          <p>If I've written my tests well, I can get back into that focused frame of mind when I need to (e.g. for new features or bug-fixes). Without these, I have to spend a lot more time understanding a larger system just to get "up to speed". The tests can serve as an index into the design of the system. This is particularly effective when you have been paying attention to code smells and have been refactoring aggressively&#8212;your tests will map effectively to the underlying concepts of the system design.</p>
          
          <p>This kind of confidence has a real tangible benefit. Without it I'm easily distracted by small details and dead-ends. As soon as I have more I have to worry about at once, I have less of a chance of succeeding at the task at hand in that moment. When I have such a thing in place, I have an instant force-multiplier in my hand. I can get something done. I don't have to repeat the entire experience of developing the code the first time. Instead I can leverage that experience to be more productive the next time I come back to that part of the system.</p>
          
          <h1>Conclusion</h1>
          
          <p>So there you have it. That's where I stand.</p>
          
          <p>Is testing hard? <em>Yes.</em></p>
          
          <p>Does it catch everything? <em>No.</em></p>
          
          <p>Is it still worth doing? <em>I think so.</em></p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Make View Helpers a Little Less "Helpful"
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/09/23/make-view-helpers-a-little-less-helpful/' />
    <updated>
      2008-09-23T15:41:27PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/09/23/make-view-helpers-a-little-less-helpful/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I stumbled across a little bit of hidden Rails fun last night when I was trying to get the form_for method to <em>stop</em> wrapping error fields with extra div tags. Did you know that? Maybe you never noticed, but when you use the field helper methods, like text_field, password_field, etc, Rails will wrap fields with errors in a <code>&lt;div&gt;</code> with the class 'fieldWithErrors'.</p>
          
          <p>This was causing all sorts of grief for me in some JavaScript I was trying to write. At first I tried to go with the flow and fix my JS, but it got really hacky really fast. So I went on a little source-code spelunking to figure how to make the problem go away.</p>
          
          <p>In actionpack-2.1.0 there is a Proc attached to the <code>ActionView::Base.field_error_proc</code> class attribute. It's not documented in the RDoc, but this is also a <em>writable</em> attribute which means I can shut the damn thing up. Here's what it looks like in the original file, <code>GEM_HOME/actionpack-2.1.0/lib/action_view/helpers/active_record_helper.rb</code>:</p>
          
          <div class="highlight"><pre><span class="nb">require</span> <span class="s1">&#39;cgi&#39;</span>&#x000A;    <span class="nb">require</span> <span class="s1">&#39;action_view/helpers/form_helper&#39;</span>&#x000A;    &#x000A;    <span class="k">module</span> <span class="nn">ActionView</span>&#x000A;      <span class="k">class</span> <span class="nc">Base</span>&#x000A;        <span class="vc">@@field_error_proc</span> <span class="o">=</span> <span class="no">Proc</span><span class="o">.</span><span class="n">new</span><span class="p">{</span> <span class="o">|</span><span class="n">html_tag</span><span class="p">,</span> <span class="n">instance</span><span class="o">|</span> <span class="s2">&quot;&lt;div class=</span><span class="se">\&quot;</span><span class="s2">fieldWithErrors</span><span class="se">\&quot;</span><span class="s2">&gt;</span><span class="si">#{</span><span class="n">html_tag</span><span class="si">}</span><span class="s2">&lt;/div&gt;&quot;</span> <span class="p">}</span>&#x000A;        <span class="n">cattr_accessor</span> <span class="ss">:field_error_proc</span>&#x000A;      <span class="k">end</span>&#x000A;      <span class="o">.</span><span class="n">.</span><span class="o">.</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>My solution was to create a little file in <code>config/initializers</code> named <code>field_errors.rb</code> with this text:</p>
          
          <div class="highlight"><pre><span class="no">ActionView</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">field_error_proc</span> <span class="o">=</span> <span class="no">Proc</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">html_tag</span><span class="p">,</span> <span class="n">instance</span><span class="o">|</span>&#x000A;      <span class="n">html_tag</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>Et voila! Just a simple pass-through with no more fancy-pants markup. Putting stuff like this in separate files in the <code>initializers</code> directory keeps your config and environment files from getting out of hand.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Clip 1.0.0 Released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/09/19/clip-100-released/' />
    <updated>
      2008-09-19T19:17:33PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/09/19/clip-100-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Command-line parsing made short and sweet.</p>
          
          <h3>1.0.0 / 2008-09-19</h3>
          
          <ul>
          <li>Added support for mapping dashes to underscores for flags</li>
          <li>Define Clip.hash.remainder as a singleton method instead of reopening Hash</li>
          <li>remainder works with Clip.hash now</li>
          <li>Reimplemented Clip.hash to use a parser.</li>
          </ul>
          
          
          <p>Check out the docs at <a href="http://clip.rubyforge.org">http://clip.rubyforge.org</a>.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Oracle's Listening&hellip;
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/09/19/oracles-listening/' />
    <updated>
      2008-09-19T16:17:51PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/09/19/oracles-listening/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Following a re-tweet of @timoreilly, I went to check out <a href="http://oracle.com">Oracle's home pag</a>e today. Here's what I got:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/09/picture-1.jpg" alt="Picture 1.png" /></p>
          
          <p>So I put in my proposal and got:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/09/picture-2.jpg" alt="Picture 2.png" /></p>
          
          <p>I wonder if they'll actually consider what I proposed. For that matter, I wonder if they'll consider <em>any</em> of the proposals users send them.</p>
          
          <p>What is the bloody point?</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Book Review: "JavaScript: The Good Parts"
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/08/15/book-review-javascript-the-good-parts/' />
    <updated>
      2008-08-15T03:41:45PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/08/15/book-review-javascript-the-good-parts/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="/images/2008/08/dsc-0204.jpg" alt="DSC_0204.NEF" /></p>
          
          <p>It takes a brave author to give a book this title and keep it at 150 pages. The number of jokes about the proportionality of the "good parts" to the size of the book are endless. Be that as it may, when I saw this book at the <a href="http://www.powells.com/">Powell's</a> stand at <a href="http://en.oreilly.com/rails2008">RailsConf '08</a>, I figured anything written by Crockford on the subject of JavaScript was probably worth taking a look at.</p>
          
          <p><img src="/images/2008/08/javascript.jpg" class="left"/></p>
          
          <p>Given the diminutive nature of the the book, I suspect the author was attempting to do for JavaScript what Kernighan and Richie did for C with their book. I found an abused first edition copy of that C book and it taught me more about C than any other book. It is a triumph of restrained, focused technical writing (for other examples check out any of Kent Beck's books). At times I felt that some chapters in "The Good Parts" were superfluous, but I imagine that they were included for completeness if nothing else. For example, the second-longest chapter in the book is about the grammar of the language. While important, it seems disproportionately large to rest of the contents.</p>
          
          <p>If you have any exposure to JavaScript a good part of this book will be a review for you. However, there are three chapters worth reading for any JavaScript programmer. Chapter 3, <em>Objects</em>, discusses the properties of objects in JavaScript and covers everything from enumeration, to prototypes to attributes. Do you know why property enumeration is usually worthless as a debug tool? That's because of the prototype mechanism. If you use <code>typeof</code> filters and the <code>hasOwnProperty</code> method, you can significantly cut down the properties you dump on an object. I never knew that before.</p>
          
          <p>Chapter 4, <em>Functions</em>, is the real money-maker of the book. This is the chapter that I put the most post-its in and will certainly be one I'll have to revisit. Here Crockford goes into the different ways functions can be invoked and what the consequences are of each invocation style. There is a <em>lot</em> of good functional programming material here. He also discusses how Functions are intimately tied to Objects. Take heed, thar be dragons!</p>
          
          <p>Chapter 5, <em>Inheritance</em>, closes the loop on Functions and Objects. It explains the important differences between JavaScripts prototype-based inheritance model and the class-based model used in many other popular object-oriented languages. Like the previous chapter, this will be one that I'm sure I'll have to re-read in the future.</p>
          
          <p>It's taken a long time, but JavaScript seems to finally be growing up a bit. Given how truly awful it was to use it in the Early Days on more than one browser, it's a bit surprising that it has come to dominate the web landscape. Now it seems to be finally getting (begrudging) respect from the rest of the software community. Unfortunately to be effective, you really need to learn some of the deep voodoo that, to me, is a bit counterintuitive. Is the prototype approach really all that innovative? I'm not sure. Arguing that it's better than inheritance is like saying that something is better than poking yourself in the eyes with a sharp stick&#8212;faint praise indeed. But I do love passing around functions as objects with complete abandon. When I finally grokked this part of JavaScript, things really clicked for me.</p>
          
          <p>Is this book a must-read? No, probably not. If you're doing any serious JavaScript in the browser you're probably using one of the popular JavaScript frameworks out there that hide some of the yucky details of Function/Object interaction. But, lacking a decent language spec (and the ECMA spec sucks rocks), it's not a bad resource. It certainly won't take up much space in your bookshelf.</p>
          
          <p>2.5 stars out of 5.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Book Review: About Face 3
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/07/30/book-review-about-face-3/' />
    <updated>
      2008-07-30T04:35:18PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/07/30/book-review-about-face-3/
    </id>
    <content type='html'>
      <![CDATA[
          <p><a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0470084111"><img src="http://ecx.images-amazon.com/images/I/41PoEitkH1L._SL160_.jpg" class="left"/></a></p>
          
          <p>Alan Cooper's <em>About Face</em> is one of those pillars of UI/UX design, the reading of which is a rite of passage. I figured few books would be more appropriate as a capstone to my long list of design-oriented reads. It is nearly an institution in and of itself. Last night I turned the final page and ticked a pretty big 560-page book off of my reading list.</p>
          
          <p>There was enough material in this book that I adopted a new habit of using small post-its to mark important passages. This was helpful not only in referring back to earlier material in the book, but also in cementing some of the concepts in my head. This practice was so useful I've started doing it with other books too.</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/07/dsc-0124.jpg" alt="DSC_0124.JPG" /></p>
          
          <p>You may have noticed that the post-its don't really kick in until about 2/5 of the way through the book (Chapter 10 to be specific). I'll be honest and admit that the first nine chapters felt like a rehash to me. That's not to say they are without value, but they are a bit long-winded and, at times, excruciating in detail.</p>
          
          <p>So let me go ahead and get my beefs with the book out of the way. If you guessed that a book on its third edition that is nearly three inches thick would have some opinions you would be right. I don't have a problem with opinions&mdash;that's why I bought the book. But I did find the tone a bit much. Haughty, imperious, self-righteous and overbearing might be good descriptions too. There is a definite Moses-coming-down-from-the-mountain-with-fresh-tablets feel to this book. Mr. Cooper and his cohorts are here to set you straight. Don't let it turn you off. Think of these guys as that cranky-but-humorous guy you work with. He's a riot as long as you don't take what he says <em>too</em> seriously.</p>
          
          <p>Secondly this is a <em>long</em> book. I'm not convinced it really needed to be this long. There's an awful lot of repetition spread throughout the chapters. All of that is nit-picking really. This was an incredibly informative book. Again, the number of stickies you see should give you some idea of the value that I got from it. There is a <em>lot</em> a person can learn here.</p>
          
          <p>A big part of Cooper's philosophy is the focus on Goal-Oriented Design. The first part of the book spends a significant amount of ink describing the concepts of personas, goals and user research. As a developer I couldn't help but feel that a lot of this was <a href="http://c2.com/xp/BigDesignUpFront.html%20BDUF">Big Design Up Front</a>. "Just let the arch-priests of interaction design get it all working and <em>then</em> hand it off to the developers", they say. Hmmm, my experience tells me otherwise. To be fair, the authors attempt to address in the afterword of the book. But still...</p>
          
          <p>Once goal-oriented design is out of the way, the book picks up significantly by covering such concepts as the "excise" (tax) that systems place on humans, how people get into "flow" and how bad software can remove them from it or prevent it. One of my favorite little gems is a discussion of possible vs. probable. While it's <em>possible</em> that a user may want to choose one option over another, in cases where one option is disproportionately chosen over the other (the <em>probable</em>) use a default with an override. Think of how many times you've had to answer the same question over and over. It's pretty irritating, no?</p>
          
          <p><img src="http://upload.wikimedia.org/wikipedia/en/thumb/6/69/Magic_Cap_OS.gif/300px-Magic_Cap_OS.gif" class="left"/></p>
          
          <p>Another great section is the discussion of metaphor. Of the book's numerous examples, the ones demonstrating bad metaphor really shine. General Magic's Magic Cap interface is an absolute nightmare of conflicting messages and unnecessary navigation. What do these icons mean? If I rub the lamp do I get three wishes? If I push the rubber stamp am I getting notarized or checking out a book? Just what the hell is going on here?</p>
          
          <p>Cooper describes Magic Cap's failure as an over-reliance on <em>global metaphor</em>, where the system is essentially trapped in its slavish adherence to its metaphor. The rubber-stamp is there because real desks have rubber-stamps. But the need to be consistent with the desk metaphor weakens the interaction.</p>
          
          <p>Cooper proposes <em>idiomatic design</em> as the alternative to metaphors. User interfaces have been around long enough that a large number of interactions have already been figured out. Users are already familiar with them and, generally, don't require additional ramp-up to recognize them. Obviously there are a lot of <em>bad</em> idioms out there too so, like anything in life, take that advice with some degree of moderation.</p>
          
          <p>If there's one over-arching theme to the book it's that there are basically three groups of users you have to consider: beginners, intermediates and advanced users. The first and last groups are usually the smallest with the bulk of your user population consisting of perpetual intermediates. Beginners generally graduate quickly to intermediates. From there it's a much larger jump to advanced users. However, a lot of interfaces are often geared towards beginners. I would suspect (with little evidence to back this up) that a lot of this has to do with too much focus on customer-acquisition.</p>
          
          <p>Without a means for potential intermediate users to shed their training wheels, users can get quickly frustrated. However you can't build a power-user-only application either. Very few users run the gauntlet from beginner all the way to the advanced user. So the trick to is spend the correct amount of effort on features that match the proportions on your users.</p>
          
          <p>With this idea in mind the final eleven chapters of the book provide a fantastic, detailed look at how the principles described above apply to common visual idioms. For example, in the chapter devoted to menuing systems, the authors describe not as the sole interface, but a "pedagogic vector" for beginners. When combined with shortcut keys and accelerators, menus provide a way for beginners to graduate to intermediates and beyond.</p>
          
          <p>Another important theme in the last section is just how far software really needs to come to meet users. The authors review example after example of "computer-first" design where the user seems be treated as a necessary irritant. One of my favorite passages in the entire book is on the topic of wizards: "Programmers like wizards because they get to treat users as peripheral devices."</p>
          
          <p><img src="http://farm4.static.flickr.com/3108/2694787797_3c7d0ffb93_m.jpg" class="left"/></p>
          
          <p>Another chapter is devoted just to disk storage and how most of our idioms around disk storage should really be the computer's problem, not the users. At first this kind of talk seems like the crazy guy in Hyde Park, but after some reflection I think he's right. There is an awful lot of software that couldn't care less about the user. We can do better than this. We <em>should</em> do better than this.</p>
          
          <p>One technical detail of the book that I just love is how they integrate images with captions. A particular pet peeve of mine is when images and captions seemed to be dropped into the text in willy-nilly fashion with little regard to the reader's flow. When figures that are referred to in the text aren't placed close to the text, I have to context switch and try not to lose my place. I either have to remember to look at the figure soon, or I have to switch to the figure immediately and then find my place back in the text. It drives me nuts. Whoever did the layout for <em>About Face 3</em> obviously thought about the usability of the text. God bless you, whoever you may be.</p>
          
          <p>While I'm pretty sure that I wouldn't want to have to talk to any of these guys at cocktail party (I doubt I'd get a word in edge-wise), they put together an incredibly informative book. I'm pretty sure I'll need those sticky notes in the future to revisit a number of concepts presented here.</p>
          
          <p>5 out 5 stars.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          ActiveRecord Fun Thay May Stump Only Me
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/07/24/activerecord-fun-thay-may-stump-only-me/' />
    <updated>
      2008-07-24T04:52:15PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/07/24/activerecord-fun-thay-may-stump-only-me/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I've just spent the last two hours pulling my hair out trying to get Single-Table Inheritance (STI) working with associations in <code>ActiveRecord</code>. After essentially walking through all of the possible <code>ActiveRecord</code> options in this setup, I finally stumbled upon a configuration that seems to work. So this post is an attempt to help the next poor bastard who is Googling in earnest for a solution to a similar problem.</p>
          
          <p>So let's start with the domain model. I'm too spent at this point in the evening to port this to one of the standard examples. Instead I'll expose you to the domain of my particular problem. The app I'm working on is one that tracks (non-financial) lending transactions between two individuals. The parties involved, the item in question and when it's due are all tracked in the <code>Transaction</code> model (and <code>transactions</code> table). A <code>Transaction</code> has a number of states it walks through, using the <a href="http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/%20acts_as_state_machine%20SVN%20repository"><code>acts_as_state_machine</code></a> plugin. These state transitions are triggered by opaque-looking URLs that are sent via email to either party. These are one-time use actions that once consumed are no longer available. When an <code>Action</code> instance is created it also has a <code>before_save</code> callback that generates a unique ID (used in the URL) using <code>Digest::SHA1</code>.</p>
          
          <p>So my plan was to have my <code>Transaction</code> class write one or more <code>Action</code> records for each possible action based on my state transitions. Take a look at the state diagram below:</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/07/state-transitions.jpg" alt="state-transitions.png" /></p>
          
          <p>I want to encapsulate the actual work to be performed within the <code>Action</code> instance the user invokes by following the link in their email. So my plan is to use STI to have different sub-classes of <code>Action</code> that operate on a transaction and march it forward to its next state polymorphically.</p>
          
          <p>Now STI may appear to be total overkill for this problem, but here are my reasons for going this route:</p>
          
          <ul>
          <li>I want to have these opaque IDs written down somewhere to associate a specific action with a URL</li>
          <li>When the action is complete, I want to remove the record so it can't be performed again</li>
          <li>The state for a given <code>Transaction</code> can have more than one possible action. I want a separate for each action.</li>
          </ul>
          
          
          <p>Whew. Okay, clear so far? So my initial code looked something like this:</p>
          
          <div class="highlight"><pre><span class="nb">require</span> <span class="s2">&quot;digest/sha1&quot;</span>&#x000A;    &#x000A;    <span class="k">class</span> <span class="nc">Action</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>&#x000A;    &#x000A;      <span class="n">belongs_to</span> <span class="ss">:transaction</span>&#x000A;      <span class="n">before_save</span> <span class="ss">:create_guid</span>&#x000A;    &#x000A;      <span class="k">def</span> <span class="nf">create_guid</span>&#x000A;        <span class="n">sha1</span> <span class="o">=</span> <span class="no">Digest</span><span class="o">::</span><span class="no">SHA1</span><span class="o">.</span><span class="n">new</span>&#x000A;        <span class="n">sha1</span><span class="o">.</span><span class="n">update</span> <span class="n">transaction_id</span><span class="o">.</span><span class="n">to_s</span>&#x000A;        <span class="n">sha1</span><span class="o">.</span><span class="n">update</span> <span class="nb">type</span><span class="o">.</span><span class="n">downcase</span>&#x000A;        <span class="n">sha1</span><span class="o">.</span><span class="n">update</span> <span class="no">DateTime</span><span class="o">.</span><span class="n">to_s</span>&#x000A;        <span class="nb">self</span><span class="o">.</span><span class="n">guid</span> <span class="o">=</span> <span class="n">sha1</span><span class="o">.</span><span class="n">hexdigest</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="k">class</span> <span class="nc">ReturnAction</span> <span class="o">&lt;</span> <span class="no">Action</span>&#x000A;      <span class="k">def</span> <span class="nf">execute</span>&#x000A;        <span class="n">transaction</span><span class="o">.</span><span class="n">return!</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="k">class</span> <span class="nc">AbortAction</span> <span class="o">&lt;</span> <span class="no">Action</span>&#x000A;      <span class="k">def</span> <span class="nf">execute</span>&#x000A;        <span class="n">transaction</span><span class="o">.</span><span class="n">abort!</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    &#x000A;    <span class="k">class</span> <span class="nc">DisputeAction</span> <span class="o">&lt;</span> <span class="no">Action</span>&#x000A;      <span class="k">def</span> <span class="nf">execute</span>&#x000A;        <span class="n">transaction</span><span class="o">.</span><span class="n">abort!</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>It seemed like a good idea at the time, but the strange thing was that no matter which incantation I tried, I simply couldn't create a new <code>Action</code> instance and have it write a record to the database. This simply didn't work:</p>
          
          <div class="highlight"><pre><span class="no">ReturnAction</span><span class="o">.</span><span class="n">create!</span> <span class="ss">:transaction_id</span> <span class="o">=&gt;</span> <span class="mi">1</span>&#x000A;    </pre>
          </div>
          
          
          <p>There were no errors on the returned object. No exceptions were thrown. No queries to the database and certainly no insert statements executed. Just complete and utter silence. Out of desperation, as much as anything else, I removed the <code>belongs_to</code> declaration from the <code>Action</code> class and instead declared a <code>has_many</code> on the <code>Transaction</code> class. Voila! It worked like a champ.</p>
          
          <p>After a bit of thought, the <code>has_many</code> association makes complete sense to me in the case where we want to create new <code>Action</code> instances for a particular <code>Transaction</code>. However, if you look in the code above, the <code>execute</code> methods of each sub-class are referring to a <code>transaction</code> object/method&mdash;which I no longer have. However I don't necessarily need the full-blown <code>belongs_to</code> association here. I can just fake the bits I want in the parent <code>Action</code> class like so:</p>
          
          <div class="highlight"><pre><span class="k">class</span> <span class="nc">Action</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>&#x000A;      <span class="k">def</span> <span class="nf">transaction</span>&#x000A;        <span class="vi">@transaction</span> <span class="o">||=</span> <span class="no">Transaction</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="nb">self</span><span class="o">.</span><span class="n">transaction_id</span><span class="p">)</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
          </div>
          
          
          <p>So none if this is particularly earth-shattering. Sorry folks, no great gems of philosophical wisdom today. Just one man's small accomplishment blown completely out of proportion.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 0.0.6 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/07/10/clip-version-006-has-been-released/' />
    <updated>
      2008-07-10T17:12:27PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/07/10/clip-version-006-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why
          should you have to create a Hash, then create a parser, fill the Hash
          out then throw the parser away (unless you want to print out a usage
          message) and deal with a Hash? Why, for Pete's sake, should the parser
          and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>0.0.6 / 2008-07-10</h3>
          
          <ul>
          <li><p>Fixed a bug with getting the 'remainder' when only flags are declared.</p></li>
          <li><p><a href="http://clip.rubyforge.org">http://clip.rubyforge.org</a></p></li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Military History
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/28/military-history/' />
    <updated>
      2008-06-28T16:15:19PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/28/military-history/
    </id>
    <content type='html'>
      <![CDATA[
          <p>In addition to technical geekery and social commentary, one of my favorite intellectual pursuits is the study of military history. It's one of my many interests that makes me so very thankful that I met my wife when I did or I would never have had a date in my adult life.</p>
          
          <p>I am not a pro-war person. Anyone who reads <em>good</em> military history will often find that the best historians are quite <em>anti-war</em>. I had the opportunity to see <a href="http://www.liberationtrilogy.com/%20Rick%20Atkinson's">Rick Atkinson</a> speak in Seattle last winter as he was promoting his book, <em>Day of Battle</em>. He has written several titles about both WWII and Iraq and said that all of his books as anti-war and hopes his readers understand that. No historian has summed that notion up as well as <a href="http://www.google.com/url?q=http://books.google.com/books%3Fas_auth%3DJohn%2BKeegan&amp;sa=X&amp;oi=book_group&amp;resnum=1&amp;ct=title&amp;cad=author-navigational&amp;usg=AFQjCNH1nGziOaBfW4F8cI42VFrbtcCdYw%20John%20Keegan">John Keegan</a> in his introduction to <em>The History of Warfare</em>.</p>
          
          <p>To study war is not necessarily to glorify it. To be sure, a good bit of the military history bookshelf is filled with martial hagiography (see Ambrose, Stephen), but to those who study the history with more than a simple fascination of the technologies and armies there is a rich depth of human experience and tragedy to explore.</p>
          
          <p><img src="http://farm4.static.flickr.com/3083/2378828503_8a9e683206_m.jpg" class="left"/></p>
          
          <p>Like most men (and I'm sure that 99.9% of all military historians are male), I began with that very boyish fascination with all things violent and martial. As I grew older I realized that this was a silly childish interest. I either needed to stop reading about this subject, or I needed to understand it better. I chose the latter in an attempt to cull meaning from so many centuries of meaningless slaughter.</p>
          
          <p>Humans go to war for a variety of reasons–most of them not good. Greed, hatred, and lust for power have fueled more than their fair share of conflict and tragedy. However that doesn't mean that I think all war is useless. There are some things worth fighting and dying for, but those moments are few and far between in human history. While I cannot condone military action in most of the cases in which it occurs, I believe that it is an inevitable part of the human experience. We were simply bred to beat each others brains out. This is a depressing and tragic conclusion, but I believe that human history is on my side when I make that statement.</p>
          
          <p>So what's the point of reading military history? If all we are going to do is make the same mistakes over and over again what possible good can from studying the past? Despite my pessimistic outlook on the short-term chances of humanity straightening itself out, I think in long-term we may learn from our mistakes. Military history is nothing if not a study of mistakes. Yes the Hannibals, Napoleons and Pattons of history get the accolades, but there isn't nearly as much to learn from their successful campaigns. We need to look at the spectacular failures too.</p>
          
          <p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Jacques-Louis_David_017.jpg/300px-Jacques-Louis_David_017.jpg" class="left"/></p>
          
          <p>For example, we can learn far more from the fateful decisions of both Napoleon and Hitler to campaign in the Russian winter. While the technical reason for their defeat was weather and logistics, the true cause of their downfall was hubris. It wasn't that neither failed to comprehend the risks, but rather they felt that their leadership and the elan of their troops transcended reality. Can anyone else think of a recent example where a leader ignored the facts on the ground in pursuit of their own personal policy? Hmm? Anyone?</p>
          
          <p>Another fine example is the book I'm currently reading, Mr. Atkinson's aforementioned <em>The Day of Battle</em>. The Italian campaign is an oft-forgotten part of World War II. This is due in no small part because there was very little to celebrate in that campaign. No gutsy fortitude like Guadalcanal or Stalingrad, no tragedy like Poland or Saipan, just lots of dumb decisions that required a tremendous amount of cannon-fodder to achieve victory.</p>
          
          <p>Few campaigns offer such a textbook example of group-think gone horribly wrong as the Allies in Italy during World War II. From Churchill and Roosevelt, to Eisenhower, to the theater commanders, everyone in the chain of command was eager to cast what they saw with their own eyes in terms of what they desired, not what the actual realities on the ground were. While we may not be in a war in our day-to-day work, each of us can certainly come up with examples where group-think led everyone to bad conclusions.</p>
          
          <p>The other valuable outcome of studying military history to come to a better understanding of just what the cost of war truly is. Obviously anyone who has <em>not</em> experienced combat cannot imagine the horrors of that experience. I thank my lucky stars that I never had to go to war. But I feel that it's disingenuous to rail against the horrors of war without making an attempt to understand them.</p>
          
          <p><img src="http://farm4.static.flickr.com/3272/2338835862_6eed1417f1_m.jpg" class="left"/></p>
          
          <p>I attended the University of Oregon and there are few places on earth that have a stronger innate anti-war bias. I have no problem with the pursuit of peace, but to do so in ignorance serves no one. It's vital that we all understand what the consequences of going to war are. I fear that the cavalier attitude with which the United States has prosecuted the Iraq War and insulated the public from the horrifying facts on the ground only serves to keep us ignorant of the true costs of war. This is not a game of cops and robbers–people are dying daily for questionable causes, to say nothing of the long-term political consequences. But I digress...</p>
          
          <p>One final reward of the study of military history is to recognize how leadership within a corporate, in the purest sense of the word,  setting can work. I don't mean the famous generals such as Grant, Lee or Washington. Rather, a kind of leadership that few successfully execute consciously. Instead it is the <a href="http://en.wikipedia.org/wiki/Joshua_Chamberlain%20The%20Hero%20of%20Little%20Rount%20Top">Joshua Chamberlains</a> of the world that provide insightful, meaningful case studies of what true leadership is. Most of us don't work in groups of one thousand or more, but instead in "squads" of ten or less people. Learning how Captains and Sergeants command, push and prod their troops and maintain esprit de corps is worth the time of anyone who is interested in exercising any form of leadership.</p>
          
          <p>It's rare that at the end of a good military history read I don't feel the need to weep. Maybe I'm a sucker for heartache but I can't help but feel just a teeny bit smarter after turning the last page of a well-written piece of military history. So before parting, let me leave you with a short list of great military reads (in no particular order) that I've come across over the years:</p>
          
          <ul>
          <li><em>The Peloponnesian War</em> &mdash; Thucydides</li>
          <li><em>The Civil War (Trilogy)</em> &mdash; Shelby Foote</li>
          <li><em>At Dawn We Slept</em> &mdash; Gordon Prange</li>
          <li>Just about anything by John Keegan</li>
          <li><em>The Best and the Brightest</em> &mdash; David Halberstam</li>
          <li><em>We Were Soldiers Once...And Young</em> &mdash; Harold G. Moore</li>
          <li><em>The Rise and Fall of the Great Powers</em> &mdash; Paul Kennedy</li>
          <li><em>Diplomacy</em> &mdash; Henry Kissinger</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          gemdoc completion in zsh
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/25/gemdoc-completion-in-zsh/' />
    <updated>
      2008-06-25T16:30:24PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/25/gemdoc-completion-in-zsh/
    </id>
    <content type='html'>
      <![CDATA[
          <p>This week I stumbled upon Stephen Celis' awesome bit of shell-fu, <a href="http://stephencelis.com/archive/2008/6/bashfully-yours-gem-shortcuts%20gemdoc">gemdoc</a>, which allows you to quickly get to the HTML docs for installed gems via command-line. Unfortunately I abandoned bash years ago for zsh and Stephen's shell bits needed a little porting. For me, zsh, is a bit like swiss-army knife where about 95% of it is a mystery to me, but the 5% I use I couldn't live without. So simply switching back to bash is a no-go.</p>
          
          <p>My setup is little-bit complicated, but I believe the following, stripped-down, recipe should work:</p>
          
          <div class="highlight"><pre><span class="nv">GEMDIR</span><span class="o">=</span><span class="k">$(</span>gem env gemdir<span class="k">)</span>&#x000A;    <span class="nv">OPEN</span><span class="o">=</span><span class="k">$(</span>whence xdg-open <span class="o">||</span> whence open<span class="k">)</span>&#x000A;    &#x000A;    gemdoc<span class="o">()</span> <span class="o">{</span>&#x000A;      <span class="k">${</span><span class="nv">OPEN</span><span class="k">}</span> <span class="nv">$GEMDIR</span>/doc/<span class="sb">`</span><span class="k">$(</span>which ls<span class="k">)</span> <span class="nv">$GEMDIR</span>/doc | grep <span class="nv">$1</span> | sort | tail -1<span class="sb">`</span>/rdoc/index.html&#x000A;    <span class="o">}</span>&#x000A;    &#x000A;    _gemdocomplete<span class="o">()</span> <span class="o">{</span>&#x000A;      <span class="nv">reply</span><span class="o">=(</span> <span class="sb">`</span><span class="k">$(</span>which ls<span class="k">)</span> <span class="nv">$GEMDIR</span>/doc<span class="sb">`</span> <span class="o">)</span>&#x000A;    <span class="o">}</span>&#x000A;    &#x000A;    compctl -K _gemdocomplete gemdoc&#x000A;    </pre>
          </div>
          
          
          <p><em>Update 6/25/08-10:30</em>: Updated to work for both Penguins and Macs.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Launch Day!!!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/24/launch-day/' />
    <updated>
      2008-06-24T04:17:58PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/24/launch-day/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I've spilled a lot of (virtual) ink in this blog, but almost none of it about what I do all day. That's because I've been working at a startup in "stealth mode" for darn near two years and haven't been able to really say much about it. Until today.<a href="http://evri.com" title="Evri" target="_blank"></a></p>
          
          <p><a href="http://evri.com" title="Evri" target="_blank"><img src="http://livollmers.net/wp-content/uploads/2008/06/picture-4.jpg" alt="Picture 4.png" /></a></p>
          
          <p>Today at <a href="http://evri.com%20Evri">Evri</a> we're launching the beta version of our site. If you head to the <a href="http://evri.com%20Evri">home page</a> and signup, you'll get yourself a free set of brand-new shiny credentials that will give you the keys to data-surfing heaven.
          <img src="http://blog.evri.com/wp-content/uploads/2008/06/evri-homepage-aaman.png" alt="homepage" />
          The <a href="http://blog.evri.com/index.php/2008/06/24/little-room/%20Evri%20Blog">company blog post</a> does a good job of highlighting what we have available, but for the truly lazy I'll give you the quick highlights.</p>
          
          <p>First, is the home page which gives you a look at entities and their relations as we understand them currently. We start out with lists ranking the top people, places and things. In addition to popularity, you can also see who is rising and falling in popularity over time. All of these lists are clickable and enable our super-whizzy widget which provides a nice way of pivoting between entities, all the while getting related content.</p>
          
          <p>This is one of my favorite parts of the product, as it's really easy to just get lost wandering around from link to link to see how things are related. It's like a big six-degrees-of-Kevin-Bacon game, except that you can do with just about anything. Part of that link-hopping experience is visiting specific pages about each entity.</p>
          
          <p>Here you can find more detailed content about an entity. Currently these details comes from Wikipedia, but we anticipate adding several other specific sources of structured content. And of course, these pages link you to other pages, so between the hub-and-spoke visualization and the detail pages you can spend quite a bit of time just data-grazing.
          <img src="http://blog.evri.com/wp-content/uploads/2008/06/bon-iver.png" alt="evri profile page for bon iver" />
          So take it for a spin and have some fun exploring! Give us your feedback (a link is at the top of each page) and let us know what you like and don't like. Most importantly, stay tuned. This is just the beginning for us, we have some pretty exciting stuff in the works and you won't want to miss out.</p>
          
          <p>Things have been a bit nutty the last few days&#8211;as they are for any release&#8211;but it will be worth it for the satisfaction of finally lighting this candle.</p>
          
          <p>Enjoy!</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Smorgasm!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/21/smorgasm/' />
    <updated>
      2008-06-21T04:13:31PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/21/smorgasm/
    </id>
    <content type='html'>
      <![CDATA[
          <p>While on vacation last week, my wife and some friends of ours solved the age-old problem of melting the chocolate <em>and</em> the marshmallow in a s'more. You stuff a chunk of chocolate (we prefer good old-fashioned Hershey's waxy American milk chocolate) <em>inside</em> the mallow and then toast the entire unit.</p>
          
          <p><a href="http://www.flickr.com/photos/36455265@N00/2579055859/"><img src="http://farm4.static.flickr.com/3164/2579055859_8f20a4194c_m.jpg" alt="DSC_0182.JPG" /></a></p>
          
          <p>Do you see where this is going? No? How 'bout this?</p>
          
          <p><a href="http://www.flickr.com/photos/36455265@N00/2579061059/"><img src="http://farm4.static.flickr.com/3179/2579061059_fc9547bb05_m.jpg" alt="DSC_0190.JPG" /></a><a href="http://www.flickr.com/photos/36455265@N00/2579890496/"><img src="http://farm4.static.flickr.com/3031/2579890496_db32c29b53_m.jpg" alt="DSC_0187.JPG" /></a><a href="http://www.flickr.com/photos/36455265@N00/2579882146/"><img src="http://farm4.static.flickr.com/3126/2579882146_19007c158c_m.jpg" alt="DSC_0178.JPG" /></a></p>
          
          <p>Amen sisters and brothers. Now <em>that's</em> a properly-melted s'more.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Book Reviews: Designing the Obvious/Designing the Moment
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/20/book-reviews-designing-the-obviousdesigning-the-moment/' />
    <updated>
      2008-06-20T04:55:00PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/20/book-reviews-designing-the-obviousdesigning-the-moment/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I've been on a usability/design kick for about the last six months. Somehow I stumbled across a link to <a href="http://rhjr.net">Robert Hoekman Jr's site</a> which was described as great design books for programmers. I fully recognize the fact that I really don't have that little spark that good designers have, but I'd like to be better at it than I am. So I've been eager to find usability and design books that work for visually-clumsy folks like me. Robert Hoekman's pair of books, <em>Designing the Obvious</em> and <em>Designing the Moment</em> were wonderful additions to my growing design-for-code-dorks library.</p>
          
          <p>The covers of both books were what initially piqued my interest. Both have very simple white covers. Unlike a lot of design books, this one isn't about showing off a bunch of pyrotechnics on the cover (see Jenifer Tidwell's <em><a href="http://designinginterfaces.com/">Designing Interfaces</a></em> which includes a colored version of O'Reilly's usual animal lithograph). I figured anyone willing to put such a sparse cover on the page was pretty confident about the content inside. I also really liked the fact that the form-factor of both books is smaller than the usual trade paperback and comes in at a very economic 200 pages, or about 1/4" thick.</p>
          
          <p>Alright, I'll admit that I was taken in by the author's use of my <a href="http://blog.livollmers.net/index.php/2008/03/13/one-geeks-aesthetics/%20Previous%20post%20of%20font%20aesthetics">favorite font, Gill Sans</a>. I just love this font (it's the font this blog is set to if you don't override CSS) because it's clean and elegant with a minimum&#8211;or complete absence&#8211;of decorative fuss. Unlike the Pragmatic Programmers or O'Reilly the publisher, New Riders, doesn't seem enforce a particular font style for their books. Therefore I think it's safe to assume that the author made a conscious decision to use this font which, at a microscopic level, supports many of the notions of simplicity and cleanliness presented in the books.</p>
          
          <h2><a href="http://rhjr.net/dto/">Designing The Obvious</a></h2>
          
          <p><a href="http://www.amazon.com/Designing-Obvious-Common-Approach-Application/dp/032145345X%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D032145345X"><img src="http://ecx.images-amazon.com/images/I/31tDU7ayPvL._SL160_.jpg" class="left"/></a></p>
          
          <p>His first book, <em>Designing the Obvious</em> focuses on translating from what a user needs to creating workable screen-flows. While I've knocked out several smaller design books, I've been slowly making my way through Alan Cooper's seminal <em>About Face</em> in which the concept of <em>goal-oriented design</em> is introduced. Hoekman's book is the second text I've come across that offers a contrasting opinion on goal-oriented design the author calls <em>task-oriented design</em>. Whereas Cooper's approach is to begin design by understanding a user's goal within the larger context of their lives or career aspiration, <em>task-oriented design</em> is focused on more immediate desires.</p>
          
          <p>A goal-oriented design might start with something like "Anna is a small-business owner who wants to balance career and family. She needs particular help with payroll for her small three-person company." A task-oriented design might start with "A user with a small-company must be able to setup employees with a minimum of fuss: perhaps just name, address and social security number". Hoekman even titles one of his chapters "Understand Users, Then Ignore Them".</p>
          
          <p>Each chapter is tightly-focused on a single concept and few supporting ones. For example, the chapter titled "Turn Beginners Into Intermediates, Immediately" spends a thrifty thirty-five pages outlining the basic distribution of user expertise (hint: the big fat blob in the middle are the intermediate users) and then enumerating several concrete examples of how to serve the intermediates, how to get the beginners to immediates as quickly as possible, and how to keep the advanced users still engaged.</p>
          
          <p>The ability of Hoekman to outline a concept and back it up with several concrete examples is the real strength of the book. This is not a patterns or recipe book. Similarly it's not a grand philosophical tome (see Cooper, above). Instead it's a very practical work intent on getting the ideas across, but leaving plenty of room for the reader to explore on their own.</p>
          
          <p>The fact that he gets such a rich amount of information is such a small package is a testament to the author's well-thought, lean design approach.</p>
          
          <p>5 out of 5 stars</p>
          
          <h2><a href="http://rhjr.net/dtm/%20Designing%20The%20Moment">Designing The Moment</a></h2>
          
          <p><a href="http://www.amazon.com/Designing-Moment-Interface-Design-Concepts/dp/0321535081%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0321535081"><img src="http://ecx.images-amazon.com/images/I/41AfJf7CygL._SL160_.jpg" class="left"/></a></p>
          
          <p>Hoekman's second title focuses specifically on web application design. Unlike his previous book which is more philosophical and abstract, <em>Designing The Moment</em> is much more concrete. With thirty-one chapters spread out over 220 pages, each chapter is tightly-focused. Those chapters are split up into seven major sections.</p>
          
          <p>The first section is titled <em>Getting Oriented</em> and focuses on getting the user oriented with your site. He delves into how users' eyes flow over a page, navigation, links and dealing with common web paradigms like tag clouds.</p>
          
          <p>The second section, <em>Learning</em>, provides specifics about getting users "over the novice hump". This theme was an important one in his first book and here he offers several ways to teach your users about your site.</p>
          
          <p>The third section, <em>Searching</em>, walks you through the pitfalls of search interface design. A common theme in both books is that of a <a href="http://en.wikipedia.org/wiki/Poka-yoke">poke-yoka,</a> which means to fool-proof in Japanese. The term was originally derived from Toyota's Production System which was developed in the '80's (note: Toyota is currently kicking serious rear-end in the car biz). Here he uses the term <em>poke-yoka device</em> to mean any mechanism that will help prevent the user from hurting themselves. This is not about treating users as idiots but rather hiding ugly implementation details away from the users if at all possible. For example, you if need users to enter a phone number in a particular format, design a form that makes so that users enter phone numbers in that format. Don't just give them a text field and then complain when they don't get it right.</p>
          
          <p>Moving on we get to fourth section, titled <em>Diving In,</em> where we really start to get into the nitty-gritty details of things like media player controls, form layout, wizards, and validation. This is the longest section of the book and meatiest. Again, Hoekman nails the concepts with well-chosen representative examples and solutions.</p>
          
          <p>The fifth section, <em>Participating</em> focuses on the mechanics of features commonly associated with "social-networking" web applications. This chapter ranges from concrete implementation recommendations like how to build user profiles, to more abstract, strategic concepts like how to embrace user feedback and how to channel your most vocal users.</p>
          
          <p>The sixth section, <em>Managing Information</em>, provides some tips on helping users digest your site's contents. Tips here include how to effectively use syndication, dealing with tags and folksonomies, where drag-and-drop is appropriate and dealing with system notifications.</p>
          
          <p>The final section, <em>Moving On</em>, embraces I concept I first saw articulated in 37Signals' <em><a href="http://gettingreal.37signals.com/toc.php">Getting Real</a></em> . Don't build your apps as walled gardens where you make every attempt to keep your users from leaving. This ain't Vegas you aren't a casino. Yes, you want to give users another chance to reconsider and you certainly want to know why they're leaving, but don't be a jerk about it. This section offers some guidelines for parting ways with your users. I think to design something without this in mind is to the fact that not everyone is going to dig what you've built. Let them go easily and don't make things worse by making parting a painful experience.</p>
          
          <p>I loved this book as much as Hoekman's first title. Both are handy references I'll keep nearby.</p>
          
          <p>5 out 5 stars.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Somebody Hates Me
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/19/somebody-hates-me/' />
    <updated>
      2008-06-19T22:43:49PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/19/somebody-hates-me/
    </id>
    <content type='html'>
      <![CDATA[
          <p>When I see a forecast like this, I gotta think that life just isn't fair sometimes...</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/06/picture-2.jpg" alt="Picture 2.png" /></p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          It Would Be Nice If...
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/14/it-would-be-nice-if/' />
    <updated>
      2008-06-14T22:00:02PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/14/it-would-be-nice-if/
    </id>
    <content type='html'>
      <![CDATA[
          <p>When talking about building software, few sentences set off more red flags than those beginning with "it would be nice if..". I don't mean some variation of this phrase, I mean exactly this phrase. It's like those words are a specific code-phrase for "speculative features coming your way!"</p>
          
          <p>What the heck is "nice" anyway? The very language of that statement does nothing more than imply; it makes no assertions and offers no proof. A piece of candy is nice. So are flowers and a new house. But those things all require widely varying levels of planning, effort and cost. So "nice" isn't a very precise word and certainly fails us when we try to evaluate what goes into our product and what stays on the sidelines for further evaluation.</p>
          
          <p>In a geek-heavy setting, such as my workplace, I often observe this phrase used as a desire to establish authority in a conversation. This happens when features are proposed not so much for their value, but as a way of showing how deep and nuanced the proposer's understanding of the domain is. For example in a brainstorming session we had recently about new visualizations for rich data structures, a lot of IWBNI ideas were proposed that were fairly baroque and hard to imagine being interesting to a wider audience. In this instance instead of focusing on the goal, making sense of a big pile of information, the exercise turned into a demonstration of various participants' grasp of market dynamics, web trends and cutting-edge features. You can imagine how useful the final set of ideas were.</p>
          
          <p>Another issue with IWBNI features is that they are often very implementation-focused. For example if you are working on a web service that is consumed by other services, you might want to track usage statistics to generate a regular report to see who is using it. The real feature is tracking usage, but that original need can easily be obscured by an overly-specific implementation. Ideas for these features often emerge out of the system constraints that are a result of the system design, not necessarily a natural outcome of the problem domain. Differentiating between these two is probably one of the hardest things to do in any kind of design.</p>
          
          <p>It's vital to differentiate between these because IWBNI features seem especially prone to calcifying the current implementation. Back to our web services example, let's say we implement this usage report, which dumps a text file every hour of usage statistics. We love that feature so much that we hook it up to our automated monitoring system as it seems like a nice way to monitor the "heartbeat" of the system. However, down the road we discover that we need a maintenance window that makes the file unavailable for a period of time that causes the monitoring system to alert us. Now we have a choice: we can patch up the monitoring to manage this exception, or we can re-think just how important the text-file interface is.</p>
          
          <p>In this case I would argue that the text-file dump might instead be replaced with a simple web-request. When the system is in its maintenance mode, it could still answer questions about general availability (which is what we were originally interested in) without tying a more specific feature, usage, to monitoring. I don't think that making the monitoring script more sophisticated is the right answer. More complexity there means a higher likelihood of breaking and it spreads some very implementation-specific details to other parts of the system.</p>
          
          <p>The features and attributes of a system can be viewed like walls in a house. Some are load-bearing and some are not. The load-bearing features are those that without which, the house would simply fall. In your applications these are features that are the very essence of the software. An application like Quicken has an awful lot of walls. The load-bearing features of Quicken are the ledgers and reconciliation process. Without these, the other features of Quicken are irrelevant.</p>
          
          <p>However features like downloading transactions over the internet or viewing pie-charts are mostly decorative. This doesn't mean they are without worth, but they are not as essential as the load-bearing features. These could be removed and Quicken's essence would still be preserved. Quicken is certainly more useful with these features, but those aren't the features that generally drive users to use it. (NB: This is not to say Quicken is a well-designed application. But I'll save that for another post...)</p>
          
          <p>You can move the decorative walls around to change the space of a room without major fuss. Moving a load-bearing wall is a fairly major operation and has a huge impact on the character of the house and requires extra planning so that the house doesn't collapse during the change. The danger of IWBNI is that it's easy to confuse these features with essential "load-bearing" ones. Worse yet, the compound of multiple IWBNI features can end up as a load-bearing walls that are difficult to move. Revisiting our web services example, if more features like the text file were piled on and external parties began to rely on these, it would become much more difficult to move these in the future. It's not difficult to imagine getting to a point where the original role of the web service is obscured by all of the other tangential bells and whistles.</p>
          
          <p>Sometimes IWBNI features are user- or domain-driven. These seem like they might have a better chance of withstanding the litmus test. More often than not these ideas end up obscuring the core of the application, but these can be, relatively, easy to test with tools like mockups, user interviews and usability testing. In supporting services it's much harder to evaluate these features. How do we do usability testing for a web service? Does the variable for a request belong in the path or as a query parameter? How do we figure out what consumers want? This is tricky because in this case we're designing something by geeks, for geeks. This doesn't mean that it's okay to pile on a bunch of implementation details and stop thinking about separating our load-bearing features from our decorative ones. But it does mean that we have to be extra vigilant about the IWBNI features and view them with a particularly suspicious eye.</p>
          
          <p>So I think this is the real trick&#8211;whether you are a visual designer, information architect or software developer&#8211;is to separate the essential from the decorative. Being able to sort features in this way gives you a chance to properly evaluate the cost/benefit tradeoffs. Without this I believe it is much more difficult to clearly see the value of a feature and its overall impact on the system.</p>
          
          <p>So let me offer up a challenge: treat IWBNI as a codeword for something requiring exceptional scrutiny. When something is proposed as a IWBNI feature, regard it with a suspicious eye. When you feel yourself proposing a IWBNI feature, think long and hard about whether or not it is really "nice" or whether it might "essential" or "superfluous". And for goodness' sake, don't get hung up on your IWBNI features. If they're "nice" they probably aren't a core feature anyway. You're a smart, creative person and you'll have other ideas in the future.</p>
          
          <p>And finally, let's remember the most common trait that nearly all IWBNI features share...</p>
          
          <div style="font-size: 72px; font-weight: bold;">YAGNI*</div>
          
          
          <ul>
          <li>Ya ain't gonna need it</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 0.0.5 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/13/clip-version-005-has-been-released/' />
    <updated>
      2008-06-13T22:06:04PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/13/clip-version-005-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why should you have to create a Hash, then create a parser, fill the Hash out then throw the parser away (unless you want to print out a usage message) and deal with a Hash? Why, for Pete's sake, should the parser and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>0.0.5 / 2008-06-12</h3>
          
          <ul>
          <li>Removed sample_parser from bin (technomancy)</li>
          <li>fix a stupid bug causing an infinite loop for empty ARGV (technomancy)</li>
          <li><a href="http://clip.rubyforge.org">http://clip.rubyforge.org</a></li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The End of an Era
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/07/the-end-of-an-era/' />
    <updated>
      2008-06-07T04:58:07PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/07/the-end-of-an-era/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Well, okay maybe that title is a bit misleading. I mean, we're not talking about a transition from when dinosaurs ruled the earth to the Ice Age or the introduction of the combustible engine. But today I shut down my remaining home Linux server which ran this blog since its inception.</p>
          
          <p>After overcoming a few technical hurdles I got this blog moved over to Dreamhost. Things seem to be running well, but if you notice anything, let me know.</p>
          
          <p><img src="http://livollmers.net/wp-content/uploads/2008/06/shutdown.jpg" alt="shutdown.png" /></p>
          
          <p>It sort of felt like the end of "T2" when Arnie willingly destroys himself in the forgery and signals a final thumbs-up before incineration. It was definitely time for that box to shutdown, but just a tiny bit sad just the same.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 0.0.4 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/07/clip-version-004-has-been-released/' />
    <updated>
      2008-06-07T04:34:01PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/07/clip-version-004-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why
          should you have to create a Hash, then create a parser, fill the Hash
          out then throw the parser away (unless you want to print out a usage
          message) and deal with a Hash? Why, for Pete's sake, should the parser
          and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>0.0.4 / 2008-06-06</h3>
          
          <ul>
          <li>Fixed typo in error message (thanks francois!)</li>
          </ul>
          
          
          <h3>0.0.3 / 2008-06-05</h3>
          
          <ul>
          <li>Merged technomancy's patches for simple 1 LOC parsing -> hash</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          RailsConf '08 Wrapup
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/06/03/railsconf-08-wrapup/' />
    <updated>
      2008-06-03T16:56:46PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/06/03/railsconf-08-wrapup/
    </id>
    <content type='html'>
      <![CDATA[
          <p>RailsConf closed up last Sunday afternoon and after three-hour drive back and day of work to contemplate, here's what I've boiled it down to:</p>
          
          <h1>The Good:</h1>
          
          <p><img src="http://farm4.static.flickr.com/3122/2547719330_0eae9343db_m.jpg" class="left"/></p>
          
          <p>I met a ton of people this year. Last year I went with a co-worker and we pretty much stuck together. This year I was on my own and made a concerted effort to just meet folks. By the end of the conference I couldn't go more than about fifteen minutes without running into someone I had previously met. I ordered a fresh batch of <a href="http://www.moo.com%20Moo">Moo</a> cards before I left and I was hell-bent to hand as many out as I could. Just meeting people turned out to be my favorite part of the conference.</p>
          
          <p>The Kent Beck address was fantastic. I've had the fortune earlier in my career to work at a company that had Kent come out and run XP workshops with us. Those experiences left a last impression on me (much like Chad Fowler expressed in the introduction) and so I was eager to hear his talk after seeing him on the roster. While his main content probably dragged for a bit, the Q &amp; A ended with a bang. The answer he gave to the final question expressing a mixture of hope and concern brought the crowd to its feet. Go on, Kent.</p>
          
          <p>There were a couple of presentations I went to that I though really knocked it out of the park. In some cases the material alone saved the day (in spite of the presenters) and in a few other cases the two came together nicely. I thought some of these presentations were particularly good:</p>
          
          <ul>
          <li>"Facebook Development and Performance with Rails" &#8211; Mike Mangino</li>
          <li>"The Launch: Do's and Don'ts of Real-life Deploys" &#8211; Chris Wanstrath</li>
          <li>"Assembling Pages Last: Edge Caching, ESI &amp; Rails" &#8211; Aaron Batalion</li>
          <li>"Skynet: A Ruby Map/Reduce Framework" &#8211; Adam Pisoni</li>
          <li>"Vertebra" &#8211; Ezra Zygmuntowicz</li>
          <li>"Advanced ActiveRecord Techniques: Best Practice Refactoring" &#8211; Chad Pytel</li>
          </ul>
          
          
          <h1>The Bad:</h1>
          
          <p>Sadly, a number of the presentations were pretty lacking. Now I think presenting is just plain hard and very few people are good at it. Keynote helps a bit, but really it's a crutch for people who don't have good public speaking skills (which I'm not necessarily claiming I have). Really exceptional content can help overcome the stylistic short-comings of a particular speaker, but I think that's rare. I think it's pretty easy to lose an audience quickly if your material can't shine in the way you present it.</p>
          
          <p>Since I have another year of Ruby and Rails experience under my belt, many more of the talks just really didn't do anything for me. That's why I'm psyched that the RailsConf team has decided to incorporate Caboose Conf as the "hallway track" in next year's meeting. I think that's the track I'll be taking next year. I did a lot of ingesting this year, next year I'd really like to produce more.</p>
          
          <h1>The Style Report:</h1>
          
          <p><img src="http://farm3.static.flickr.com/2089/2547838261_48efb49aa8_m.jpg" class="left"/></p>
          
          <p>Apparently the black t-shirt is king in the Rails community. Something like 99% of all attendees had black t-shirts on. Of the free t-shifts to be had, the GitHub tees were the only ones that weren't black. All of the others were red on black. So apparently the new black is, well, black. I'm hoping that nuclear orange makes a comeback next year. All-black is just a little too Depeche Mode for me.</p>
          
          <div style="clear: both;"></div>
          
          
          <h1>Portland:</h1>
          
          <p><a href="http://www.flickr.com/photos/75756154@N00/2549373887/"><img alt="Voodoo Doughnuts Parade" src="http://farm3.static.flickr.com/2332/2549373887_7b29066b2a_m.jpg class="left"/></a></p>
          
          <p>Portland deserves special mention because I just flat-out love that city. Besides Seattle, it's probably the only other city I would choose to live in. One of the highlights of experiencing the local flair was getting involved in the 1000-person "doughnut march" held by Portland's beloved <a href="http://voodoodoughnut.com/%20Voodoo%20Doughnuts">Voodoo Doughnuts</a>. Somehow they convinced officials to get a parade permit and police escort as they crossed from their Pearl District digs to their new shop in East PDX. It was a very "Portland" experience with a whole crowd of folks letting their freak-flags fly high.</p>
          
          <p><a href="http://www.flickr.com/photos/36455265@N00/2539344898/"><img alt="Bacon maple bar" src="http://farm3.static.flickr.com/2305/2539344898_ea077b65e6_m.jpg" class="right"/></a></p>
          
          <p>The big treat at the end was the bacon maple-bar. I'm not kidding folks, this is real and it's freakin' brilliant. So hear this Chad Fowler and the rest of the RailsConf committee, please don't move this to Vegas! Besides, can you imagine putting a bunch of hygienically-challenged nerds in 100-degree heat in a desert? That is simply not a good idea.</p>
          
          <div style="clear: both;"></div>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          1Password To Rule Them All...
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/05/26/1password-to-rule-them-all/' />
    <updated>
      2008-05-26T23:31:21PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/05/26/1password-to-rule-them-all/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I came across a fantastic piece of Mac software thanks to a <a href="http://twitter.com/hotdogsladies">Merlin Mann tweet</a>. The app is called <a href="http://agilewebsolutions.com/products/1Password">1Password</a> and, to paraphrase Mr. Mann's original tweet, it solves a problem I didn't even realize I had. Well...that's not entirely true. I knew that the various passwords I have scattered across the net weren't as secure as they could be. I had heard of master-password apps but hadn't really done much research on them. Now I'm not going to bother because 1Password so completely blew me away that I went ahead and bought the license (more on that in a bit).</p>
          
          <p>As you might suspect, 1Password is a master-password application. You can easily generate hard-to-crack passwords (like, '81239jsdfj912jlksdf8981'), but only have to remember one master-password. This in and of itself isn't particularly interesting (though the password-generation feature is really well done). What makes 1Password so compelling is how well it is integrated into your online activities. 1Password works with just about every kind of web browser you can imagine on a Mac.</p>
          
          <p>On Firefox, 1Password can install a toolbar that puts all of 1Password's features right there. When you navigate to a site for which you stored a password, you can automatically fill out a form with the click of a button. If you haven't re-authorized with 1Password in a bit (often after waking up my laptop) you have to give your master password again (nice touch boys).</p>
          
          <p><img src="/images/2008/05/200805261621.jpg" alt="200805261621.jpg" /></p>
          
          <p>Also whenever you submit a page that 1Password thinks is auth-related, it will offer to remember these credentials for you. When you update your credentials on a site, the app will ask if you want to update your existing credentials. That is absolutely killer. Clearly these guys understand the achilles' heel to most security systems--people are lazy and are the weakest link. Having such smooth, inline integration makes it difficult for even the lazy user to subvert their own security.</p>
          
          <p>1Password doesn't just live in your browser, it's also a nice stand-alone application. You can easily modify and update your secure information as well as import and export it (a handy way for me to sync my work and home machines).</p>
          
          <p>You're not just limited to passwords either. The app also comes with a notion of identities where you can specify the contact information you might need at various web sites. For myself, I keep both "work" and "personal" profiles. Whenever I have to sign up for something I can simply click the profile I want to use and 1Password fills out as many of the relevant form fields as it can. It also has a "wallet" feature where you can stuff various other secure information like credit card numbers (including the verification number on the back), AWS keys and host of other things. Very very very cool.</p>
          
          <p>Perhaps the most supremely cool feature of 1Password is the ability to sync encrypted javascript bookmarklets with your iPhone that gives you access to those same secret items on your iPhone! 1Password creates two special bookmarklets (synced via iTunes through your Safari bookmarks). One displays your passwords, the other will fill out web forms with with the selected credentials. Both require you to enter a password to unlock the bookmarklet, which you set when you export the bookmarklets from the application. Being able to get that secure information away from my computer makes sure that I don't set simple passwords for iPhone access just because I can't get to my secret stuff. Well done, boys, well done.</p>
          
          <p>The features of this app alone are enough to have sold me. But a good part of the impression this tool has made is how nicely it's been done: no sharp corners, wonderful usability, smooth integration. Even the experience of entering the license key is cool. Your license is an image file (no doubt with some extra steganographic goodies embedded) that you simply drag to a target area. No funny numbers to type. How freakin' cool is that?</p>
          
          <p><img src="/images/2008/05/license.jpg" alt="license.png" /></p>
          
          <p>I've got a whole 'nuther post cooking up about my master-list of indispensable nerd-tools, but I felt that this app was worth a standalone post. If you're on a Mac, do yourself a favor and check this app out.</p>
          
          <p>P.S. No, I wasn't paid a dime to write this.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Passing The Mom Test
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/05/24/passing-the-mom-test/' />
    <updated>
      2008-05-24T05:07:26PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/05/24/passing-the-mom-test/
    </id>
    <content type='html'>
      <![CDATA[
          <p>How many times have you excitedly tried to show your parents some project you're working on and gotten a confused or indifferent response? My reaction has often been to dismiss this disconnect as the result of a generation-gap, but a recent experience has led me to rethink that.</p>
          
          <p>At <a href="http://www.evri.com%20evri">work</a>, we're getting very close to start unleashing our product on the world and so I was doing a little demo for my mom. At first this started to feel like other times when I've showed her things I've worked and she'll focus on some seemingly insignificant detail or re-imagines the application in terms that seem very specific to her world. I felt my usual generation-gap defenses warming up and I started to wrap up the demo. No point in going any further, right?</p>
          
          <p>But after a few more moments I was able to demonstrate enough compelling features that she was engaged. More importantly I became engaged in her reaction to the system. The barrier between us where each side couldn't really grok the other seemed to fall. I was able to have a better understanding of how she might look at it, instead of how I've been looking at for the past year and a half.</p>
          
          <p>So perhaps it's trite and obvious to state that one can benefit from giving yourself the time and patience to understand your users. But I think it's especially true when dealing with other generations. If you can come up with something that crosses those barriers like my impromptu demo did, by George you're probably onto something.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 0.0.2 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/05/21/clip-version-002-has-been-released/' />
    <updated>
      2008-05-21T04:35:32PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/05/21/clip-version-002-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why
          should you have to create a Hash, then create a parser, fill the Hash
          out then throw the parser away (unless you want to print out a usage
          message) and deal with a Hash? Why, for Pete's sake, should the parser
          and the parsed values be handled by two different objects?</p>
          
          <p>Changes:</p>
          
          <h3>0.0.2 / 2008-05-20</h3>
          
          <ul>
          <li>Cleaned up README</li>
          <li>Added support for late-binding option processing with blocks</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          The Great Music Backup
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/04/24/the-great-music-backup/' />
    <updated>
      2008-04-24T03:58:41PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/04/24/the-great-music-backup/
    </id>
    <content type='html'>
      <![CDATA[
          <p>My to-do list is a mile-long and never ends. That thought can be quite depressing at times, but sometimes you finally get to tick something off of the list that has sat there so long that you can briefly enjoy a fleeting moment of smug self-satisfaction. I had just such a moment this week when my Great Big Music Backup to S3 finally completed.</p>
          
          <p>Why S3? Well, something as important as backing up my music (which hasn't come from a CD in about three years) means I need multiple copies. I certainly plan on getting a local backup happening soon, but having one out "in the cloud" provides a little extra comfort if things go totally haywire. Of course none of this would be possible if S3 weren't so darn cheap. By my estimates my 50GB music collection will cost me about $6/mo to backup. That's pretty cheap peace of mind if you ask me.</p>
          
          <p>I did the backup using excellent <a href="http://s3sync.net/wiki">S3Sync</a> utility. Every S3 tool has its own way of mapping a filesystem to S3's bucket system. I thought about using JungleDisk in headless mode, but that turned out to be more complicated than I was willing to deal with. The nice thing about S3sync is that it maps files to your buckets in a way that is compatible with the <a href="https://addons.mozilla.org/en-US/firefox/addon/3247">S3Fox</a> extension for Firefox. Most excellent.</p>
          
          <p>Running over SSL with my crippled Comcast connection it took about a full week to push all of that data out to S3. Thank goodness for Gnu's <a href="http://www.gnu.org/software/screen/">screen</a> utility which hosted the entire sync process. That's right kids, I did this all with a single invocation of s3sync.rb that ran for a solid week. Boo yah. Total upload cost was $3.58. Not too freakin' bad.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          clip version 0.0.1 has been released!
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/04/12/clip-version-001-has-been-released/' />
    <updated>
      2008-04-12T03:41:45PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/04/12/clip-version-001-has-been-released/
    </id>
    <content type='html'>
      <![CDATA[
          <p>You like command-line parsing, but you hate all of the bloat. Why should you have to create a Hash, then create a parser, fill the Hash out then throw the parser away (unless you want to print out a usage message) and deal with a Hash? Why, for Pete&#8217;s sake, should the parser and the parsed values be handled by two different objects?</p>
          
          <p>Introducing Clip...</p>
          
          <p>Checkout the details at <a href="http://clip.rubyforge.org%20Clip">http://clip.rubyforge.org</a>, or just dive right in and install that sucker as a gem.</p>
          
          <p>Changes:</p>
          
          <h3>0.0.1 / 2008-04-10</h3>
          
          <ul>
          <li>Initial release for y'all to throw rotten veggies at.</li>
          </ul>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          S3 Sync Update
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/04/05/s3-sync-update/' />
    <updated>
      2008-04-05T15:49:18PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/04/05/s3-sync-update/
    </id>
    <content type='html'>
      <![CDATA[
          <p>A while back <a href="http://blog.livollmers.net/index.php/2008/01/21/poor-mans-mac/">I wrote about my strategy for synchronizing between two machines</a> using Amazon's S3 and the JungleDisk tool. I just wanted to post a quick update that refines that strategy a bit. First, let me describe what needed improvement. I sync the <code>~/Documents</code> directory between my home and work MacBooks. However, on my home machine I have some extra files that really don't belong on my work machine (like Quicken files), so I have a small text file (called <code>sync_files</code>) that enumerates which sub-directories and file in ~/Documents are to be synchronized between the two machines.This all worked pretty well until I noticed duplicates of files appearing in different places. I realized that what had happened was that I had moved the files on one of the disks and then sync'd with S3. With my current scripts this resulted in copying the file to the new location, but not removing the old one.So with a quick glance at the <code>rsync</code> man-page, I found the <code>--delete</code> option. I refined my scripts and ran them. It all looked good--until I got home. Oops, I just lost a whole bunch of files. Uh-oh. It turns out I forgot to use the <code>sync_files</code> file for both directions. This was an easy tweak but reminded me of the Golden Rule of Rsync:</p>
          
          <blockquote><p> Always run <code>rsync</code> with <code>--verbose</code> and <code>--dry-run</code> to make sure it's doing what you think it's doing</p></blockquote>
          
          <p>So I decided it was time to re-write the script to support this. While you can do command-line options with bash, it quickly gets kinda oogy, so I fell back on Ruby instead. I've also collapsed the synchronizing down into a single script--one that goes both ways. So without further ado, you can download the script <a href="/wp-content/uploads/2008/04/sync_s3">here</a>. This should work with a stock Ruby install, no special gems required.</p>
          
          <p><em>Update 4/8/2008:</em> Okay, I still don't know what the hell I'm doing. There is a bug with this script in that if you create a new file locally then try to sync from S3, your new file will get obliterated. Well guess what kids? Synchronization is hard. I've been noodling on a variety of hacks to get around this but none are terribly satisfying. Anyway, my Golden Rule (see above) still stands: make sure you test the thing out before you run it "live".</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          PCI4R Update
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/03/23/pci4r-update/' />
    <updated>
      2008-03-23T18:13:24PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/03/23/pci4r-update/
    </id>
    <content type='html'>
      <![CDATA[
          <p>We finally made some progress this week on the languishing <a href="http://github.com/alexvollmer/pci4r/tree/master%20pci4r%20on%20GitHub">pci4r</a> project. First, congrats to <a href="http://www.railsonwave.com/">Sandro Paganotti</a> for the first commit to pci4r--the prize is in the mail. This morning, after a bit of git-fiddling, I managed to get the second commit for the project in. It's code for document classification, which is the topic of Chapter 6 of Toby Segaran's <a href="http://www.oreilly.com/catalog/9780596529321/">"Programming Collective Intelligence"</a>. I deviated quite a bit from Toby's original code. In some cases this was simply a side-effect of porting from Python to idiomatic Ruby. In other cases though changes were made for simple aesthetic reasons.</p>
          
          <p>In short, here's what you can do:</p>
          
          <div class="highlight"><pre><span class="n">c</span> <span class="o">=</span> <span class="no">Filtering</span><span class="o">::</span><span class="no">NaiveBayes</span><span class="o">.</span><span class="n">new</span>&#x000A;    &#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="s2">&quot;Nobody owns the water&quot;</span><span class="p">,</span> <span class="ss">:good</span><span class="p">)</span>&#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="s2">&quot;the quick rabbit jumps fences&quot;</span><span class="p">,</span> <span class="ss">:good</span><span class="p">)</span>&#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="s2">&quot;buy pharmaceuticals now&quot;</span><span class="p">,</span> <span class="ss">:bad</span><span class="p">)</span>&#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="s2">&quot;make quick money at the online casino&quot;</span><span class="p">,</span> <span class="ss">:bad</span><span class="p">)</span>&#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="s2">&quot;the quick brown fox jumps&quot;</span><span class="p">,</span> <span class="ss">:good</span><span class="p">)</span>&#x000A;    &#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">prob</span><span class="p">(</span><span class="s2">&quot;quick rabbit&quot;</span><span class="p">,</span> <span class="ss">:good</span><span class="p">)</span>  <span class="c1">#=&gt; ~ 0.156</span>&#x000A;    <span class="n">c</span><span class="o">.</span><span class="n">prob</span><span class="p">(</span><span class="s2">&quot;quick rabbit&quot;</span><span class="p">,</span> <span class="ss">:bad</span><span class="p">)</span>   <span class="c1">#=&gt; ~ 0.050`</span>&#x000A;    </pre>
          </div>
          
          
          <p>Here we create a new <code>NaiveBayes</code> classifier, train it with some text and then query it with other text. Nifty eh? There is another classifier included in the package called <code>Fisher</code>, which has a slightly more clever classification algorithm.</p>
          
          <p>Both of these default to in-memory storage of classification data. You can override it by using the built-in ActiveRecord persistence adapter like so:</p>
          
          <div class="highlight"><pre><span class="n">ar_config</span> <span class="o">=</span> <span class="no">Filtering</span><span class="o">::</span><span class="no">Persistence</span><span class="o">::</span><span class="no">ActiveRecordAdapter</span><span class="p">(</span>&#x000A;      <span class="ss">:adapter</span> <span class="o">=&gt;</span> <span class="s2">&quot;sqlite3&quot;</span><span class="p">,</span>&#x000A;      <span class="ss">:database</span> <span class="o">=&gt;</span> <span class="s2">&quot;mydb.sqlite3&quot;</span>&#x000A;      <span class="ss">:timeout</span> <span class="o">=&gt;</span> <span class="mi">5000</span>&#x000A;    <span class="p">)</span>&#x000A;    <span class="n">c</span> <span class="o">=</span> <span class="no">Filtering</span><span class="o">::</span><span class="no">NaiveBayes</span><span class="p">(</span><span class="n">ar_config</span><span class="p">)</span><span class="sb">`</span>&#x000A;    </pre>
          </div>
          
          
          <p>Finally, there's an executable in the 'bin' directory where you can interactively classify RSS feeds using either of the classifiers or persistence mechanisms provided. This relies on the
          <a href="http://feedtools.rubyforge.org/%20RDoc%20for%20feedtools">feed_tools</a> gem.</p>
          
          <p>So there it is. The rest of the pci4r team should be spooling up soon and hopefully we'll make some more progress. Stay tuned...</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          One Geek's Aesthetics
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/03/13/one-geeks-aesthetics/' />
    <updated>
      2008-03-13T15:36:01PDT
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/03/13/one-geeks-aesthetics/
    </id>
    <content type='html'>
      <![CDATA[
          <p>I'm a fussy guy when it comes to fonts. I like them a certain way because I have strong opinions about which fonts look good and because I spend a lot of time throughout the day looking at them. I like being an avid reader, a software developer and a guy with 20/20 vision. As a result I spend more time than most fiddling with the fonts on my machine to get them just so.</p>
          
          <p>At work I have a MacBook Pro hooked up to a large Dell flat-screen LCD monitor. The screen real estate is fantastic, but it has a weird effect on my terminal program. Here's a snapshot of what the Monaco font looks like when I start <a href="http://iterm.sourceforge.net/%20iTerm">iTerm</a> (or Terminal.app) while attached to the Dell:</p>
          
          <p><img src="/images/2008/03/200803130811.jpg" alt="200803130811.jpg" /></p>
          
          <p>Here's a screenshot of what iTerm looks like when I launch it without the Dell attached:</p>
          
          <p><img src="/images/2008/03/200803130812.jpg" alt="200803130812.jpg" /></p>
          
          <p>See how much thicker the letters are in the second shot? I much prefer the latter setup because it's easier on my eyes. Also I find the variation in the thickness of the lines (probably a result of anti-aliasing with the Dell) in the first screenshot distracting. But that's just my font-related <a href="http://en.wikipedia.org/wiki/Obsessive-compulsive_disorder">OCD</a> kicking in. It bugs me enough that if I have to start iTerm again, I'll unplug the Dell, wait for my Mac to figure out I have one screen, relaunch iTerm and then plug the monitor back in. Yup, it matters that much to me.</p>
          
          <p>It seems stereotypical that dudes who write Ruby on Macs love big fonts. Meeting other Ruby dudes with Macs was certainly my first exposure to terminals set to 18-point type. Before then I felt like 14 was pushing it. But then I realized that there really isn't that much I can look at at once. I used to be one of those guys that would get four terminals going simultaneously in 10-point type. Just look at me, I'd think to myself, I am soooooo productive. Now I'm on the other side of the fence. I'm a big-font guy.</p>
          
          <p>In part this is because I know that I can get distracted too easily. Having a bunch of stuff open at once only opens me up to more opportunities for something to steal my attention. These days I really don't need to exacerbate my ADD so cutting down on what I have to look at is generally a good thing. I've actually returned to using virtual desktops just to partition my running applications. Oh yeah, I turn off all those notifications too. It was fun for awhile, but now it's just irritating.</p>
          
          <p>I like to keep the fonts pretty big. I don't like reading from a screen nearly as much as I like reading from paper. I can feel a sort of mental fatigue set in after reading too much online. One way I've found to combat that fatigue is to simply increase the font-size. Honestly I can't read five paragraphs at once...I can read only read one so I really don't need to cram a bunch in a single space.</p>
          
          <p>I think I'm not alone in my preference for big bold, stripped-down fonts. I've seen an increasing number of web applications that go with a real stark, big-font look. One of my favorites is <a href="http://github.com%20GitHub!">GitHub</a>:</p>
          
          <p><img src="/images/2008/03/200803192007.jpg" alt="200803192007.jpg" /></p>
          
          <p>I think it's pretty clear what you're supposed to do here. Very little extraneous BS, just direct to the point. Give them a login and a password, they'll give you GitHub. It couldn't possibly be any simpler. Oftentimes you see the login box relegated to a corner of the screen with the remaining 80-90% devoted to some kind of market-ese with stock photos of trim, athletic, happy people who are ostensibly using the same product. What a total waste of space.</p>
          
          <p>Size isn't my only bone to pick with fonts. I'm also quite particular about which faces I like. In general I'm not a big fan of serif fonts. I find the clutter of the extra lines distracting, so I generally stick to sans-serif fonts as much as possible. Among sans-serif fonts I have two favorites: Monaco for fixed-width and Gill Sans for variable width.</p>
          
          <p>Fixed-width fonts are popular in programming because the code just lays out better to our eyes. It could be that with things like blocks and indentation, programmesr have a natural tendency to scan code horizontally and vertically in rows and columns. Vertical scanning would be much more problematic with a variable-width font.</p>
          
          <p>However for general reading, I like Gill Sans as a variable-width font. I like it so much that whenever I setup a new desktop, I go fiddle with the font settings in Firefox to get 'em the way I like 'em. I even go so far as to trump a site's stylesheets just to keep my font. Sometimes this results in pretty weird looking pages, but more often than not it turns out okay.</p>
          
          <p><img src="/images/2008/03/ff-prefs.jpg" alt="ff-prefs.png" /></p>
          
          <p>However, I realize that not everyone likes the same font I do. Because I do some web development I need to be able to view sites the same way as the poor unwashed masses view them. For that I take advantage of Firefox's profiles which allow me to have my font-fascist settings for general browsing and factory default font-settings for testing.</p>
          
          <p>So there it is. I like big fonts and I'm not ashamed to admit it. Sure it might look like I'm reading the code-equivalent of the large-print section from the library. But hey, I still have great vision and you small-font people aren't processing any more at once than I am.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Book Review: Information Dashboard Design
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/03/07/book-review-information-dashboard-design/' />
    <updated>
      2008-03-07T22:15:32PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/03/07/book-review-information-dashboard-design/
    </id>
    <content type='html'>
      <![CDATA[
          <p><a href="http://www.amazon.com/Information-Dashboard-Design-Effective-Communication/dp/0596100167%3FSubscriptionId%3D0PZ7TM66EXQCXFVTMTR2%26tag%3Dhttplivollmne-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0596100167"><img src="/images/2008/03/information-dashboard-design.jpg" class="left"/></a>Stephen Few's <em>Information Dashboard Design</em> is the latest in a series of books I've been reading about visual design and the display of quantitative information. It's a surprisingly heavy book for being relatively skinny (~200 pp), but is printed on gorgeous high-quality paper. This O'Reilly book feels much more like a coffee-table book than the usual animal-cover books for which they are famous.</p>
          
          <p>Dashboards are one of those phrases that the synergy-loving, tassle-loafer, khaki-loving business-types really like. I was worried at first that this book would be targeted more toward the executive officer crowd and less about helping designers. The first two chapters didn't ease my concerns with lots of discussion around designing for executive goals and summaries. However once we got past the introductory chapters, the book really picks up...</p>
          
          <h2>Chapter 3: Common Mistakes</h2>
          
          <p>This chapter highlights a litany of common dashboard design mistakes. These aren't just limited to visual tips, but also includes important concepts like providing context through comparison and scaling displayed data appropriately. The examples given here are fairly egregious examples of bad dashboard design, but acclimate the reader to critical review.</p>
          
          <h2>Chapter 4: Tapping Into The Power of Visual Perception</h2>
          
          <p>This is where the fun begins as you learn some of the science behind visual perception. Few describes how shape, position, color, hue and encapsulating marks all affect how we process and perceive data visually. This is one of three chapters that a designer will return to again and again for review.</p>
          
          <h2>Chapter 5: Eloquence Through Simplicity</h2>
          
          <p>Here we head to a particularly Tufte-ian territory with the consistent refrains of "maximizing data ink" and "removing non-data marks". While the words make sense, the concepts are driven home with some great examples. My favorite part of this chapter was the rectangle depicting which screen regions get the most attention and why. After you see it, it's obvious and yet you'll easily be able to recall many examples you've seen that violate these principles.</p>
          
          <h2>Chapter 6: Effective Dashboard Display Media</h2>
          
          <p>The party continues with a detailed survey of the most common graphical visual idioms. The common chart styles like line plots, bar graphs and scatter plots are explored as well as the more exotic ones such as radar graphs, stem-plots and even strategic icon placement. This chapter serves as a great foundation for the final chapters where you will use your newly-acquired visual vocabulary to perform a detailed critique of a number of sample dashboards. Oh and if you take nothing else from this book, remember this: <em>pie-charts are useless.</em></p>
          
          <h2>Chapter 7: Designing for Usability</h2>
          
          <p>This is the shortest chapter of the book, but the two great takeaways from this chapter are encouraging useful comparisons and avoiding senseless ones. If unrelated data-sets are placed too closely or use the same visual representation, it may encourage meaning comparison. Conversely using different styles for data that <em>should</em> be compared simply makes the user's job harder.</p>
          
          <p>Few dives into a few tips around making an esthetically pleasing dashboard without resorting to decorative gew-gaws that clutter the display. In particular things such as using a muted color palette, designing for high resolution and picking the right fonts (a particular sticking point for me) are all ways to be informative without distracting the user.</p>
          
          <h2>Chapter 8: Putting It All Together</h2>
          
          <p>This is easily the best part of the book. However I wouldn't suggest skipping the other chapters in a effort to get to the payoff. I think the reader would best be served by reading this book in sequential order because the principles and concepts covered in the earlier chapters help to give the reader a visual vocabulary for what comes in this chapter.</p>
          
          <p>The begins by showing a dashboard the author designed designed for a competition designing dashboards for a mock business. The dashboard is concise, dense without being cluttered and draws focus to important items quickly. In contrast the author shows eight other dashboards that contestants submitted for the same mock business. Each one has a number of defects, some easy to find and others less so. It's definitely worth studying these dashboards with a careful eye prior to reading the author's criticism.</p>
          
          <p>The chapter ends with three more dashboards targeted to other audiences: the CIO, tele-sales and marketing. Each shows off the other motifs highlighted in earlier chapters. However they all have a consistent style--one that is clear, concise, dense but uncluttered. The prospective designer would be well-advised to spend some quality time studying these examples to distill them into principles for their own designs. This chapter really caps the book off well.</p>
          
          <p><em>Finally...</em></p>
          
          <p><em>Information Dashboard Design</em> is a well-written book full of useful information. The high-level principles are well-described and the catalog of details motifs make this book worth having.</p>
          
          <p>4 out of 5 stars.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Green Fields
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/03/04/green-fields/' />
    <updated>
      2008-03-04T15:44:07PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/03/04/green-fields/
    </id>
    <content type='html'>
      <![CDATA[
          <p>Ahhh...a fresh new server install. It's like getting the first squeeze of toothpaste or the first scoop of peanut butter. It feels especially good because it's all yours. It brims with potential and has no marks of anyone else's will upon it. Setting a server for yourself is liberating because there are no constraints, no corporate policies to adhere to. Right or wrong, you get to call all the shots and take all the responsibility. You finally get to do what you always dremed of when that sneering, omnipotent system administrator show down all your ideas. Petty bureacracy will not stand in your way!</p>
          
          <p>I'm waxing poetically because I just acquired my first <a href="http://www.slicehost.com%20Slicehost">Slicehost</a> account for a side-project I'm working on. I've dozens upon dozens of Linux installs over the years, why should this be special? Perhaps it's worth a trip down memory-lane first...</p>
          
          <p>If you discount those early years writing BASIC for the Apple II and TRS-80, I've been living Unix/Linux longer than I've been programming. In that time I've gotten rather particular about my distros and how I like to configure them. I first cut my teeth on HP-UX working at a wireless telco. Some co-workers there introduced me to Linux which like having an equivalent HP-UX-like interface on a 486 under my desk at home.</p>
          
          <p>Like many, my first distro was the tower of floppies known as <a href="http://www.slackware.com/%20Slackware">Slackware</a>. Ah, the good old days. When setting up X might have entailed destroying your monitor if you didn't get the parameters right. When I started doing actual development I moved over to <a href="http://www.redhat.com/%20Red%20Hat">Red Hat</a> because it was the most polished distro at the time. After that I had a brief flirtation with <a href="http://www.novell.com/linux/%20SuSE">SuSE</a>, but found the configuration frustrating although I did have a major success getting dial-up internet working via number of arcane Hayes modem commands and some network scripts I found on the web.</p>
          
          <p>Then I discovered <a href="http://www.mandriva.com/%20Now%20Mandriva">Mandrake</a>, which I stuck with for a number of years. It was Red Hat-based, but had a much better installer and better package manager. In the end though, even the package management improvements could not overcome the inherent flaws of RPM. On countless occasions I would upgrade and the entire sweater of package dependencies would unravel and suddenly I need to upgrade to a new version of glibc just to get a decent RSS reader working in KDE. Ugh.</p>
          
          <p>It was then that my most Linux-geeky friend turned me on to <a href="http://www.gentoo.org/%20Gentoo">Gentoo</a>. You will learn more about linux kernels and configuration running Gentoo than you ever imagined. Mind you, I didn't get into Gentoo because I wanted to hyper-optimize my install of emacs. I switched because Gentoo's package management and configuration beat the snot out of Mandrake and I found the ebuild system rather elegant.</p>
          
          <p>Unfortunately Gentoo took a tool on my patience with Linux on the desktop. Gentoo required far more care and feeding that I could give it. I spent far more time building and re-building my system than actually doing anything with it. I will point out though, that doing a bare-metal Gentoo install all the way to a full-blown desktop manager like KDE or Gnome has to be about the best hardware burn-in test there is.</p>
          
          <p>So then I hopped on the <a href="http://www.ubuntu.com/%20Ubuntu">Ubuntu</a> band-wagon. While there are far too many ways to install packages (apt-get? dpkg? adept? wirble?), the Debian package management is a nice compromise between pre-built package systems like RPM and configurability (a la Gentoo). So that's what I've put on my new Slicehost host. It's well-documented, has tremendous community support behind and is much more up to date than it's older, conservative sibling, Debian.</p>
          
          <p>So back to Slicehost. So far the experience has been tremendous. I would say that less than a minute elapsed between the time I decided to give them a credit card number and when I got a console login. They have several pre-built server images you can use to provision your slice. And now it's mine...all mine. I get to set it up just the way I like.</p>
          
          <p>So what's in the soup, you may ask?</p>
          
          <p><em>Web Server:</em> <a href="http://nginx.net/%20nginx">nginx</a></p>
          
          <p>I've done a lot of Apache over the years and it's hard to overestimate the impact that it has had on the web. However, it's configuration has become nightmarish. In this case my needs are pretty narrow, so I'll go with something easier to work with. Plus it has a rad name.</p>
          
          <p><em>App Server:</em> <a href="http://www.rubyonrails.org/%20Ruby%20on%20Rails">Rails!</a></p>
          
          <p>I hope I never have to do Java-based web development again. As far as dynamic language go, I've thrown my hat in with Ruby rather than Python, although I hear great things about Django and I'd like to play with it. There are certainly other viable Ruby web frameworks (Merb, Camping, ...) but for this project I'm more interested in getting things done than learning a new web-stack.</p>
          
          <p><em>Database Server:</em> <a href="http://www.mysql.com/%20MySQL">MySQL</a></p>
          
          <p>I really really really wanted to do this with <a href="http://www.postgresql.org/%20PostgreSQL">Postgres</a> since it has just about the best command-line tool I've seen for any RDBMS. I also find the permission model in MySQL to be byzantine and difficult to debug. But alas, scaling out to multiple nodes with read/write master/slave and replication is much more do-able in MySQL than Postgres. There's a ton of existing literature out there on it and I've had <a href="http://www.wetpaint.com%20WetPaint">experience doing it</a>.</p>
          
          <p><em>Mail:</em> <a href="http://www.postfix.org/%20Postfix">Postfix</a></p>
          
          <p>Eventually this app will need to support incoming mail so simple MTA's like exim or esmtp weren't going to cut it. Since I'm deathly afraid of Sendmail, I figured I'd go with Postfix. This is probably the tool I know the least about right now, but it should be interesting to learn.</p>
          
          <p><em>Monitoring:</em> <a href="http://www.tildeslash.com/monit/%20monit">monit</a> or <a href="http://god.rubyforge.com/%20god">god</a></p>
          
          <p>I've used other commercial and open-source monitoring tools and they've all felt really heavy-weight and invasive. I don't so much mean "heavy-weight" in a CPU-sense, but in a process and procedure sense. Looking at the sample configurations for both god and monit put a smile on my face. god looks particularly interesting because it's in Ruby.</p>
          
          <p><em>Text Search:</em> <a href="http://lucene.apache.org/solr/%20Solr">solr</a>, <a href="http://ferret.davebalmain.com/trac%20Ferret">ferret</a>, <a href="http://www.sphinxsearch.com/%20Sphinx">sphinx</a></p>
          
          <p>I've spent a little time looking at all of these solutions to supported inverted-index, full-text search support. I'm not 100% sure where (or if) this app will need full-text search so this area is a little bit hazy. I'm not committed to a particular implementation technology here (i.e. running Solr which is in Java is totally viable).</p>
          
          <p><em>Message Queue:</em> .....</p>
          
          <p>I'm more sure that we'll eventually need to have asynchronous, queue-based work processing to handle things like image resizing and storage or document generation. Like the text search, running something like a Java-based message queue (like <a href="http://activemq.apache.org/%20Active%20MQ">ActiveMQ</a>) is entirely possible. A major piece of the selection criteria will be based on ease of integration.</p>
          
          <p>So we'll see how this goes. I run my own Linux box at home to host this blog, a Subversion repo and couple of other things. It's nice to have a virtual equivalent sitting on much fatter pipes. I'm excited to see where this goes.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Fat Proxies and the Danger of Reuse
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/02/19/fat-proxies-and-the-danger-of-reuse/' />
    <updated>
      2008-02-19T01:50:25PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/02/19/fat-proxies-and-the-danger-of-reuse/
    </id>
    <content type='html'>
      <![CDATA[
          <p>UIs are, essentially, collections of widgets. These widgets act as visual and manipulative proxies between the user and the underlying conceptual model. If we think of the ultimate UI as being one which minimizes the mental distance between what the user wants to do and what they have to do to accomplish it, perhaps the ideal interface would be like the fictional jet-fighter, <a href="http://imdb.com/title/tt0083943/">Firefox</a>. What could possibly be more direct than thinking, fire that missile, and seeing that missile burst forth from under the wing? Unfortunately, since most of us work on slightly less fantastic technologies than those portrayed in the movie, we have to figure how to work best within our milieu. This is the real challenge of what we do. How can we take the crude medium of computer software and diminish the distance between thinking and doing?</p>
          
          <p>Yesterday I checked out a site that plays in the same space as a project I'm working on. These sorts of things are bit like going to the dentist, you don't necessarily look forward to it, but you do it because it's good for you. It's not that I'm trying to ignore what is out there, but for a side-project there is a certain bliss in being ignorant of what else is out there--especially when there really isn't any money at stake. But I was a good boy and checked it out. I went in fearing the worst--that these guys would have nailed the concept and the interface, and there was simply no reason to put any more time on our version. After about fifteen minutes I was pretty convinced that we could come up with a more compelling user experience.</p>
          
          <p>Like mom always said, if you don't have anything nice to say, say it anyway--just don't name names. So let me try to provide some detail on what I found without tipping my hand. This app had all the right rounded-corner-drop-shadow-muted-blue patina that any self-respecting Web 2.0 app should. But digging a bit under the surface revealed a pretty face on what was essentially a Windows for Workgroups-era application mentality. The user flow felt like it was driven from the underlying relational data model, not necessarily from sensible use cases. As I filled out wizard form after wizard form, I couldn't help imagining each one mapping to a particular table in a database. In addition, each form had several tabs with a mix of required and optional features to be identified by the user. The tabs were clearly meant to further sub-categorize the input, however because of the limited real-estate in a tab, only single-word descriptions were available. I had to click on each tab to see if I needed fill anything out in there or not. Too much clicking to satisfy the data model, not enough payoff for the user to keep it up.</p>
          
          <p>Then I ran into something called "templates". I can't help but wonder if templating concepts aren't a smell rather than a feature. In the case of this application, it wasn't really clear what the benefits of templates would be. Normally templates are there to avoid repeating work and providing a model of re-use. Looking at this "feature", I couldn't help but wonder why I should care. If templates are so damn important, do I really want to use an app in which templates are a necessity? Again, too much work, no clear payoff. Humans serve the machine. Bah!</p>
          
          <p>So why would somebody put something like templates in? The answer is re-use. Software developers simply love re-use wherever they can get it. I can imagine the developers and product team sitting around reviewing this complicated system they've built and finally having to address the fact that the complexity makes it hard to use. Templates to the rescue! We can reduce the user's work-load with reuse! Ugh. It's only an economic win if I really care to continue the app. Otherwise the real problem lies in the original interaction model.</p>
          
          <p>The Golden Age of Perfect Software is nowhere on the horizon so building software will continue to be a type of gruesome sausage-making for the foreseeable future. One of the great lies about software development is the false economics of reuse. The theory goes like this: if applications can be built by assembling more-powerful, higher-level components together, the overall cost of software development should decrease. At face value this theory makes a lot of sense. I'm sure many of us can think of time we have wasted (or seen wasted) on building rounder wheels. Why should anyone spend time working on a library of sorting algorithms when for 99.999% of all cases the sorting routines available with your platform are adequate?</p>
          
          <p>The problem is that the component-based thinking doesn't always match the needs of the application. Sure we may have built it more cheaply than if we had written it from scratch, but we have to ask ourselves how much did we compromise in that effort? Software is a notoriously tricky business and the number of failures greatly outweigh the number of successes. Google wasn't built in one shot. Heck, the first version of Google Reader was so badly panned, they threw it away and wrote another one. Apple is on the tenth major version of the OS software and fifth major revision within the latest family. Let's not kid ourselves, we're much more likely to get it wrong than get it right. So let's just assume that it's possible that none of the available, reusable components is going to suffice for your needs. That doesn't have to be your starting assumption, but we have to keep the possibility in the back of our minds.</p>
          
          <p>This leads to a second point I'd like to make about re-use. Many UI toolkits come with a pretty rich array of widgets that are used to build nearly every application out there. This is true of native clients as it is of web applications. If our goal is to minimize the conceptual distance between the user's mental model of the application (remember, the developer's mental model is almost irrelevant) and what they need to do to meet that model, then restricting ourselves only to what the widget palette offers will be fraught with compromise. Developers may see applications built as collections of widgets, but users often don't. It's quite possible that using the "standard" widgets for your application greatly increases the mental distance between thinking and doing for the user. When this happens the user is serving the application--not the other way around. Uh oh. Wrong turn. Back up. Try again.</p>
          
          <p>Don't misunderstand me. I'm not saying that every application has to be written from the ground up because there is no hope in getting the interaction right by reusing off-the-shelf components. That's ridiculous. We'd never get anything done if we approached our apps like that. Rather, my point is that we can't necessarily limit ourselves to the widget sets and conventions of our platforms. In doing so we may leave the user out in the cold. However, visual or interactive exceptionalism for the sake of differentiation invites similar risk. Dressing up your app to stand out is akin to putting lipstick on a pig. If you app is compelling, dressing it up will be unnecessary.</p>
          
          <p>Let's return to our anonymous whipping boy...er, sample web site. Not only did the wizards and multiple-layers of object hierarchy force me to learn the tool's model (one I don't care about), but the expression of those wizards (the widgets) similarly required me (the user) to play along, rather than getting me to the payoff. Some applications are very sophisticated and will require more of the user, but that's not the case for this one. Indeed the selling point is how easy it is to use and how user-focused it really was! Boo, hiss. F-.</p>
          
          <p>So while the wizards had a very consistent and recognizable look and feel to them, they did a horrible job of getting me to where I wanted to be. I can't help but feel that this application was built with a primary focus on a relational data model and component reuse. This ended up with fat proxies between me and what I wanted to get done--an increase in the mental distance between thinking and doing. This is the real shame. Increasing that distance is the primal sin of application design.</p>
          
          <p>One final note: a lot of the inspiration for this post came from a <a href="http://katidev.com/blog/wp-trackback.php?p=20%20Computer%20Administrative%20Debris">fantastic post</a> by Cathy Shive on, what she terms, "Administrative Debris". I interpreted "debris" as that which increases this conceptual distance I keep harping on. Her post, unlike mine, provides a lot more visual examples to get the point across. I would highly recommend reading her article to get another angle on these ideas.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Shopping for Men
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/02/11/shopping-for-men/' />
    <updated>
      2008-02-11T17:37:15PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/02/11/shopping-for-men/
    </id>
    <content type='html'>
      <![CDATA[
          <p><img src="/images/2008/02/photo-2.jpg" class="left"/></p>
          
          <p>This is all I walked out of the local Apple Store with today. No unnecessary bag. No receipt I have to dispose of securely. Just the product I wanted and a friendly little "Thank you" sticker. If all stores were like this, I might actually like to shop.</p>
          
          <p>The local Apple Store also switched over to a cool new portable POS system where just about any sales associate can swipe your credit-card and allow you to make the purchase there. They must have been paying attention to customer complaints because before the remodel, the lines to the cash register were absolute heinous.</p>
          
          <p>This was fantastic. I walked in, a sales associated asked what I was looking for. I told her and she immediately directed me to the available products. I picked one and she took to me another guy who had one of these little POS thingies. I gave him my card, he asked if I wanted my receipt e-mailed to me and I was out the door in less than two minutes. In the time it took my wife to pick out a wedding present I walked a block to the Apple Store, completed this transaction and made it back to where she was before she was ready to go. Fantastic.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          Washington Caucuses
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/02/10/washington-caucuses/' />
    <updated>
      2008-02-10T18:53:04PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/02/10/washington-caucuses/
    </id>
    <content type='html'>
      <![CDATA[
          <p>This past week has seen Washington State abuzz with the excitement over Saturday's Caucuses. For the Democrats especially, this is an exciting time since the two candidates are running neck and neck and in the Evergreen State the Caucus is for all the marbles. So Saturday we headed over the local church for our precinct Caucus which was an absolute madhouse. There was a record turnout for the Caucuses and my personal experience certainly validated that.</p>
          
          <p>Our particular location covered six precincts. I wish I had taken a snapshot of the precinct signup--it was utter chaos. I have no idea if there were any Fire Marshalls in the crowd, but they wouldn't have been happy with what they saw. However, I did manage to get a snapshot of our precinct's meeting:</p>
          
          <p><img src="/images/2008/02/img-0178.jpg" alt="IMG_0178.JPG" /></p>
          
          <p>This picture doesn't really do justice to the size of the crowd. Our precinct had over sixty people register (though not all of them stayed for the meeting). This was my first Caucus and it was certainly an interesting and eye-opening experience. It was completely disorganized--our precinct head wasn't there so we had to elect one. What we lacked in direction was made up for in earnest desire to pick the best candidate for the Democrats.</p>
          
          <p>Like most of Washington State Democrats, our precinct was overwhelmingly for Barack Obama. That's not to say that it was a room full of Hilary-haters. Indeed many Obama supporters voiced their pledge to support Clinton if she wins the nomination. However two themes emerged as people pled the case of Obama.</p>
          
          <p>The first was that the sense of change that Senator Obama would bring to the nation is one that is desperately needed. The second is that having Senator Clinton in the Whitehouse would lead to four years of fractious fighting with the Republicans which would prevent the nation from addressing the stack of dire issues we face.</p>
          
          <p><img src="/images/2008/02/img-0183.jpg" class="right"/></p>
          
          <p>After we voted a couple of times, the final tally was held. We then split into the two camps. The Clinton camp needed to select one delegate to send to the city caucus and the Obama camp needed four delegates. At this point my wife and daughter left because Audrey, bless her heart, hung in like a trooper but was starting to fade. A Tootsie-pop can only take a kid so far. I stuck around for what I thought would be a lengthy delegate-selection process but what, in fact, only took about ninety seconds to decide. We selected four delegates and four backups in record time which sort of made up for the previous hour's worth of bumbling.</p>
          
          <p>We'll see how the race turns out as this primary/caucus season unfolds, but it was certainly exciting to participate in the process and feel like it mattered.</p>
      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
          A Survey of Super Tuesday Infographics
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2008/02/06/a-survey-of-super-tuesday-infographics/' />
    <updated>
      2008-02-06T05:23:46PST
    </updated>
    <id>
      http://alexvollmer.com/posts/2008/02/06/a-survey-of-super-tuesday-infographics/
    </id>
    <content type='html'>
      <![CDATA[
          <p>On Super Tuesday, I forwent attending the usual Seattle Ruby Brigade meeting and stayed at home glued to the radio and TV keeping up on the primary and caucus results across the nation. I love the Public Radio/TV talking heads, but I was really lacking the overall picture. So I warmed up the Internet tubes and started searching for some helpful at-a-glance snapshot of the state of Super Tuesday.</p>
          
          <p>Here then, is an amateur's critique of the various infographics I tripped across. What I was looking for was something that would tell me:</p>
          
          <ul>
          <li> Margin of victory for each candidate</li>
          <li> Percentage of precincts reporting</li>
          <li> The number of delegates available</li>
          <li> The number of delegates each candidate won</li>
          <li> Clear indication of races that have finished, and those that have not.</li>
         