<?xml version='1.0' encoding='utf-8' ?>
<rss version='2.0' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:content='http://purl.org/rss/1.0/modules/content/' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:slash='http://purl.org/rss/1.0/modules/slash/' xmlns:sy='http://purl.org/rss/1.0/modules/syndication/' xmlns:wfw='http://wellformedweb.org/CommentAPI/'>
  <channel>
    <title>
      Alex Vollmer
    </title>
    <atom:link href='http://alexvollmer.com/feed/' rel='self' type='application/rss+xml'></atom:link>
    <link>
      http://alexvollmer.com
    </link>
    <description>
      Latest posts from Alex Vollmer
    </description>
    <lastbuilddate>
      2010-06-13T15:10:14PDT
    </lastbuilddate>
    <language>
      en
    </language>
    <sy:updateperiod>
      hourly
    </sy:updateperiod>
    <sy:updatefrequency>
      1
    </sy:updatefrequency>
    <item>
      <title>A Tale of Two Cultures</title>
      <link>
        http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-06-13T15:10:14PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            apple
        ]]>
      </category>
      <category>
        <![CDATA[
            google
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Cocoa's Broken Tests</title>
      <link>
        http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-06-01T11:20:51PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The International Colors of iPhoneOS</title>
      <link>
        http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-05-21T08:46:32PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            i18n
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Visual Affordance in a Touch-Enabled World</title>
      <link>
        http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-05-07T10:46:39PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <category>
        <![CDATA[
            ipad
        ]]>
      </category>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/
      </guid>
      <description>
        <![CDATA[
            <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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>On Technical Presentations</title>
      <link>
        http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-04-30T07:51:51PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            presentations
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Menu Bar Ghetto</title>
      <link>
        http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-04-23T08:49:57PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            mac
        ]]>
      </category>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Thanks, mom</title>
      <link>
        http://alexvollmer.com/posts/2010/04/17/thanks-mom/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-04-17T20:23:21PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            personal
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/04/17/thanks-mom/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Scripting Build Selection in Xcode</title>
      <link>
        http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-03-06T00:20:30PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            xcode
        ]]>
      </category>
      <category>
        <![CDATA[
            applescript
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/
      </guid>
      <description>
        <![CDATA[
            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>.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>RVM meets zsh</title>
      <link>
        http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-02-27T17:19:45PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            zsh
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/
      </guid>
      <description>
        <![CDATA[
            <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>.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Static Cling</title>
      <link>
        http://alexvollmer.com/posts/2010/02/22/static-cling/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-02-22T17:40:40PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            blog
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/02/22/static-cling/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The iPad</title>
      <link>
        http://alexvollmer.com/posts/2010/01/31/the-ipad/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-01-31T08:12:05PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            apple
        ]]>
      </category>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <category>
        <![CDATA[
            ipad
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/01/31/the-ipad/
      </guid>
      <description>
        <![CDATA[
            <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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Prototyping with Briefs</title>
      <link>
        http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-01-10T17:40:40PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Tools of 2009</title>
      <link>
        http://alexvollmer.com/posts/2010/01/07/tools-of-2009/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2010-01-07T04:35:42PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            mac
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2010/01/07/tools-of-2009/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>All-Time Lineup</title>
      <link>
        http://alexvollmer.com/posts/2009/12/15/all-time-lineup/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-12-15T06:14:09PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            sports
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/12/15/all-time-lineup/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Building a Knowledge Base</title>
      <link>
        http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-12-11T16:39:09PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <category>
        <![CDATA[
            GTD
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Cleaning out the Closet</title>
      <link>
        http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-11-07T22:12:45PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/
      </guid>
      <description>
        <![CDATA[
            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>.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The Cleverest Git Maneuver I Ever Pulled Off</title>
      <link>
        http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-10-09T15:44:04PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>clip version 1.0.2 has been released!</title>
      <link>
        http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-10-03T16:03:14PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The End of an Era</title>
      <link>
        http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-10-02T21:55:55PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            personal
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>iPhone Screencasts</title>
      <link>
        http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-09-15T04:13:03PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            peepcode
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>EvriVerse 2.0</title>
      <link>
        http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-08-19T16:27:18PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            evri
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/
      </guid>
      <description>
        <![CDATA[
            <img src="/images/2009/08/photo-5.jpg" class="left">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Cocoa's Ways of Talking</title>
      <link>
        http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-06-25T01:53:32PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/
      </guid>
      <description>
        <![CDATA[
            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>
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The iPhone and Web APIs</title>
      <link>
        http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-05-27T03:57:39PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            REST
        ]]>
      </category>
      <category>
        <![CDATA[
            evri
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Peepcode meets MacRuby</title>
      <link>
        http://alexvollmer.com/posts/2009/05/15/peepcode-meets-macruby/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-05-15T21:38:30PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            peepcode
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            mac
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/05/15/peepcode-meets-macruby/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Incremental Find on the iPhone</title>
      <link>
        http://alexvollmer.com/posts/2009/05/15/typeahead-search-on-the-iphone/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-05-15T04:55:38PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/05/15/typeahead-search-on-the-iphone/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Introducing the EvriVerse</title>
      <link>
        http://alexvollmer.com/posts/2009/05/12/introducing-the-evriverse/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-05-12T17:28:15PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            evri
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/05/12/introducing-the-evriverse/
      </guid>
      <description>
        <![CDATA[
            <img src="/images/2009/05/graph.jpg" class="left">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The Great Git Setup</title>
      <link>
        http://alexvollmer.com/posts/2009/05/08/the-great-git-setup/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-05-08T04:17:14PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/05/08/the-great-git-setup/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Using Git as a Safety Net</title>
      <link>
        http://alexvollmer.com/posts/2009/03/14/using-git-as-a-safety-net/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-03-14T18:11:32PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/03/14/using-git-as-a-safety-net/
      </guid>
      <description>
        <![CDATA[
            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).
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>What Jersey Means To Java</title>
      <link>
        http://alexvollmer.com/posts/2009/03/04/what-jersey-means-to-java/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-03-04T18:42:49PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            java
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/03/04/what-jersey-means-to-java/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>You Put Merb In My Jetty!</title>
      <link>
        http://alexvollmer.com/posts/2009/02/11/you-put-merb-in-my-jetty/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-02-11T23:31:53PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            java
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/02/11/you-put-merb-in-my-jetty/
      </guid>
      <description>
        <![CDATA[
            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!
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Rewriting History with Git</title>
      <link>
        http://alexvollmer.com/posts/2009/01/31/rewriting-history-with-git/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-31T20:04:13PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/31/rewriting-history-with-git/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Opening The Gates&#8230;of Hell!!</title>
      <link>
        http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-27T06:01:11PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/
      </guid>
      <description>
        <![CDATA[
            &hellip;umm, no, actually not so much.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Ruby Threads Suck&#8230;Just Not The Way You Think They Do</title>
      <link>
        http://alexvollmer.com/posts/2009/01/26/ruby-threads-suckjust-not-the-way-you-think-they-do/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-26T01:47:24PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/26/ruby-threads-suckjust-not-the-way-you-think-they-do/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Meet Magit!</title>
      <link>
        http://alexvollmer.com/posts/2009/01/18/meet-magit/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-18T20:58:06PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            emacs
        ]]>
      </category>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/18/meet-magit/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>clip version 1.0.1 has been released!</title>
      <link>
        http://alexvollmer.com/posts/2009/01/07/clip-version-101-has-been-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-07T02:58:13PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/07/clip-version-101-has-been-released/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>ActiveRecord, Associations and Counters</title>
      <link>
        http://alexvollmer.com/posts/2009/01/04/activerecord-associations-and-counters/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-04T22:39:21PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            rails
        ]]>
      </category>
      <category>
        <![CDATA[
            moochbot
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/04/activerecord-associations-and-counters/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The Fast and the Quick</title>
      <link>
        http://alexvollmer.com/posts/2009/01/01/the-fast-and-the-quick/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2009-01-01T16:39:38PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <category>
        <![CDATA[
            sports
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2009/01/01/the-fast-and-the-quick/
      </guid>
      <description>
        <![CDATA[
            <img alt="Walter Payton" src="http://media-2.web.britannica.com/eb-media/91/95591-004-36D62DDD.jpg" class="left">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Flaccid Attitudes</title>
      <link>
        http://alexvollmer.com/posts/2008/12/23/flaccid-attitudes/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-23T05:47:54PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/23/flaccid-attitudes/
      </guid>
      <description>
        <![CDATA[
            Today I had an impromptu conversation with a total stranger at my local caf&eacute; 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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Burning My Ships</title>
      <link>
        http://alexvollmer.com/posts/2008/12/21/burning-my-ships/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-21T03:40:56PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            geekery
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/21/burning-my-ships/
      </guid>
      <description>
        <![CDATA[
             When Columbus reached the New World, he burned his ships. As a result his men were well-motivated.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>A Tale of Sandwiches and Happiness</title>
      <link>
        http://alexvollmer.com/posts/2008/12/18/a-tale-of-sandwiches-and-happiness/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-18T18:44:11PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/18/a-tale-of-sandwiches-and-happiness/
      </guid>
      <description>
        <![CDATA[
            <img src="http://farm4.static.flickr.com/3228/3096590905_8ccb3341e4_m.jpg" class="left">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Just Having Fun</title>
      <link>
        http://alexvollmer.com/posts/2008/12/16/just-having-fun/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-16T06:04:28PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/16/just-having-fun/
      </guid>
      <description>
        <![CDATA[
            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&hellip;stupid. Can you imagine the ad execs sitting around the table thinking this one up?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>This Evening's moochbot Lessons</title>
      <link>
        http://alexvollmer.com/posts/2008/12/11/this-evenings-moochbot-lessons/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-11T05:27:15PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            moochbot
        ]]>
      </category>
      <category>
        <![CDATA[
            git
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/11/this-evenings-moochbot-lessons/
      </guid>
      <description>
        <![CDATA[
            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:
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>moochbot is out</title>
      <link>
        http://alexvollmer.com/posts/2008/12/10/moochbot-is-out/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-10T06:29:02PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            moochbot
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/10/moochbot-is-out/
      </guid>
      <description>
        <![CDATA[
            <img alt="moochbot" src="http://moochbot.com/images/logo.png" class="left">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Code Personification</title>
      <link>
        http://alexvollmer.com/posts/2008/12/09/code-personification/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-12-09T04:31:19PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/12/09/code-personification/
      </guid>
      <description>
        <![CDATA[
            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 "&hellip;<em>you</em> should send the dates in GMT so that <em>I</em> can search correctly&hellip;" I don't think this conversational style is uncommon among developers. Clearly it's not logically correct&mdash;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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Asynchronous Mail with DelayedJob, God &#38; Daemons</title>
      <link>
        http://alexvollmer.com/posts/2008/11/06/asynchronous-mail-with-delayedjob-god-daemons/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-11-06T05:14:42PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            rails
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/11/06/asynchronous-mail-with-delayedjob-god-daemons/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Election Infographics Redux</title>
      <link>
        http://alexvollmer.com/posts/2008/11/05/election-infographics-redux/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-11-05T05:43:36PST
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            information design
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/11/05/election-infographics-redux/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Proportional Code</title>
      <link>
        http://alexvollmer.com/posts/2008/10/26/proportional-code/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-10-26T23:53:14PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/10/26/proportional-code/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Back To My...Emacs</title>
      <link>
        http://alexvollmer.com/posts/2008/10/07/back-to-myemacs/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-10-07T03:36:51PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            emacs
        ]]>
      </category>
      <category>
        <![CDATA[
            geekery
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/10/07/back-to-myemacs/
      </guid>
      <description>
        <![CDATA[
            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".
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>A Philosophy of Testing</title>
      <link>
        http://alexvollmer.com/posts/2008/10/02/a-philosophy-of-testing/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-10-02T16:44:27PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/10/02/a-philosophy-of-testing/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Make View Helpers a Little Less "Helpful"</title>
      <link>
        http://alexvollmer.com/posts/2008/09/23/make-view-helpers-a-little-less-helpful/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-09-23T15:41:27PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            rails
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/09/23/make-view-helpers-a-little-less-helpful/
      </guid>
      <description>
        <![CDATA[
            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'.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Clip 1.0.0 Released!</title>
      <link>
        http://alexvollmer.com/posts/2008/09/19/clip-100-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-09-19T19:17:33PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/09/19/clip-100-released/
      </guid>
      <description>
        <![CDATA[
            Command-line parsing made short and sweet.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Oracle's Listening&hellip;</title>
      <link>
        http://alexvollmer.com/posts/2008/09/19/oracles-listening/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-09-19T16:17:51PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            gripe
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/09/19/oracles-listening/
      </guid>
      <description>
        <![CDATA[
            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:
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Book Review: "JavaScript: The Good Parts"</title>
      <link>
        http://alexvollmer.com/posts/2008/08/15/book-review-javascript-the-good-parts/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-08-15T03:41:45PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            book review
        ]]>
      </category>
      <category>
        <![CDATA[
            javascript
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/08/15/book-review-javascript-the-good-parts/
      </guid>
      <description>
        <![CDATA[
            <img src="/images/2008/08/dsc-0204.jpg" alt="DSC_0204.NEF">
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Book Review: About Face 3</title>
      <link>
        http://alexvollmer.com/posts/2008/07/30/book-review-about-face-3/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-07-30T04:35:18PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            book review
        ]]>
      </category>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <category>
        <![CDATA[
            information design
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/07/30/book-review-about-face-3/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>ActiveRecord Fun Thay May Stump Only Me</title>
      <link>
        http://alexvollmer.com/posts/2008/07/24/activerecord-fun-thay-may-stump-only-me/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-07-24T04:52:15PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            rails
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/07/24/activerecord-fun-thay-may-stump-only-me/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>clip version 0.0.6 has been released!</title>
      <link>
        http://alexvollmer.com/posts/2008/07/10/clip-version-006-has-been-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-07-10T17:12:27PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/07/10/clip-version-006-has-been-released/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Military History</title>
      <link>
        http://alexvollmer.com/posts/2008/06/28/military-history/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-28T16:15:19PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/28/military-history/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>gemdoc completion in zsh</title>
      <link>
        http://alexvollmer.com/posts/2008/06/25/gemdoc-completion-in-zsh/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-25T16:30:24PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            zsh
        ]]>
      </category>
      <category>
        <![CDATA[
            geekery
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/25/gemdoc-completion-in-zsh/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Launch Day!!!</title>
      <link>
        http://alexvollmer.com/posts/2008/06/24/launch-day/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-24T04:17:58PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            evri
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/24/launch-day/
      </guid>
      <description>
        <![CDATA[
            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>
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Smorgasm!</title>
      <link>
        http://alexvollmer.com/posts/2008/06/21/smorgasm/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-21T04:13:31PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            food
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/21/smorgasm/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Book Reviews: Designing the Obvious/Designing the Moment</title>
      <link>
        http://alexvollmer.com/posts/2008/06/20/book-reviews-designing-the-obviousdesigning-the-moment/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-20T04:55:00PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            book review
        ]]>
      </category>
      <category>
        <![CDATA[
            UX
        ]]>
      </category>
      <category>
        <![CDATA[
            information design
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/20/book-reviews-designing-the-obviousdesigning-the-moment/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>Somebody Hates Me</title>
      <link>
        http://alexvollmer.com/posts/2008/06/19/somebody-hates-me/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-19T22:43:49PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            personal
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/19/somebody-hates-me/
      </guid>
      <description>
        <![CDATA[
            When I see a forecast like this, I gotta think that life just isn't fair sometimes...
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>It Would Be Nice If...</title>
      <link>
        http://alexvollmer.com/posts/2008/06/14/it-would-be-nice-if/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-14T22:00:02PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            philosophy
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/14/it-would-be-nice-if/
      </guid>
      <description>
        <![CDATA[
            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!"
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>clip version 0.0.5 has been released!</title>
      <link>
        http://alexvollmer.com/posts/2008/06/13/clip-version-005-has-been-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-13T22:06:04PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/13/clip-version-005-has-been-released/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>The End of an Era</title>
      <link>
        http://alexvollmer.com/posts/2008/06/07/the-end-of-an-era/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-07T04:58:07PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            geekery
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/07/the-end-of-an-era/
      </guid>
      <description>
        <![CDATA[
            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.
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>clip version 0.0.4 has been released!</title>
      <link>
        http://alexvollmer.com/posts/2008/06/07/clip-version-004-has-been-released/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-07T04:34:01PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            clip
        ]]>
      </category>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/07/clip-version-004-has-been-released/
      </guid>
      <description>
        <![CDATA[
            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?
        ]]>
      </description>
      <content:encoded>
        <![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:encoded>
    </item>
    <item>
      <title>RailsConf '08 Wrapup</title>
      <link>
        http://alexvollmer.com/posts/2008/06/03/railsconf-08-wrapup/
      </link>
      <comments>
        http://alexvollmer.com/posts/{post.full_path}/#comments
      </comments>
      <pubdate>
        2008-06-03T16:56:46PDT
      </pubdate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            ruby
        ]]>
      </category>
      <category>
        <![CDATA[
            rails
        ]]>
      </category>
      <category>
        <![CDATA[
            railsconf
        ]]>
      </category>
      <guid ispermalink='false'>
        http://alexvollmer.com/posts/2008/06/03/railsconf-08-wrapup/
      </guid>
      <description>
        <![CDATA[
            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:
        ]]>
      </description>
      <content:encoded>
        <![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 l