<?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>
      Thu, 25 Aug 2011 07:50:50 PDT
    </lastBuildDate>
    <language>
      en
    </language>
    <sy:updatePeriod>
      hourly
    </sy:updatePeriod>
    <sy:updateFrequency>
      1
    </sy:updateFrequency>
    <item>
      <title>Thanks Mr. Jobs</title>
      <link>
        http://alexvollmer.com/posts/2011/08/25/thanks-mr-jobs/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/08/25/thanks-mr-jobs/#comments
      </comments>
      <pubDate>
        Thu, 25 Aug 2011 07:50:50 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            apple
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/08/25/thanks-mr-jobs/
      </guid>
      <description>
        <![CDATA[
            I suppose it's quite fashionable at the moment to comment on the Steve Jobs' resignation as Apple's CEO. Maybe this is just another me-too post, but I felt compelled to say <em>something</em> about this moment.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>I suppose it's quite fashionable at the moment to comment on the Steve Jobs' resignation as Apple's CEO. Maybe this is just another me-too post, but I felt compelled to say <em>something</em> about this moment.</p>
            
            
            <p>The first computer I fell in love with was the Apple ][ (2? II?). I learned BASIC and a smidgen of assembly to write little games. I grew up with a bunch of other computer-nerd friends and we all swapped disks with games we copied (remember Copy ][ Plus?) or stuff we'd written. Only I didn't own an Apple. Instead the computer my parents chose to buy was a TRS-80. It was a good lesson in hiding your disappointment for the sake of loved ones' feelings.</p>
            
            
            <p>Fast-forward to high-school and my parents upgraded us to a Mac Classic with 30MB external drive.  I had walked away from programming for a few years and turned my attention to music. I didn't program on that Mac, but I did just about everything else. That computer carried me through my college years.</p>
            
            
            <p>Once I entered professional life I was in the world of Windows, DOS and PCs. I was working for a financial services company and was about as far away from programming as a person could get. When I returned to the Pacific Northwest fifteen years ago, I found myself back in the world of computers.</p>
            
            
            <p>My professional career in computers really started with UNIX and Linux. I was a pretty hard-core Linux guy for a long time, until the day I finally ran out of patience with all the fiddly configuration. I bought my first modern Mac five years ago and started learning to develop on the platform three years ago.</p>
            
            
            <p>The timing of my "conversion" to the Apple platform couldn't have come at a better time. Not only was the marketplace exploding with demand for those skills but, more importantly, Apple rescued me at a time when I was pretty disillusioned with technology.</p>
            
            
            <p>While I started playing with computers at an early age, it's not my biggest passion. Computers and programming are really just a means to an end to me. It's not that I don't care about my craft, it's more that I care more about the end-product than the process to get there. Honestly I don't know how much longer I could have gone on feigning interest in algorithms and scalability. Don't get me wrong—they're important, but I'm not passionate about them.</p>
            
            
            <p>When I came to the Apple platform I thought, <em>finally somebody gave a damn about the person on the other side of the glass</em> and I was happy to be a part of it. So all of this is a roundabout way of saying "thanks" to Mr. Jobs and the company and culture he helped build.</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>WWDC 2011</title>
      <link>
        http://alexvollmer.com/posts/2011/06/11/wwdc-2011/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/06/11/wwdc-2011/#comments
      </comments>
      <pubDate>
        Sat, 11 Jun 2011 10:23:44 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            apple
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/06/11/wwdc-2011/
      </guid>
      <description>
        <![CDATA[
            After returning home in the after-glow (read: bleary-eyed) of the 2011 edition of WWDC, I think I finally have a moment to reflect on the conference and the slew of goodies we found under the Christmas tree Monday morning.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>After returning home in the after-glow (read: bleary-eyed) of the 2011 edition of WWDC, I think I finally have a moment to reflect on the conference and the slew of goodies we found under the Christmas tree Monday morning.</p>
            
            
            <h1>Monday Keynote</h1>
            
            
            <p>Officially, the content in the Monday keynote is all anyone at WWDC is really supposed to talk about publicly. Frankly, the details within the rest of the conference are (mostly) an elaboration of what is announced publicly in the Monday-morning keynote address. There are few little geeky odds-and-ends that would be fun to write about, but I'll wait until they're publicly available. But those aren't the big things, these are:</p>
            
            
            <h2>Lion</h2>
            
            
            <p>I don't do enough Mac development (yet) to warrant playing with betas of the OS. I need the OS to be stable so that I can get my iOS work done. That said, I was starting to develop "Lion-envy" whenever I saw other geeks trying it out. This morning I finally sacrificed my laptop to a Lion install just so I could get the new bits. In just the first few minutes I realized this is a really nice upgrade from Snow Leopard. I can't wait for the official release so I can upgrade my main work machine.</p>
            
            
            <p>When Lion was first announced I wondered if it was going to continue the "flattening-out" in the curve of feature-growth that we saw from Leopard to Snow Leopard. Honestly, I had a hard time imagining what they could do to evolve such a mature OS. But once again, the folks in Cupertino wowed me with some innovative thinking about how to make the OS easier to use. Goodbye Spaces, goodbye Exposé, hello Mission Control and Launch Pad. These seem to be a much better implementation of the ideas behind those original technologies. But I don't know that they would have been the obvious conclusion pre-iOS. It's hard to overstate the impact iOS has had on Apple's thinking about UI design.</p>
            
            
            <p>I like the muted look of Lion. The Finder is just a wee-bit more toned-down. Standard Aqua buttons have dropped much of their original garish look. Overall it's just a much more mature look. There's just a lot of polish in this release. Features like Air Drop, Resume, Auto Save, Versions do a nice job of just rounding the sharp-edges off. With these features, it's clear that Apple has declared war on the filesystem as a core concept for personal computing.</p>
            
            
            <h2>iOS 5</h2>
            
            
            <p>If there was a sub-theme below iCloud, it was (dare I say?) a bit of humility from Apple for acknowledging the things that needed to be addressed in all the platforms. The thunder of applause that went up when the new notifications UI was announced from iOS showed just how frustrated we had all become with a system that clearly wasn't working. It's one of the few times I've seen Apple acknowledge the superiority of someone else's design and just unabashedly copied it. The new notifications system was clearly inspired by Android and Android deserves a lot of credit for getting that right the first time. Kudos to the Google-Bot.</p>
            
            
            <p>PC Free was probably received the second warmest welcome from the audience. It was great to hear Apple openly acknowledge the thud-of-a-user-experience we all had when we got our shiny new iPad or iPhone and were faced with the "please plug me into iTunes" screen. Cue the sad trumpet song. The original promise of the iPad as a replacement for a traditional computer is now actually possible.</p>
            
            
            <p>The two things that surprised me the most were the addition of the Reminders app and the deep Twitter integration. As someone who has worked on a <a href="http://www.busymac.com/busytodo/index.html">MobileMe-based to-do list app</a>, I can't say that I didn't feel my heart sink a bit when this was announced. But this was one of those apps that had many wondering why it took this long for Apple to build it. I haven't played with it yet, but I'm really curious to see how the location-awareness features work.</p>
            
            
            <p>Even more intriguing is the first-class Twitter integration in the iOS. Without tipping too much about what's in the API, I can say that it's more than just a cursory implementation. I can only hope that it means that other big services will join up soon and all of us poor developers can stop dealing with the home-grown contraptions we're using now to talk to these services.</p>
            
            
            <h2>iCloud</h2>
            
            
            <p>iCloud was clearly the center-piece of the show. If Apple pulls this off, it has the potential to radically change the personal computing experience. We all have plenty of reason to be suspicious of this offering. MobileMe is Exhibit A in the case against Apple doing online services. But I think it's also fair to remember the services that Apple has gotten right, specifically iTunes and iOS Push Notifications. I remain cautiously optimistic about this. More than anything else announced last week, I think this is the feature that could have the biggest lasting effect.</p>
            
            
            <p>What makes iCloud so compelling is the chance to take advantage of server-side storage without the penalty of explicit synchronization. Frankly, it's what makes Dropbox so great too. As the tag-line goes, "it just works". But something like Dropbox doesn't quite make sense in iOS where the holy-war on filesystems was declared from day one. Instead, iCloud is a re-thinking of the atomic units of documents in such a way that its constraints promise a tighter integration between devices. The slide in the keynote in which Jobs declared that they were "demoting" the Mac says it all. Out of all the technologies introduced this year, iCloud captures my imagination the most. I can't wait to see what people build on top of it.</p>
            
            
            <h1>The Rest</h1>
            
            
            <p>I've done my fair share of conferences and WWDC has become the one I've enjoyed the most. RailsConf is probably my second favorite, but I have to admit that I've always felt a little miffed that they moved it from Portland.  WWDC is a sensory-overload the likes of which I've never experienced for a geek conference. This year, especially, just felt huge and somewhat overwhelming. Maybe it was the announcements on Monday, maybe it was the crush of humanity trying to move through Moscone, maybe it was just the buzz in the air. This year's conference was my favorite of the three WWDCs I've been to.</p>
            
            
            <p>There was a lot of great stuff in the sessions that I'll eventually write about once it's all publicly released. There's so much goodness just in the developer-side of iOS that I'm seriously considering just writing for that and waiting for the fall release of the OS. It was a truly inspiring week. Once I shake off the sleep-deprivation I, like many others I talked to, will be back to work with a vengeance.</p>
            
            
            <p>A large part of what made the 2011 edition so fantastic was getting a lot out of the extra-curricular hours outside of the conference. Lots of late nights talking with other Apple-nerds is a great way to really cement a sense of place in the community. My only regret is that there were still several folks I didn't get a chance to introduce myself to and chat with.</p>
            
            
            <p>Well, it's time to get back to "real life". I have a lawn to mow and family to spend time with. But starting Monday, I'll be hitting Xcode in a caffeine-fueled rage, ready to kick some tater.</p>
            
            
            <p> </p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>One Year In Orbit</title>
      <link>
        http://alexvollmer.com/posts/2011/05/21/one-year-in-orbit/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/05/21/one-year-in-orbit/#comments
      </comments>
      <pubDate>
        Sat, 21 May 2011 10:13:35 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            radiantcapsule
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/05/21/one-year-in-orbit/
      </guid>
      <description>
        <![CDATA[
            It's been a year since I called it quits being an employee and struck out on my own. In that time I've had the privilege of working with <a href="http://www.panopto.com/">some</a> <a href="http://mytimewerks.com/">excellent</a> <a href="http://www.busymac.com/">clients</a>.&nbsp;This week in particular saw the release of my latest client-project,&nbsp;<a href="http://www.busymac.com/busytodo/index.html">BusyToDo</a> as a universal app for iPhone and iPad, right on the heels of my one year anniversary as an indie. I've been proud of the work I've done for all of my clients this year, but this latest release of BusyToDo has been a particularly satisfying achievement.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>It's been a year since I called it quits being an employee and struck out on my own. In that time I've had the privilege of working with <a href="http://www.panopto.com/">some</a> <a href="http://mytimewerks.com/">excellent</a> <a href="http://www.busymac.com/">clients</a>. This week in particular saw the release of my latest client-project, <a href="http://www.busymac.com/busytodo/index.html">BusyToDo</a> as a universal app for iPhone and iPad, right on the heels of my one year anniversary as an indie. I've been proud of the work I've done for all of my clients this year, but this latest release of BusyToDo has been a particularly satisfying achievement.</p>
            
            
            <p>I count myself as extremely blessed to be doing what I do for a living. Not only do I make ends meet doing work I love, but I also have tremendous time flexibility. This makes it so much easier to do the little things like pack a lunch for my daughter and walk her to school each day. That is something I can't put a price on.</p>
            
            
            <p>The other thing that "going indie" has allowed me to do is take up the drums. I've played guitar for about twenty-five years, but always harbored a secret desire to play the drums. When I was a kid I knew there was no way my parents were going to buy me a drumset (though why they put up with electric guitar is beyond me). As someone in their late thirties whose brain is starting to calcify, taking up something like drumming is a major mind-stretch. It has been, at times, one of the most frustrating things I've ever done. But it's also been one of the most rewarding.</p>
            
            
            <p>When I get a new exercise or groove from my drum teacher, at the beginning of the week it seems impossible. How am I possibly going to get all these uncoordinated limbs to cooperate? Like any daunting problem, I break it down. I set the metronome to a laughably slow tempo and <em>slowly</em> work my way up. At the end of the week I (usually) get it. At an age when most people spend their days executing what they're experts at, it's easy to forget what the joy of mastery still feels like. Every day I thank my lucky stars that I have the opportunity to remember what that's like.</p>
            
            
            <p><img style="display: block; margin-left: auto; margin-right: auto;" title="IMG_1408.JPG" src="/images/2011/05/IMG_1408.JPG" border="0" alt="Drums!" width="600" height="448" /></p>
            
            
            <p> </p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Amazing Times</title>
      <link>
        http://alexvollmer.com/posts/2011/04/24/amazing-times/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/04/24/amazing-times/#comments
      </comments>
      <pubDate>
        Sun, 24 Apr 2011 15:01:07 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            technology
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/04/24/amazing-times/
      </guid>
      <description>
        <![CDATA[
            I know it sounds trite. But truly&hellip;we live in amazing times. If my fifteen year-old self could see the things I have available to me today, his little pubescent mind would have been completely blown off of his shoulders. Take an app like <a href="http://www.supermegaultragroovy.com/products/Capo/">Capo</a>, for instance. Here's something that lets me take any song out of my library, slow it down, fuss with the pitch to pick apart a song and learn how to play it. This technology was unthinkable twenty years ago when I first picked up the guitar. I had to rely on transcriptions in guitar magazines. I don't know what kind of gear the transcribers of the day were using, but I'm sure it was giant, immobile and expensive.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>I know it sounds trite. But truly…we live in amazing times. If my fifteen year-old self could see the things I have available to me today, his little pubescent mind would have been completely blown off of his shoulders. Take an app like <a href="http://www.supermegaultragroovy.com/products/Capo/">Capo</a>, for instance. Here's something that lets me take any song out of my library, slow it down, fuss with the pitch to pick apart a song and learn how to play it. This technology was unthinkable twenty years ago when I first picked up the guitar. I had to rely on transcriptions in guitar magazines. I don't know what kind of gear the transcribers of the day were using, but I'm sure it was giant, immobile and expensive.</p>
            
            
            <p>The best we could do were some ham-fisted tricks to try to slow-down turn-tables, but you could never really get it down to a reasonable pitch to match your guitar. So the secrets to our favorite songs were passed around amongst aspiring musicians like epic poems among ancient Greeks. This fits in my pocket. If I had seen that when I was fifteen it would have <em>melted my brain.</em></p>
            
            
            <p>Or take a look at MLB.tv. I've been a huge baseball fan since I was thirteen. If you told me then that I would one day have a device I could sit in bed with, watch any ballgame I wanted to and look at realtime, in-game statistics, my unhinged jaw would never return to its rightful closed position.</p>
            
            
            <p>Or the Kindle (device and app). I could read a book on my phone while waiting for the bus, then pickup right where I left off on my iPad for night-time reading before bed. That…is…simply…amazing.</p>
            
            
            <p>So with all of our cool toys and services, are we really getting anywhere? By offloading the tedious and mundane tasks of modern living to technology, are we really taking advantage of our spare mental capacity? Are we really evolving as a culture or species to do more and learn more than our ancestors before us? I don't know. Sometimes I look at something like Farmville and I have to just shake my head at the frivolity of it all (money-making frivolity, but c'mon, are you kidding me?) On the other hand the role of social networks  in the Jasmine Revolution in the Middle East is heartening.</p>
            
            
            <p>We live in a time breathtaking technical accomplishment. Each of us has the capability to achieve amazing things. We also have the equal opportunity to fritter our time and attention away on the trivial. So the question is, now that we can do so much, what are we going to do that's worthwhile?</p>
            
            
            <p><iframe src="http://www.youtube.com/embed/8r1CZTLk-Gk" width="480" height="390" frameborder="0"></iframe></p>
            
            
            <p> </p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>The Dumbest Thing I've Ever Done</title>
      <link>
        http://alexvollmer.com/posts/2011/04/17/the-dumbest-thing-i've-ever-done/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/04/17/the-dumbest-thing-i've-ever-done/#comments
      </comments>
      <pubDate>
        Sun, 17 Apr 2011 09:10:18 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            productivity
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/04/17/the-dumbest-thing-i've-ever-done/
      </guid>
      <description>
        <![CDATA[
            To me, there's nothing more precious than my time. Okay, I suppose my family and dearest friends would rank ahead of that. But, even then, I can't enjoy their company if I don't have the time. So, in the last year, &nbsp;I've thought a lot about how I choose to spend my time. For example, I don't do my own taxes anymore because the money I pay to our accountant is worth the time (and brain-ache) I save from not doing them myself.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>To me, there's nothing more precious than my time. Okay, I suppose my family and dearest friends would rank ahead of that. But, even then, I can't enjoy their company if I don't have the time. So, in the last year,  I've thought a lot about how I choose to spend my time. For example, I don't do my own taxes anymore because the money I pay to our accountant is worth the time (and brain-ache) I save from not doing them myself.</p>
            
            
            <p>Some things, like taxes, are pretty easy to make decisions about regarding my time. But others, especially tech/software projects get a little murkier. I'm certainly less-inclined to noodle on go-nowhere personal projects than I used to be. I still enjoy software, but only in a really focused way. These days, I'd much rather spend those extra bits of time and attention on becoming a better drummer.</p>
            
            
            <p>So, why is it that I went off for a month to fiddle with my blog setup? Good grief, I have written anything in nearly <em>three months</em>. I don't think that "tweaking my setup" is the reason that the posts have dried-up recently. Even though I know that, there's a little voice in the back of my head that says, "Yeah, but what if it were just a <em>little easier</em> to write a post. You'd write more then, wouldn't you?" The evolved, brain-cortex side of me quickly dismissed that notion as rubbish. But my deep-down, brain-stem part of me took the bait. "Of course! What I need is a smoother blogging setup!"</p>
            
            
            <p>So, after a month of noodling on this project, here I am writing my first post with The New Setup™. It is a Pyrrhic victory if there ever was one. If I'm honest with myself, I'll acknowledge that if posting more is important to me, tweaking my "flow" isn't going to hinder me from writing. This is the lie of productivity tools—they're useless without real passion and attention from the humans using them. But sometimes you just get an itch that you have to scratch, and this is my itch.</p>
            
            
            <h1>The Itch</h1>
            
            
            <p>About a year ago I went through another major effort with my blog by converting it from a Dreamhost-ed Wordpress blog to a static-site generated using <a href="http://nanoc.stoneship.org/">nanoc</a>. How I came to use nanoc is a long and uninteresting story.  Nanoc certainly has a lot of nice features, but suffers a bit from complexity-overkill due to its configurability. In retrospect I wish I'd just gone through the pain of switching to <a href="https://github.com/mojombo/jekyll">Jekyll</a>. But the main reason I went with nanoc was that I was trying to mimic the structure of the Wordpress site as closely as possible and found it difficult to do that with Jekyll.</p>
            
            
            <p>In retrospect, this was mistake number one. I went through a lot of effort to build a new system that looked a lot like the old system. Sometimes you can't avoid this, but I don't think I asked myself forcefully enough whether I really needed to do that. That had consequences further down the road.</p>
            
            
            <p>So here I am going along with my nanoc site. The final output is certainly better than I would have achieved with Wordpress. But the sausage-making behind the scenes to get a post into place was not happening. As much I really wanted to get hip to The Markdown Way, I just didn't do it enough to make it stick. I simply couldn't get hyperlink syntax to stay put in my brain. So I had to constantly interrupt whatever I was writing to go look up Markdown syntax again and again. Ugh.</p>
            
            
            <p>Oh, and images. I had a glorious Automator folder-action that was supposed to help with images. I could drag an image to the top-level directory of the blog and the action would prompt me for a name and put the URL in the clipboard which I could paste write in the post. Oh my goodness, it was so clever and awesome—except that it didn't work half the time. So I'd end up having to copy files around manually and type out image URLs that were often incorrect the first few times. Round and round and round and round. It took <em>a lot</em> of iteration to crank a post out.</p>
            
            
            <p>Over time I realized that I really missed using <a href="http://www.red-sweater.com/marsedit/">MarsEdit</a>. It's just so easy to sprinkle a little formatting here and there or drop an image or two in a post. Links are a snap. It's nice because my meager brain can stay at one level of abstraction while I write. So I started thinking about how I could graft MarsEdit onto my existing setup.</p>
            
            
            <h1>The Scratch</h1>
            
            
            <p>So I ended up writing a little <a href="http://www.sinatrarb.com/">Sinatra</a> app that pretends to be an Wordpress-like XML-RPC server on top of my existing nanoc setup. It sounds simple enough, right? Well, the end result turned out to be somewhat elegant (if I do say so myself), but the path to get there was a festival of Moses-in-the-desert-like meandering.</p>
            
            
            <p>In the end I've got something pretty slick. This Sinatra app runs through the built-in Apache instance on my Mac using <a href="http://www.modrails.com/">Phusion Passenger</a>, running on a private "alexvollmer.local" address. Since the stock Apache installation is always running on OS X (unless you go out of your way to disable it), I have an always-on local server backing MarsEdit. The great thing about this is that I don't have to remember that part of writing a blog post is starting a server process. I fire up MarsEdit, I write, I post.</p>
            
            
            <p>This Sinatra app handles drafts and publishing, deleting posts and image upload. When I hit "Send to Blog" it commits the post to the git repository, compiles the nanoc site and rsync's it out to my server. It feels like a "real" blog setup again. I can't say that I'm not a little pleased with how it turned out.</p>
            
            
            <h1>The Rash</h1>
            
            
            <p>But here I am, a month later, and wondering to myself if I've really accomplished <em>anything</em>. I've essentially migrated from Wordpress to a third-party static-site generator (which needed heavy customization along the way). Then I put in another round of customization to make it look like Wordpress again so I can use the same front-end tool. I've essentially poured a boat-load of time adhering to an arguably lousy interface. Had I gone with Jekyll in the first place, I could have used an <a href="http://code.movieos.org/jekyll-metaweblog/">existing solution</a> to make it work with MarsEdit and gone on my merry way.</p>
            
            
            <p>Hell, it's not even like I've built a nice re-usable XML-RPC interface for other nanoc users to use. It's so wired into my nanoc setup that it's value as publicly-available source is little more than demonstrative. <em>Sigh</em>. So that's why I'm calling this the dumbest thing I've ever done. I knew <em>exactly</em> what a waste of time this was going to be at every step of the way. I managed to tell myself to be patient long enough to solve the next little hitch in the process of creating this Frankenstein. After clearing several hurdles that I thought would capsize this project, I ended up at the finish line. Success, of a sort, I suppose.</p>
            
            
            <p>Now one thing I'd like to point out that I started on this Quixotic cause <em>before</em> Brent Simmons started the <a href="http://inessential.com/2011/03/16/a_plea_for_baked_weblogs">call-to-arms for static site generators</a>. However, I did mention my windmill-charging exercise to him at a recent <a href="http://seattlexcoders.org/">Seattle Xcoders</a> meeting and, as he put it, <em>sometimes ya just gotta do things like that</em>. Yes, indeed, sometimes you just need to scratch that itch. So, scratched it I have, and now it's time to get back to the real work.</p>
            
            
            <p> </p>
            
            
            <p>P.S. Despite all my self-flagellation, this new blogging setup <em>is</em> pretty sweet…</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Tools of the Estate</title>
      <link>
        http://alexvollmer.com/posts/2011/01/30/tools-of-the-estate/
      </link>
      <comments>
        http://alexvollmer.com/posts/2011/01/30/tools-of-the-estate/#comments
      </comments>
      <pubDate>
        Sun, 30 Jan 2011 19:15:19 PST
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            mac
        ]]>
      </category>
      <category>
        <![CDATA[
            productivity
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2011/01/30/tools-of-the-estate/
      </guid>
      <description>
        <![CDATA[
            I've wanted to write this post for some time, but each attempt came out
            sounding sort of flat and uninspiring. Now, at a altitude of 30,000 feet, free
            (mostly) from distractions, I'm going to try this again with some real focus.
            This will be, no doubt, one of the oddest posts I've done in a long time.  As
            you may recall, <a href="/posts/2010/04/17/thanks-mom/" title="Thanks Mom">my mother passed away last
            March</a>. Since then I inherited a
            part-time job known as "Personal Representative" of her Estate. It has
            consumed much of my life over the last year.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>I've wanted to write this post for some time, but each attempt came out
            sounding sort of flat and uninspiring. Now, at a altitude of 30,000 feet, free
            (mostly) from distractions, I'm going to try this again with some real focus.
            This will be, no doubt, one of the oddest posts I've done in a long time.  As
            you may recall, <a href="/posts/2010/04/17/thanks-mom/" title="Thanks Mom">my mother passed away last
            March</a>. Since then I inherited a
            part-time job known as "Personal Representative" of her Estate. It has
            consumed much of my life over the last year.</p>
            
            <p>But that's not what I wanted to write about here. What I wanted to share with
            you was a little bit of how I avoided going crazy while doing this. And while
            I'm not completely finished with the process, the end is in sight and I can
            confidently say that the tools and techniques I'm going to describe below were
            a huge benefit to me.</p>
            
            <p>One of the reasons I struggled so much with this post was that I had a hard
            time making it not sound like some long-winded commercial for my favorite
            software tools. Yes, these tools are great. But really this is about so much
            more than that. It's really about the whole change in mindset and approach
            that was necessary for me to get stuff taken care of.</p>
            
            <p>So rather than just give you a lame, amateur impression of a MacWorld review,
            let me put these tools in context. Let me start by laying out a few rules and
            constraints. I have, on occasion, been prone to being a bit obsessed with the
            world of so-called "productivity porn". This is the contant fiddling about
            with your tools and ways of doing things that quickly eclipses your ability to
            actually get any meaningful work done. It was clear to me, right away, that if
            I was going to add anything to my toolbox I had to benefit from it
            immediately. Similarly, any tool that required me to internalize a whole
            new methodology was just not going to work.</p>
            
            <p>This isn't to say that my game couldn't use some improvement.
            Rather, it was a recognition of the fact that I simply don't have <em>time</em> to
            change my ways too much. I need to get stuff done. Lawyers are calling, taxes
            are due and I cannot be the roadblock that holds things up.</p>
            
            <p>The last principle (if we can call it that) in all of this was that both space
            and time were limited resources. I had limited amounts of both and in many
            cases I was willing to trade money for either. Usually this meant paying a
            professional to take care of something that didn't make sense for me to do
            (e.g. estate taxes, carrying out an estate sale, etc.). However, in some
            cases, I had to make choices <em>between</em> space and time.</p>
            
            <p>Scarcity of time probably makes sense, but scarcity of space may not. No
            matter how frugal or simple a person may have lived, if they reached adulthood
            they acquired a lot of stuff over the course of their life. Since this was my
            mother, some of those things I had some emotional attachment to. But the vast
            majority was "stuff" I simply didn't want or need. That didn't mean that it
            wasn't my problem though. More on this later.</p>
            
            <p>So, given that I already have job, how did I keep myself from going crazy
            while trying to get this stuff settled?<a href="#note1"><sup>1</sup></a> In
            short, I used a handful of tools (mostly software) and a lot of discipline.</p>
            
            <h1>OmniFocus</h1>
            
            <p>I've been a big <a href="http://www.omnigroup.com/products/omnifocus">OmniFocus</a> user
            since it debuted. I also have the iPhone and iPad versions. Though all three
            add up to quite a premium, they all solved the biggest problem I had: having
            one place to dump things I need to do and sort them out later.</p>
            
            <p>OmniFocus let me dump every little thing that came up that needed attention
            into a single place that I could then orchestrate into a sequence of actions
            to take. Take for example, the process of filing tax returns. Depending on
            where you live and when your relative passed away, you may have multiple tax
            returns to file (the personal tax returns of your loved one, Estate Taxes and
            fiduciary taxes for the Estate). Given that these weren't tax returns I had
            <em>planned</em> to file I suddenly had a metric s**t-ton of paperwork to locate.</p>
            
            <p>So let's say that I had a task like "Get date-of-death valuations for all
            investments". I would create a task in OmniFocus and give it some rough due
            date. If it was something like a personal tax return that had a known due date,
            I'd put that due date in. Now clearly a task like that is too big (or it least
            it was too big to me). So then I would add several sub-tasks to that, one for
            each financial institution that I needed to contact.</p>
            
            <p>If I had more than, say, three or four sub-tasks and they were particularly
            onerous, I might spread them out before the parent task's
            deadline and space-out the due-dates for each child task. This turned out to
            be extremely helpful because it allowed me to do a little bit each day, without
            getting too discouraged. And let me tell you, there were a whole lot of tasks
            on that list that I did not want to do. If I had stuffed a bunch under one
            task and waited to do them until the last minute (either because I didn't see
            them or because I procrastinated) it would have made completing them so much worse.</p>
            
            <p>So part of this was a sort of psychological head-game I'd play with myself to
            keep going. It's like what any endurance athlete does to complete a race. You
            don't consider the entire course, instead you run to the next block or bike
            over the next hill. <em>That's all you care about right now.</em> You can deal with
            the <em>next</em> hill after that.</p>
            
            <p>Because I was often in lots of different places with a varying "kit" of
            equipment, I needed to access that list from anywhere. Here, OmniFocus'
            ability to sync with various "cloud services" (I use MobileMe) was a huge
            help. This brings me to what I might call Golden Rule #1:</p>
            
            <blockquote><p>Make sure you only have <em>one</em> place for things.</p></blockquote>
            
            <p>Once you start scattering stuff around in-duplicate, the genie is out of the
            bottle, and you will have a hell of a time getting it back in. When it's absolutely
            <em>crucial</em> that you stay on top of things do not use multiple
            places/buckets/services to store a disjoint set of the same things. You might
            find a better way to do it, but the cost of migrating while you're in
            fire-fighting mode is a heavy price to pay.</p>
            
            <p>So I'm not going to sit here and tell you that OmniFocus is the One True Way.
            There are certainly enough to-do apps out there to choke a whale. All I can
            tell you is that it was a life-saver for me.</p>
            
            <h1>OmniOutliner</h1>
            
            <p>So, where OmniFocus was my tool keeping myself on-track, I needed something
            else to capture more permanent data. OmniFocus would have been completely
            inappropriate for historical records. Once I complete a task, it's gone. So,
            instead, I used
            <a href="http://www.omnigroup.com/products/omnioutliner/">OmniOutliner</a>.</p>
            
            <p>Now there's nothing particularly special about OmniOutliner for taking notes.
            In some ways, it's not really a note-taking tool at all. But if you have a
            proclivity for thinking hierarchically and in outlines (which I do),
            OmniOutliner is must-have.</p>
            
            <p>Being a keyboard-shortcut junkie, OmniOutliner is the
            most effortless tool I've come across for capturing information and ideas in
            outline form. The ability to quickly move up and down in a hierarchy <em>and</em>
            move items throughout the hierarchy hasn't been done better in any app that
            I've seen.</p>
            
            <p>So, I have one giant OmniOutliner file called "mom's estate" that has
            <em>everything</em> in it. It has account numbers, records of every phone
            conversation I had, when I sent paperwork, when I got
            responses&hellip;seriously&hellip;I mean everything.</p>
            
            <p>I used it most often for phone calls (which have been numerous) with
            attorneys, tax accountants and financial institutions. This was one of the
            areas where I need to be the most disciplined. If I ever let myself slip and
            failed to write down the salient points from a conversation I had, I would
            have eventually stopped doing it and lost a lot of information along the way.
            Sometimes I would get a call from an attorney while I was out an about. If I
            wasn't with my laptop, I'd reschedule the call until I could be where I could
            put my earphones in and have my hands free to type while conversing.</p>
            
            <p>This was a god-send. It helped me stay on top of things in a way I wouldn't have
            been able to do with my brain alone. Also, because it was all in one place,
            it was easy to search through my notes when I was talking with someone.</p>
            
            <h1>In-Ear Headphones</h1>
            
            <p>It sounds dumb, but I used these things all the time. In fact, I went through
            two pairs during this whole ordeal. Anytime I had a call related to matters of
            the Estate, I always politely asked the other party to wait while I put my
            earphones in so I could take notes.</p>
            
            <p>What this was really about was reducing friction as much as possible. There
            was simply no part of settling the Estate that was enjoyable, but I could at
            least try to reduce the pain. Just the simple ability to type while talking
            meant that I took better notes, more consistently. That meant that I had more
            information I could easily capture and file that I didn't have to hold in my
            head. And <em>that</em> meant more confidence in my ability to figure this stuff out and
            get it done and less stress about forgetting something.</p>
            
            <h1>DEVONThink Pro Office and the Fujitsu ScanSnap Scanner</h1>
            
            <p>I was introduced to
            <a href="http://www.devon-technologies.com/products/devonthink/index.html">DPTO</a> (as
            the cool-kids call it) by Ryan Davis during one of the Seattle.rb hack nights.
            DPTO is an amazing, powerful, abstruse piece of software. It's exactly the
            sort of thing I generally shy away from these days, but it does one thing so
            extraordinarily well that I plunked down a good chunk of change and spent some
            time learning its idiosyncracies.</p>
            
            <p>As I began to clear out my mom's house, I eventually whittled down a lifetime
            of collected paperwork to six banker's boxes. I don't have space to hold six
            banker's boxes of paper in my house. Hell, I don't have space to hold the
            paperwork I already have in my house. But I couldn't just get rid of the
            paperwork, I needed the information.</p>
            
            <p>Enter the Fujitsu ScanSnap document scanner. Combined with DPTO, these two
            form a rapid-input document scanning tool that allowed me to practically
            reduce about 80 cubic feet of documentation down to a pile of bytes on a
            hard-drive.</p>
            
            <p>What's great about DPTO is that it has remarkable OCR technology.  It can scan
            damn near any document, convert it to a PDF, and overlay searchable,
            selectable text. All of those statements went from pounds of paper to
            searchable bits on my harddrive. Not only did this help me save space, it also
            made all of this documentation searchable which was a huge help trying to
            piece-together my mother's financial picture (a necessary thing for probate
            and various taxes).</p>
            
            <p>Now this wasn't easy. In this case, I had to face the Sophie's Choice of
            trading time for space. It took a lot of time to scan all of those documents.
            So my solution was to do a little bit consistently and to do it during
            "down-time". I spent a lot of football games this season with a beer, a giant
            stack of documents, a paper-shredder and my document scanner.</p>
            
            <p>So it sucks that I had to spend time doing it, but now I've recovered a bunch
            of physical space and I've made all of these documents easier to get to. In
            truth, I won't need to access the vast majority of documents, but on the off
            chance I need one, it would sure suck hard not to have access to it. Keeping
            all that paper around would be giving in to the fear that "I might need that
            someday". I hate fear as a motivator. It's very powerful, but things often
            turn out very poorly as a result. So DPTO and the ScanSnap allow me to make it
            very cheap to keep all of this for the remote possibility that I'm going to
            need it someday. All of this boils down to what I'll call Golden Rule #2:</p>
            
            <blockquote><p>Never pay freight on something you "might" need.</p></blockquote>
            
            <p>DPTO can do a lot of things. I'm not sure I would really use it as my
            "all-in-one" bucket. In a lot of ways it's a pretty fussy tool that, in my
            opinion, takes a bit too much to maintain. However, just using it as a
            document scanner and archiver makes it, to me, totally worth having.</p>
            
            <h1>Backups</h1>
            
            <p>Now I'm all for going digital, but doing so means that I've taken on the risk
            of the inherent fragility of today's storage technology. Paper, in general,
            doesn't fail for mysterious reasons (perhaps this is why MBTF isn't published
            on the side of a ream of paper), but disks certainly do.</p>
            
            <p>The only way I could move more things to digital and not put myself in a
            potential crisis situation with a hardware failure was backups. Lots and lots
            of backups. And not just one backup, but multiple backups. And not just on one
            medium, but several. And not just in one location, but several.</p>
            
            <p>So my current backup strategy now uses a combination of Time Machine, Super
            Duper and Carbonite. I use Time Machine because it's the fastest backup that
            saves me from the dumb accidental file delete. It's really a first-line of
            defense and no more.</p>
            
            <p>I use <a href="http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html">Super
            Duper</a> for local, full backups. What's great about Super Duper is
            it's ability to create a bootable volume, which means that if my main drive
            fails, I can still get to the information without necessarily having to fix
            the main hard drive first. I use a rotating pair of LaCie drives and backup
            every other day (I have a repeating OmniFocus task to remind me).</p>
            
            <p>These are great tools, but they use a common medium (FireWire drives) and they
            are in the same location (my house). I might solve the location problem by
            coming up with some backup-swapping routine with someone I saw on a regular
            basis. That is, each person would have two or more Super Duper backup disks,
            and would routinely give one of them to a trusted source. You would then each
            rotate your backups and at your next meeting, "trade" backup disks. I use
            Espionage to encrypt my important data so I'm not worried about it falling
            into the wrong hands.</p>
            
            <p>I haven't done this yet. But even if I did, I'd want another form of backup,
            so I bought a <a href="http://www.carboniate.com">Carbonite</a> account to push data out to the "cloud". There are a
            growing number of services out there like Carbonite and they probably work
            just as well. The point here is peace of mind. It's like buying insurance.
            Sure, it's very unlikely that my house is going to catch on fire and burn to
            the ground with everything in it, but why worry about it at all? And if it did
            happen, why make the loss worse. Sixty bucks a year seems like a pretty cheap
            price to pay for the ability to sleep better at night. We'll call this Golden
            Rule #3:</p>
            
            <blockquote><p>Computers are great but fail. Make sure that fragility doesn't keep you up
            at night.</p></blockquote>
            
            <h1>Dropbox</h1>
            
            <p>The last tool I'll mention is <a href="http://www.dropbox.com">Dropbox</a>. Dropbox is awesome for so many reasons
            and I could go on and on about it. But what was really useful for me in this
            context was the ability to selectively share documents with others. I have
            some pretty serious, private documents going around that I don't just want to
            stuff in an email. Yes, there are encrypted zip files and PDFs but there isn't
            a good standard for the former across platforms and you still have the problem
            of getting the password to the other party in a secure way.</p>
            
            <p>With Dropbox I can share documents securely with my tax accountant. Hell, it's
            even <em>easier</em> than email because I don't have to deal with attachments and
            anti-virus software mistakenly preventing my documents from being received.</p>
            
            <p>Now not all lawyers and accountants are going to be down with such modern
            technology. In our litigation-happy society people in these professions tend
            to be pretty conservative in adapting new technologies. All I can say is that
            I was very fortunate to work with the sort of folks that <em>would</em> go along with
            something like Dropbox.</p>
            
            <h1>FAX Modem</h1>
            
            <p>I can't believe I had to buy this thing, but given the spirit of the post, I
            would be remiss if I didn't mention the humble little Zoom modem. It
            is extraordinarily depressing and aggravating that in this day and age, the
            vast majority of financial institutions out there will accept a fax, but won't
            use email or some web-based tool.</p>
            
            <p>At first I had earnestly hoped that things were going to change and that I
            would only need to make the occasional trip to the local Kinko's to send a
            four page fax for five bucks (thank you very much). As time went on though, I
            realized that any companies willing to do business over the internet were the
            exception rather than the rule. So, as much as I hated to do it, I finally had
            to admit that we haven't really evolved as much as I'd hoped and had to trudge
            down to the local Best Buy to buy a stupid little USB fax modem.</p>
            
            <p>Now, as much as I hate the fact that I have to deal with faxes, the fax
            software integrated into OS X makes it pretty easy. Most folks don't know that
            printing a document in OS X is really a gateway to sending documents to all
            sorts of interesting places (least of which is a printer).</p>
            
            <p>For example, for a number of financial institutions I had to write a cover
            letter and include court documentation to establish authority over my mother's
            accounts. I could write the cover letter in Pages, insert the PDF document
            then "print" it to the fax modem. The built-in fax print location even allows
            you to optionally compose a cover page right in the dialog without the need
            for including it in your documents.</p>
            
            <p>Conversely, accepting a fax is pretty simple too. You plug in your modem, set
            it up to receive calls. When you get the document, you can "print" anywhere.
            In my case I would often "print" incoming documents straight into the
            DEVONThink inbox where I could OCR-scan it and file it away for further use.
            No need to print or scan a damn thing. Bits from one end to the other thank
            you very much.</p>
            
            <h1>Conclusion</h1>
            
            <p>So what's this all about then? Why write this post? I'm no productivity guru,
            but I felt like I found a good set of tools and techniques in this experience
            that might be useful for others. None of these really help with dealing with
            the unexpected loss of my mother, but they were a huge help in making the
            onerous task of settling her Estate palpable and possible.</p>
            
            <h1>Notes</h1>
            
            <div id="notes">
              <ol>
                <li>
                  <a name="note1"></a>
                  Actually the stuff I talk about here was really just a stop-loss
                  program. I actually recovered/saved my sanity by taking up drum lessons.
                </li>
              </ol>
            </div>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Muscle Memory</title>
      <link>
        http://alexvollmer.com/posts/2010/11/10/muscle-memory/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/11/10/muscle-memory/#comments
      </comments>
      <pubDate>
        Wed, 10 Nov 2010 12:50:48 PST
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            software
        ]]>
      </category>
      <category>
        <![CDATA[
            music
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/11/10/muscle-memory/
      </guid>
      <description>
        <![CDATA[
            In the world of software we don't often think about the movement of our
            bodies. Oh we argue about Dvorak keyboards and such, but we don't really
            think about the intricate movements we require of our bodies. In other words,
            we argue about mechanics but we don't really understand <em>motion</em>.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>In the world of software we don't often think about the movement of our
            bodies. Oh we argue about Dvorak keyboards and such, but we don't really
            think about the intricate movements we require of our bodies. In other words,
            we argue about mechanics but we don't really understand <em>motion</em>.</p>
            
            <p>In the documentary
            <a href="http://www.rushbeyondthelightedstage.com/">"Rush: Beyond the Lighted Stage"</a>
            there's a great scene where Neil Peart is sitting down with the jazz legend
            Freddie Gruber. In the interview they talk about the first time the two drum
            masters met. They didn't play a note, but instead focused on the dance-like
            motion of percussion. This was an epiphany for Mr. Peart, who is considered by
            many to be <em>the</em> pre-eminent rock drummer of all time. Imagine being at the top
            of your game for nearly forty years and suddenly having a whole new way to look
            at your art! Instead of considering drumming to be the placement of notes in
            time, Gruber thought of drumming as a rhythmic movement of the body that
            happens to coincide with what we call "music".</p>
            
            <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/APzDktOZw5o?fs=1&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/APzDktOZw5o?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>
            
            
            <p>I bring this up because I too, am going through a muscle-memory epiphany. I've
            decided to try vim as my main text editor. I've spent a lot of years with Emacs
            and the last few with TextMate. There are things I love about both, but neither
            is perfect. I've worked with lots of smart people who swear by vim, so why not
            try it out and see what it's all about?</p>
            
            <p>I've always abhorred the silly "holy-wars" between Emacs and vim. It's the
            worst kind of provincial rah-rah-ism in a world where perspective and decent
            manners are few and far between<sup><a href="#note1">1</a></sup>. I am not "switching sides" because, frankly,
            I was never on a particular "side" to begin with. These are simply
            tools&mdash;nothing more.</p>
            
            <p>Here's the funny thing: I've noticed that those that trumpet one over the
            other often have no experience with the alternative. I can think of maybe one
            or two other developers I know that have truly attempted to become experts
            with both editors. Everyone else is simply guessing about "the other side".
            For a profession that espouses hard data and facts, it's amazing how heated
            the debates can be when each side has so little information about the other.</p>
            
            <p>But I digress&hellip;</p>
            
            <h2>The Big Question</h2>
            
            <p>So it got me to thinking. Why is that so few people have tried to master both?
            Is it <em>really</em> impossible to learn a whole new set of keyboard motions once
            you've mastered another?</p>
            
            <p>I often joke with people that the one "super-power" I have as a developer is
            my ability to remember hot-key combinations. When I code in Xcode I know all
            the hot-keys to make it sing. When I'm writing in TextMate I know how to make
            it go. I don't consciously execute keyboard motions, they are just part of the
            development experience with that tool.</p>
            
            <p>The reason I joke about it is because I don't really think that it's all that
            extraordinary. It's true that it's not something I see in a lot of other
            developers, but I don't believe it's because they can't do it. I think it's
            because they've never learned how to learn motion.</p>
            
            <h2>Six Strings and the Truth</h2>
            
            <p>Looking back, I've realized that the greatest learning experience I ever had
            was learning to play the guitar. I started when I was 14 and I was
            deadly-serious about it from day one. I devoured everything I could find on the
            subject. I learned music theory, practiced all manner of finger exercises and
            played and played and played.<sup><a href="#note2">2</a></sup> As a result,
            I'm a pretty good rock guitar player.</p>
            
            <p>The funny side-effect of this experience is that I taught myself how to learn.
            I can still remember learning basic music-theory on a train ride when I was a
            teenager. It just hit me like ton of bricks. It was all so simple. After that,
            the mystery of A&#x266D;7&#x266F;5 was gone. It was obvious what that chord was and what it
            sounded like.</p>
            
            <p>Not only did I learn how to learn in a strictly academic sense (you should see
            the binders full of notes I've kept over the years), but I also learned how to
            teach my fingers to learn. As a result keyboard shortcuts are pretty easy to
            master. It's like learning another song. Nobody agonizes over having to
            remember each and every finger-movement to play a new tune. You practice it,
            play it a few times, see the patterns in it and then it's just <em>there</em>. You
            don't think about it. Why should mastering another editor be any different?</p>
            
            <h2>Brain Stretching</h2>
            
            <p>I'm fascinated with the learning process. I've made it a point in my career to
            make learning a continous process. I simply do not get people who do the same
            thing for years on end. How do they not go insane?</p>
            
            <p>So I'm always looking for ways to stretch myself. This year I'm extending my
            learning more broadly and decided to start taking drum lessons.  Wow. Wanna
            feel awkward in less then two seconds? Try playing the simplest syncopation
            beat requiring independent movement from your limbs. It's a humbling
            experience. But, man, I can't wait to figure it out!</p>
            
            <h2>Circling Back</h2>
            
            <p>So what does this have to with editors? Honestly, I'm not quite sure yet. But
            I think most developers have a pretty narrow view of what they're willing to
            learn. As often as not, I think folks just stick with whatever they happened
            to stumble upon the first time. Think about it. How many things are central to
            your game that are the result of circumstances? Are you an Emacs master just
            because of that one job you had with that one graybeard who taught you all of
            the tricks? How would your career have turned out if you <em>hadn't</em> met that
            guy?</p>
            
            <p>It's not just about editors either. You see it in every dude who lives and dies
            with a single programming language or platform. I've got my favorites too, but
            they've never been eternal. I can't help but think that such a narrow view
            contributes in some way to the mountains of terrible software out there in the
            world. How could anyone possibly build anything of quality with such a small
            view of the world?</p>
            
            <p>So I don't think I'll be practicing my vim with a metronome the way I practice
            stick-control exercises or the way I mastered the harmonic minor scale.
            Instead we practice these motions in our daily development work as a matter of
            course. The fact that our livelihoods are tied to this activity I think makes
            people hesitant to totally re-jigger their game. I get that. But I also think
            it's not as scary as it sounds (I seem to do this in some way every two years
            or so) and it gives you a much broader view of the world.</p>
            
            <p>So Emacs-dudes? Listen up. C-x C-c outta that sucker and try something else.
            You snotty vim dudes? Hit <code>:q</code> and try life on the other side. You
            may still hate it, but don't ever pretend that you couldn't get better by
            learning something radically different.</p>
            
            <h1>Footnotes</h1>
            
            <ol>
              <li>
                <a name="note1"></a>
                Seriously. There are times when I'm just embarassed to call myself a
                software developer. How did we all become so incredibly socially inept?
              </li>
              <li>
                <a name="note2"></a>
                At one point in college, I wrote a program (in Scheme!) that generated
                random chord combinations (e.g. Am7, C&#x266F;maj7, etc. etc.) I taught
                myself to to go from one voicing to another with the least amount of
                fretboard movement. Eventually I extended this to practicing arpeggios too.
                It was like a little game and it was fun to get better and better at it.
              </li>
            </ol>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Assert Yourself!</title>
      <link>
        http://alexvollmer.com/posts/2010/10/17/assert-yourself/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/10/17/assert-yourself/#comments
      </comments>
      <pubDate>
        Sun, 17 Oct 2010 09:46:11 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            uiautomation
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/10/17/assert-yourself/
      </guid>
      <description>
        <![CDATA[
            Well lookee here. It's been a little while since the last post and wouldn't you
            know it? I've got more stuff to share with you about UIAutomation. This time
            it's about a new change made to <a href="http://github.com/alexvollmer/tuneup_js">tuneup</a> that makes it much
            easier and cleaner to assert what a particular window should look like. Like
            everything in tuneup, this new feature was driven by something I really needed
            out of it. I've tried pretty hard not to speculatively add features, instead
            relying on the feedback of my own needs to drive its development.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>Well lookee here. It's been a little while since the last post and wouldn't you
            know it? I've got more stuff to share with you about UIAutomation. This time
            it's about a new change made to <a
            href="http://github.com/alexvollmer/tuneup_js">tuneup</a> that makes it much
            easier and cleaner to assert what a particular window should look like. Like
            everything in tuneup, this new feature was driven by something I really needed
            out of it. I've tried pretty hard not to speculatively add features, instead
            relying on the feedback of my own needs to drive its development.</p>
            
            <p>As I've started writing more UIAutomation tests, I've found that there is
            a common cycle to each test. Generally there is some bit of navigation to get
            yourself somewhere in the app, then you assert a bunch of things about the
            view, and usually navigate somewhere else. I don't think this is far off from
            how you might verbally describe how the app might work. For example, you
            might say: "Go to the main screen, the left button should say 'Cancel' and the
            right button should say 'Done'. Fill in the username and password fields then
            tap the 'Done' button. On the next view you should see the user name in a table
            cell and another cell to add another account".</p>
            
            <p>It's fairly straightforward process translating that description into test
            code:</p>
            
            <div class="highlight"><pre><span class="nx">test</span><span class="p">(</span><span class="s2">&quot;account setup&quot;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="nx">target</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="c1">// initial view</span>&#x000A;      <span class="nb">window</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">();</span>&#x000A;      <span class="nx">navBar</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">();</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Cancel&quot;</span><span class="p">,</span> <span class="nx">navBar</span><span class="p">.</span><span class="nx">leftButton</span><span class="p">().</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Done&quot;</span><span class="p">,</span> <span class="nx">navBar</span><span class="p">.</span><span class="nx">rightButton</span><span class="p">().</span><span class="nx">name</span><span class="p">());</span>&#x000A;    &#x000A;      <span class="nx">table</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Enter your credentials:&quot;</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">groups</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">length</span><span class="p">);</span>&#x000A;    &#x000A;      <span class="nx">userName</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">.</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;username&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">userName</span><span class="p">.</span><span class="nx">textFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;user boy&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">password</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">.</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;password&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">password</span><span class="p">.</span><span class="nx">textFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;sekret&quot;</span><span class="p">);</span>&#x000A;    &#x000A;      <span class="nx">navBar</span><span class="p">.</span><span class="nx">rightButton</span><span class="p">().</span><span class="nx">tap</span><span class="p">();</span>&#x000A;    &#x000A;      <span class="c1">// verify new account on settings view</span>&#x000A;      <span class="nx">navBar</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">();</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;New&quot;</span><span class="p">,</span> <span class="nx">navBar</span><span class="p">.</span><span class="nx">rightButton</span><span class="p">().</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">table</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span>&#x000A;    &#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">groups</span><span class="p">().</span><span class="nx">length</span><span class="p">);</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Your accounts:&quot;</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">groups</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">groups</span><span class="p">()[</span><span class="mi">1</span><span class="p">].</span><span class="nx">name</span><span class="p">());</span>&#x000A;    &#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">length</span><span class="p">);</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;user boy&quot;</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Add Account&quot;</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">()[</span><span class="mi">1</span><span class="p">].</span><span class="nx">name</span><span class="p">());</span>&#x000A;    <span class="p">});</span>&#x000A;    </pre>
            </div>
            
            
            <p>One window's worth of activity isn't so bad, but once you get beyond that, it's
            pretty easy to lose track of what you're trying to do. Comments help a bit, but
            if our code had the same structure that matched the way we think about our
            tests, it would be even better. Now you can do exactly that with a new assertion
            method in tuneup: <code>assertWindow()</code>.  Here's the previous example, re-stated
            with <code>assertWindow()</code>:</p>
            
            <div class="highlight"><pre><span class="nx">test</span><span class="p">(</span><span class="s2">&quot;account setup&quot;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="nx">target</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="nx">assertWindow</span><span class="p">({</span>&#x000A;        <span class="nx">navigationBar</span><span class="o">:</span> <span class="p">{</span>&#x000A;          <span class="nx">leftButton</span><span class="o">:</span>  <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Cancel&quot;</span> <span class="p">},</span>&#x000A;          <span class="nx">rightButton</span><span class="o">:</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Done&quot;</span> <span class="p">}</span>&#x000A;        <span class="p">},</span>&#x000A;        <span class="nx">tableViews</span><span class="o">:</span> <span class="p">[</span>&#x000A;          <span class="p">{</span>&#x000A;            <span class="nx">cells</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">cells</span><span class="p">)</span> <span class="p">{</span>&#x000A;              <span class="nx">cells</span><span class="p">.</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;username&quot;</span><span class="p">).</span><span class="nx">textFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;user boy&quot;</span><span class="p">);</span>&#x000A;              <span class="nx">cells</span><span class="p">.</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;password&quot;</span><span class="p">).</span><span class="nx">textFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;sekret&quot;</span><span class="p">);</span>&#x000A;            <span class="p">}</span>&#x000A;          <span class="p">}</span>&#x000A;        <span class="p">],</span>&#x000A;        <span class="nx">onPass</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nb">window</span><span class="p">)</span> <span class="p">{</span>&#x000A;          <span class="nb">window</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">().</span><span class="nx">rightButton</span><span class="p">().</span><span class="nx">tap</span><span class="p">();</span>&#x000A;        <span class="p">}</span>&#x000A;      <span class="p">});</span>&#x000A;    &#x000A;      <span class="nx">assertWindow</span><span class="p">({</span>&#x000A;        <span class="nx">navigationBar</span><span class="o">:</span> <span class="p">{</span>&#x000A;          <span class="nx">rightButton</span><span class="o">:</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;New&quot;</span> <span class="p">}</span>&#x000A;        <span class="p">},</span>&#x000A;        <span class="nx">tableViews</span><span class="o">:</span> <span class="p">[</span>&#x000A;          <span class="p">{</span>&#x000A;            <span class="nx">groups</span><span class="o">:</span> <span class="p">[</span>&#x000A;              <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Your accounts:&quot;</span> <span class="p">},</span>&#x000A;              <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;&quot;</span> <span class="p">}</span>&#x000A;            <span class="p">],</span>&#x000A;            <span class="nx">cells</span><span class="o">:</span> <span class="p">[</span>&#x000A;              <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;user boy&quot;</span> <span class="p">},</span>&#x000A;              <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Add Account&quot;</span> <span class="p">}</span>&#x000A;            <span class="p">]</span>&#x000A;          <span class="p">}</span>&#x000A;        <span class="p">]</span>&#x000A;      <span class="p">});</span>&#x000A;    <span class="p">});</span>&#x000A;    </pre>
            </div>
            
            
            <p>So what's going on here? Using <code>assertWindow()</code>, we've replaced several lines
            of procedural code with a javascript object-literal that declares how to match
            the current window. The property-nesting in the object given to
            <code>assertWindow()</code> (the "expectation") is matched against the property-nesting of
            the <code>UIAWindow</code> object representing the current view. For example, when we
            declare a <code>navigationBar</code> property in our expectation object, it is matched
            against the object returned by the <code>navigationBar()</code> function invoked on the
            main window (an instance of <code>UIANavigationBar</code>). Then the <code>rightButton</code>
            property is matched against the object returned by the <code>rightButton()</code> method
            (an instance of <code>UIAButton</code>). Finally the <code>name</code> property is matched against
            the object returned by invoking the <code>name()</code> function on the button, which in
            this case is a <code>String</code>.</p>
            
            <p>You can do more than just match <code>Strings</code> though. You can also match numeric
            literals or regular expressions. These are done by applying the <code>assertEquals()</code>
            and <code>assertMatch()</code> functions, respectively. You can also completely customize
            your assertions by providing a function for the property. The corresponding
            object will be given to the function as its single argument. If any exceptions
            are thrown the assertion fails, otherwise the assertion passes.</p>
            
            <p><code>assertWindow()</code> also knows how to handle properties that return arrays (or
            <code>UIAElementArray</code>s). In the example above we matched the <code>tableViews</code> property
            by declaring an array with one element. The number of elements you put in the
            property declaration implicitly makes an assertion about the number of elements
            that should be in the property. If you are only interested in matching <em>some</em>
            of the elements in an array, you can set <code>null</code> for the elements in the array
            you don't care to make assertions about. This will allow you to still pass the
            array-length check without forcing you to write assertions you don't care to.</p>
            
            <p>The <code>onPass</code> property is an optional function you that will be invoked if all
            of the assertions pass. This is a handy way to group assertions and actions
            together in one package. In the example above, we use the <code>onPass</code> function as
            post-assertion navigation to the next screen.</p>
            
            <p>You can find all the gnarly details in the <code>assertions.js</code> file in tuneup. As
            always comments, feedback, forking and patches are all welcome and appreciated.
            Now go out and assert yourself!</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>NSOperations for Fun &amp; Profit</title>
      <link>
        http://alexvollmer.com/posts/2010/09/19/nsoperations-for-fun-and-profit/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/09/19/nsoperations-for-fun-and-profit/#comments
      </comments>
      <pubDate>
        Sun, 19 Sep 2010 16:54:43 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/09/19/nsoperations-for-fun-and-profit/
      </guid>
      <description>
        <![CDATA[
            If you've spent any time working in Cocoa, you get very familiar with
            asynchronous processing. It's the classic <a href="http://en.wikipedia.org/wiki/Hollywood_Principle" title="Hollywood Principle - Wikipedia, the free encyclopedia">"Hollywood Principle"</a>
            &mdash;don't call
            us we'll call you. But what do you do when you have several simultaneous
            asynchronous operations whose results depend on each other? The brute-force,
            caveman approach is to simply have each callback method invoke a single method
            that checks the results of each operation and then proceeds forward when
            everything is completed. But by using Cocoa's <code>NSOperation</code> and
            <code>NSOperationQueue</code> classes you can handle dependent, asynchronous operations
            much more safely and elegantly.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>If you've spent any time working in Cocoa, you get very familiar with
            asynchronous processing. It's the classic <a href="http://en.wikipedia.org/wiki/Hollywood_Principle" title="Hollywood Principle - Wikipedia, the free encyclopedia">"Hollywood Principle"</a>
            &mdash;don't call
            us we'll call you. But what do you do when you have several simultaneous
            asynchronous operations whose results depend on each other? The brute-force,
            caveman approach is to simply have each callback method invoke a single method
            that checks the results of each operation and then proceeds forward when
            everything is completed. But by using Cocoa's <code>NSOperation</code> and
            <code>NSOperationQueue</code> classes you can handle dependent, asynchronous operations
            much more safely and elegantly.</p>
            
            <h1>Kicking it Caveman Style</h1>
            
            <p>Before diving into operations and queues, let's imagine doing this in the
            "primitive" style. Let's say we have three operations: A, B, and C. Each does
            some asynchronous work and we have no idea when it will complete. The
            primitive way of handling this is to have each callback methods invoke a
            single method that checks for the results of all three units of work. Only
            when all three have returned do we continue processing. It might look
            something like this:</p>
            
            <div class="highlight"><pre><span class="c1">// our final unit-of-work when all other operations have completed</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">checkAllOperationsAndProceed</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">resultA</span> <span class="o">&amp;&amp;</span> <span class="n">self</span><span class="p">.</span><span class="n">resultB</span> <span class="o">&amp;&amp;</span> <span class="n">self</span><span class="p">.</span><span class="n">resultC</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="c1">// do that magic thing you do</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="c1">// our mythical call-back methods</span>&#x000A;    &#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">operationADidComplete:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="n">result</span> <span class="p">{</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">resultA</span> <span class="o">=</span> <span class="n">result</span><span class="p">;</span>&#x000A;      <span class="p">[</span><span class="n">self</span> <span class="n">checkAllOperationsAndProceed</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">operationBDidComplete:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="n">result</span> <span class="p">{</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">resultB</span> <span class="o">=</span> <span class="n">result</span><span class="p">;</span>&#x000A;      <span class="p">[</span><span class="n">self</span> <span class="n">checkAllOperationsAndProceed</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">operationCDidComplete:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="n">result</span> <span class="p">{</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">resultC</span> <span class="o">=</span> <span class="n">result</span><span class="p">;</span>&#x000A;      <span class="p">[</span><span class="n">self</span> <span class="n">checkAllOperationsAndProceed</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>You can think of this as a "last-one-in-wins" pattern. It's kind of ugly and
            doesn't scale well with more complicated dependencies. It gets worse when
            you have specific threading concerns like working with Core Data, which is
            notoriously fussy about threads.</p>
            
            <p>I had this exact problem using Core Location and Game Kit. I use Core Location
            to first retrieve the current location, while simultaneously communicating
            with other devices via Game Kit. When the location is resolved, we then
            attempt to reverse-geocode it which results in another asynchronous operation.
            All of these bits of work are intertwined and update the underlying persistent
            model in different ways. It didn't take too long before it spiraled completely
            out of control. What's more, it was easy to hit odd edge-cases with
            synchronizing various threads to keep Core Data happy. Since I wasn't getting
            consistent failures, it was clear that there were race-conditions in the code.
            Then a little voice in the back of my head reminded me that <code>NSOperation</code>
            instances can have dependencies between each other. A ha!</p>
            
            <h1>A More Elegant Weapon, for a More Civilized Age</h1>
            
            <p>Maybe the caveman approach doesn't offend your sensibilities for such a
            trivial example. But imagine a much more complicated set of dependencies,
            perhaps something that looked like this <sup><a href="#note1">1</a></sup>:</p>
            
            <p><img src="/images/2010/09/operation-dependencies.png" alt="operation dependencies" /></p>
            
            <p>Now imagine all the <code>if</code> checks and the spaghetti code that would be required
            to make this work. I don't know about you, but this makes my Spidey-sense
            tingle&hellip;and not in a good way.</p>
            
            <p>So let's turn these into <code>NSOperation</code> instances with dependencies. We would
            start with method prototypes and properties declarations like this:</p>
            
            <div class="highlight"><pre><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">NSOperationQueue</span>  <span class="o">*</span><span class="n">operationQueue</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationA</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationB</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationC</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationD</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationE</span><span class="p">;</span>&#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">NSOperation</span>       <span class="o">*</span><span class="n">operationF</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="n">performOperationA</span><span class="p">;</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationB</span><span class="p">;</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationC</span><span class="p">;</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationD</span><span class="p">;</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationE</span><span class="p">;</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationF</span><span class="p">;</span>&#x000A;    </pre>
            </div>
            
            
            <p>We'll do the actual work in instance methods of our class and wrap each
            one with an instance of <code>NSInvocationOperation</code>. Here's our setup method:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">initializeOperations</span> <span class="p">{</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationQueue</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSOperationQueue</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;      <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">operationQueue</span> <span class="nl">setMaxConcurrentOperationCount:</span><span class="mi">1</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationA</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationA</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;                                                               &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationB</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationB</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</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">operationB</span> <span class="nl">addDependency:</span><span class="n">operationA</span><span class="p">];</span>&#x000A;                                                               &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationC</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationC</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;                                                               &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationD</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationD</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</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">operationD</span> <span class="nl">addDependency:</span><span class="n">operationA</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">operationD</span> <span class="nl">addDependency:</span><span class="n">operationC</span><span class="p">];</span>&#x000A;                                                               &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationE</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationE</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;                                                               &#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">operationF</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">NSInvocationOperation</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithTarget:</span><span class="n">self</span>&#x000A;                                                              <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="n">performOperationF</span><span class="p">),</span>&#x000A;                                                               <span class="nl">object:</span><span class="nb">nil</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">operationE</span> <span class="nl">addDependency:</span><span class="n">operationD</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">operationE</span> <span class="nl">addDependency:</span><span class="n">operationF</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>One interesting thing to note here is that the operations that have
            dependencies could be queued right away. They won't execute until their
            dependent operations execute first. Another cool feature of <code>NSOperation</code>s
            is that dependent operations <em>don't</em> have to execute in the same operation
            queue. Believe it or not, I've actually needed this very feature.</p>
            
            <p>To execute these operations in the correct order, we simply need to add
            them to the queue. If the dependencies are correctly declared, the order in
            which we add them is irrelevant. Instead the final execution order is
            determined by the dependency graph of the queued operations<sup><a href="#note2"></a></sup>.
            So one of our asynchronous callback methods might look like this:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">didGetSpecialCallback:</span><span class="p">(</span><span class="n">NSDictionary</span> <span class="o">*</span><span class="p">)</span><span class="n">userInfo</span> <span class="p">{</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">firstName</span> <span class="o">=</span> <span class="p">[</span><span class="n">userInfo</span> <span class="nl">objectForKey:</span><span class="s">@&quot;firstName&quot;</span><span class="p">];</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">lastName</span> <span class="o">=</span> <span class="p">[</span><span class="n">userInfo</span> <span class="nl">objectForKey:</span><span class="s">@&quot;lastName&quot;</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">operationQueue</span> <span class="nl">addOperation:</span><span class="n">operationD</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>The call to add <code>operationD</code> is <em>effectively</em> like invoking the
            <code>performOperationD</code> method except that it won't get executed until it's
            two dependent methods, <code>operationA</code> and <code>operationC</code> have completed first.
            But the beauty of all of this, is that my callback code doesn't have to care
            about that ordering.</p>
            
            <p>Once your code has enough concurrent asynchronous operations that are
            dependent on each other, this can be a great way of straightening out what
            work is going to get done in a thread-safe way.</p>
            
            <h1>Rules of Thumb</h1>
            
            <h2>Queues Make Life Easy</h2>
            
            <p>One common principle of concurrency is being able to replace mutexes
            (muteces?) with queues. Any time you have shared data operated on by multiple
            threads, you can synchronize them with serial operations in a single queue
            instead of using explicit locks. The operations in my app are lightning-quick
            so I'm not worried about slowing things down with a single-threaded queue. A
            great side-effect in using operations with dependencies is that I know
            <em>precisely</em> what order those units of work are going to execute. This takes
            away a slew of edge-cases that are difficult to reproduce and debug.</p>
            
            <h2>Be Assertive</h2>
            
            <p>Because you know the order of operations, you can put a nice safety-net
            underneath yourself as you develop with a liberal application of assertions.
            For example, in the operation 'D', which requires that 'A' and 'C' have
            completed, the code can expressly assert that effects of 'A' and 'C' have
            been applied. If they aren't, it means there's a programming error:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">performOperationD</span> <span class="p">{</span>&#x000A;      <span class="k">@try</span> <span class="p">{</span>&#x000A;        <span class="n">NSAssert</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">firstName</span> <span class="o">!=</span> <span class="nb">nil</span><span class="p">,</span> <span class="s">&quot;First name is nil!&quot;</span><span class="p">);</span>&#x000A;        <span class="n">NSAssert</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">lastName</span> <span class="o">!=</span> <span class="nb">nil</span><span class="p">,</span> <span class="s">&quot;Last name is nil!&quot;</span><span class="p">);</span>&#x000A;    &#x000A;        <span class="c1">// rest of method elided for readability</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">@catch</span> <span class="p">(</span><span class="n">NSException</span> <span class="o">*</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;ERROR associating place with encounter: %@&quot;</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <h2>Try, Try Again</h2>
            
            <p>The last piece of advice is to make sure you put <code>@try/@catch</code> blocks in
            the methods that are executed by your operations. Since these are on a
            separate thread, you may not see a standard backtrace when an exception is
            thrown. You need to handle this yourself, otherwise things may silently
            fail. This is especially true of Core Data which will throw exceptions for
            programming errors like accessing objects with the wrong thread.</p>
            
            <h1 id="footnotes">Footnotes</h1>
            
            
            <ol>
              <li>
                <a name="note1"></a>
                This is a simplified version of the dependency graph of an application
                I'm currently working on, so it's not just some trite example I
                invented to make a point. Rather than saddle you with the mundane 
                details of each operation, I've chosen to go with the rather abstract,
                if boring, A-B-C nomenclature.
              </li>
              <li>
                <a name="note2"></a>
                Okay, that's not strictly true. Operations can also have different
                priorities which also affect the execution order. However assuming that
                all operations have the same priority, the original statement still
                holds true.
              </li>
            </ol>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Launching the Radiant Capsule</title>
      <link>
        http://alexvollmer.com/posts/2010/09/12/launching-the-radiant-capsule/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/09/12/launching-the-radiant-capsule/#comments
      </comments>
      <pubDate>
        Sun, 12 Sep 2010 12:26:30 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            biz
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/09/12/launching-the-radiant-capsule/
      </guid>
      <description>
        <![CDATA[
            A while back <a href="http://alexvollmer.com/posts/2010/04/17/thanks-mom/" title="Alex Vollmer &mdash; Thanks, mom">I posted</a>
            about a significant career-change brought about by the
            untimely death of my mom. This ultimately resulted in the formation
            of my own one-man company, <a href="http://www.radiantcapsule.com/" title="Radiant Capsule LLC&mdash;Mobile. Web. People.">Radiant Capsule</a>.
            I used to find the idea of forming a company pretty daunting&mdash;all the
            paperwork, all the tax-filing dates and whatnot to remember. It was all pretty
            overwhelming. But since I've launched headlong into settling my mom's estate,
            the effort forming an LLC seemed trivial by comparison.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>A while back <a href="http://alexvollmer.com/posts/2010/04/17/thanks-mom/" title="Alex Vollmer &mdash; Thanks, mom">I posted</a>
            about a significant career-change brought about by the
            untimely death of my mom. This ultimately resulted in the formation
            of my own one-man company, <a href="http://www.radiantcapsule.com/" title="Radiant Capsule LLC&mdash;Mobile. Web. People.">Radiant Capsule</a>.
            I used to find the idea of forming a company pretty daunting&mdash;all the
            paperwork, all the tax-filing dates and whatnot to remember. It was all pretty
            overwhelming. But since I've launched headlong into settling my mom's estate,
            the effort forming an LLC seemed trivial by comparison.</p>
            
            <p><img src="/images/2010/09/rc-biz-cards.jpg" class="right"/></p>
            
            <p>So what's with the name? Kinda weird, isn't it? I went around and around on
            various names. Eventually I settled on something related to space. I really love
            the look and design of Stanley Kubrick's <em>2001: A Space Odyssey</em>. Not so much
            for how it looks retro from our modern perspective, but how futuristic it
            looked from 1969. I settled on having the word "capsule" in the name somewhere
            because I liked the idea of a self-contained package. Right now it's just me,
            but even if I ever bring on partners, I don't expect it to be too big. So
            "space station" would have been inappropriate given the philosophy behind the
            company.</p>
            
            <p>Why "radiant"?. Rhythmically, I knew I wanted a name in the form of
            "<em>insert-adjective-here</em> Capsule". I sat down one afternoon, in complete
            silence, and just wrote adjective after adjective on a sheet of paper. Just
            trying out words I liked, and listening to how they sounded together. Finally
            I hit upon "Radiant Capsule" and I felt like I had a winner. I just really
            like the way it sounds.</p>
            
            <p>The design was bootstrapped by the logo which was created by
            <a href="http://whole-studios.com/" title="Ryan Eilers Schroeder | Graphic &amp; UX Design">Ryan Schroeder</a>.
            After that I was off and running. I don't know whether you can call the
            site design and business cards "good", but it is certainly some of the best
            visual design I've ever done. Like all of this, it's a learning experience.</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>UIAutomation Test Fixtures Redux</title>
      <link>
        http://alexvollmer.com/posts/2010/09/06/uiautomation-test-fixtures-redux/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/09/06/uiautomation-test-fixtures-redux/#comments
      </comments>
      <pubDate>
        Mon, 06 Sep 2010 14:41:13 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            iphone
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            uiautomation
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/09/06/uiautomation-test-fixtures-redux/
      </guid>
      <description>
        <![CDATA[
            In my ongoing exploration of the UIAutomation tool, I've iterated several
            times on implementing test fixtures. In this context, "test fixture" means
            a pre-defined starting state for the system-under-test (SUT). In my case, my
            test fixtures are focused almost exclusively on the current state of the
            persistent Core Data database. While I think this is an obvious case of an
            integration-test fixture, it's not the only possibility.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>In my ongoing exploration of the UIAutomation tool, I've iterated several
            times on implementing test fixtures. In this context, "test fixture" means
            a pre-defined starting state for the system-under-test (SUT). In my case, my
            test fixtures are focused almost exclusively on the current state of the
            persistent Core Data database. While I think this is an obvious case of an
            integration-test fixture, it's not the only possibility.</p>
            
            <h1>It's About Dependencies</h1>
            
            <p>I think it's worth backing up and explaining why I've spent so much time
            noodling on test fixtures. Any system of moderate complexity has features that
            depend on the existence of other features. For example it doesn't make sense
            to have a "recover your forgotten password" feature without having an
            authentication feature that requires a password in the first place. If you
            drew each of your features in a box then drew a line between each feature and
            its prerequisite features, you would have a graph of feature-dependencies.
            <sup><a href="#note1">1</a></sup></p>
            
            <p>When we design a system, we look for patterns in these dependencies. If we're
            smart enough and have enough experience, we'll do our best to reduce those
            dependencies, and figure out how to minimize the coupling between them. When
            we get this wrong, we something that gets hard to maintain and change
            over time.</p>
            
            <p>A big part of using dependency-analysis in our design is figuring out exactly
            at what level our features are dependent upon each other. In our
            forgotten-password example, the question to ask is <em>how much of the
            user-authentication feature does recovering a forgotten password depend on?</em>.
            To answer this question, you have to start imagining different ways the
            authentication feature could be implemented. Which ones would break the
            forgotten-password feature? Which ones would make it irrelevant?</p>
            
            <p>From the perspective of system-design it makes no sense to tie the
            implementation of the forgotten-password feature to the form-submission
            process of authentication. Instead, these features <em>should</em> be coupled at
            wherever you store authentication information (likely a database). You should
            be able to modify the authentication process without directly breaking the
            forgotten-password feature.</p>
            
            <p>Returning to automated testing, the same idea applies. But I think a lot of
            people don't factor their tests this way. Instead, a lot of test-writers
            get so wrapped-up in code reuse that they often recycle tests of dependent
            features as a way of getting the SUT into a starting state. This is a mistake.
            Just like we wouldn't over-couple the implementations of dependent features,
            we should't over-couple our tests for them. If we do, we end up with a
            very brittle suite of tests.</p>
            
            <p>We also end up losing a lot of feedback from the testing process. If the
            authentication test is failing, does that necessarily mean we should invalidate
            all the other tests that use authentication information? Logically, the answer
            is <em>no</em>. But with test-reuse that's exactly what we get. So when one feature
            breaks and a bunch of tests fail, we have no idea just how broken the system
            really is.</p>
            
            <h1>A New Perspective</h1>
            
            <p><img class="right" src="/images/2010/09/meechu-test-fixtures.png"/></p>
            
            <p>Coming back to UIAutomation, I made the decision early on to build test
            fixtures that focused on the current persistent state of the system. Much of
            the logic of the application revolves around the state of Core Data database.
            I made a conscious decision to couple the features at the persistent-store
            layer so, by extension, I've done the same for my test-fixture code.</p>
            
            <p>In my <a href="http://alexvollmer.com/posts/2010/07/09/more-uiautomation/" title="Alex
            Vollmer &mdash; More UIAutomation">first
            attempt</a>, I built a rather complicated Rube
            Goldberg contraption that simply wasn't going to scale as I added more
            fixtures. The first problem I needed to solve was to cut down on the amount of
            build variation. My original solution involved a separate build-configuration
            for each test-fixture. The problem was that my tests had an implicit
            dependency on a particular test build, but I had no way to express that with
            UIAutomation. The best I could do was simply add comments to the top of my
            tests. Blech. Too easy to get that wrong and waste a bunch of time figuring
            out why things weren't working. This is <em>not</em> what I want out of my
            integration tests.</p>
            
            <p>So the first step was to get rid of the separate build configurations. I
            replaced them with a single "Integration Test" build configuration that
            defines a build-time variable that is used in my app delegate like so
            <sup><a href="#note2">2</a></sup>:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">applicationDidFinishLaunching:</span><span class="p">(</span><span class="n">UIApplication</span> <span class="o">*</span><span class="p">)</span><span class="n">application</span> <span class="p">{</span>    &#x000A;    <span class="cp">#ifdef MEECHU_RESET_FOR_TESTING</span>&#x000A;      <span class="n">self</span><span class="p">.</span><span class="n">testFixturesController</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">TestFixtureViewController</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithDelegate:</span><span class="n">self</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">window</span> <span class="nl">addSubview:</span><span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">testFixturesController</span> <span class="n">view</span><span class="p">]];</span>&#x000A;    <span class="cp">#else</span>&#x000A;        <span class="p">[</span><span class="n">window</span> <span class="nl">addSubview:</span><span class="p">[</span><span class="n">navigationController</span> <span class="n">view</span><span class="p">]];</span>&#x000A;      <span class="p">[</span><span class="n">self</span> <span class="n">checkFirstTimeUser</span><span class="p">];</span>&#x000A;    <span class="cp">#endif  </span>&#x000A;      <span class="p">[</span><span class="n">window</span> <span class="n">makeKeyAndVisible</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>If the <code>MEECHU_RESET_FOR_TESTING</code> compiler flag is set, we insert a special
            test-fixture controller into the UI. That view controller is simply a
            control-board for running any number of pre-defined test-fixture operations.
            Here's an example of one such operation that completely nukes my Core Data
            database:</p>
            
            <div class="highlight"><pre><span class="k">@implementation</span> <span class="nc">ClearAllDataOperation</span>&#x000A;    &#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">main</span> <span class="p">{</span>&#x000A;      <span class="n">MeechuAppDelegate</span> <span class="o">*</span><span class="n">meechu</span> <span class="o">=</span> <span class="p">(</span><span class="n">MeechuAppDelegate</span> <span class="o">*</span><span class="p">)[[</span><span class="n">UIApplication</span> <span class="n">sharedApplication</span><span class="p">]</span> <span class="n">delegate</span><span class="p">];</span>&#x000A;                                                        &#x000A;      <span class="n">NSPersistentStoreCoordinator</span> <span class="o">*</span><span class="n">coordinator</span> <span class="o">=</span> <span class="p">[</span><span class="n">meechu</span> <span class="n">persistentStoreCoordinator</span><span class="p">];</span>&#x000A;      <span class="n">NSError</span> <span class="o">*</span><span class="n">error</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>&#x000A;      <span class="k">for</span> <span class="p">(</span><span class="n">NSPersistentStore</span> <span class="o">*</span><span class="n">store</span> <span class="k">in</span> <span class="p">[</span><span class="n">coordinator</span> <span class="n">persistentStores</span><span class="p">])</span> <span class="p">{</span>&#x000A;        <span class="p">[</span><span class="n">coordinator</span> <span class="nl">removePersistentStore:</span><span class="n">store</span> <span class="nl">error:</span><span class="o">&amp;</span><span class="n">error</span><span class="p">];</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>&#x000A;          <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Unable to remove persistent store %@: %@&quot;</span><span class="p">,</span> <span class="n">store</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>&#x000A;          <span class="k">return</span><span class="p">;</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="p">[[</span><span class="n">NSFileManager</span> <span class="n">defaultManager</span><span class="p">]</span> <span class="nl">removeItemAtURL:</span><span class="p">[</span><span class="n">store</span> <span class="n">URL</span><span class="p">]</span> <span class="nl">error:</span><span class="o">&amp;</span><span class="n">error</span><span class="p">];</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>&#x000A;          <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Unable to remove persistent store file %@: %@&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">store</span> <span class="n">URL</span><span class="p">],</span> <span class="n">error</span><span class="p">);</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="p">[</span><span class="n">coordinator</span> <span class="nl">addPersistentStoreWithType:</span><span class="p">[</span><span class="n">store</span> <span class="n">type</span><span class="p">]</span>&#x000A;                                  <span class="nl">configuration:</span><span class="nb">nil</span>&#x000A;                                            <span class="nl">URL:</span><span class="p">[</span><span class="n">store</span> <span class="n">URL</span><span class="p">]</span>&#x000A;                                        <span class="nl">options:</span><span class="p">[</span><span class="n">store</span> <span class="n">options</span><span class="p">]</span>&#x000A;                                                <span class="nl">error:</span><span class="o">&amp;</span><span class="n">error</span><span class="p">])</span> <span class="p">{</span>&#x000A;          <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Unable to create new persistent store at %@: %@&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">store</span> <span class="n">URL</span><span class="p">],</span> <span class="n">error</span><span class="p">);</span>&#x000A;          <span class="k">return</span><span class="p">;</span>&#x000A;        <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>I have a couple of other test-fixture operations like this. All of them
            fiddle with the underlying Core Data database.</p>
            
            <p>The next step was to create some kind of first-class representation of this
            "control-board" in my JavaScript layer. So I wrote a small wrapper for the
            test-fixture view controller:</p>
            
            <div class="highlight"><pre><span class="nx">TestFixtures</span> <span class="o">=</span> <span class="p">{</span>&#x000A;      <span class="nx">ensureFixturesMenu</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">target</span> <span class="o">=</span> <span class="nx">UIATarget</span><span class="p">.</span><span class="nx">localTarget</span><span class="p">();</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">application</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">frontMostApp</span><span class="p">();</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">mainWindow</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">application</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">();</span>&#x000A;        <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Test Fixtures&quot;</span><span class="p">,</span> <span class="nx">application</span><span class="p">.</span><span class="nx">navigationTitle</span><span class="p">());</span>&#x000A;      <span class="p">},</span>&#x000A;      &#x000A;      <span class="nx">addTwitterAccount</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">ensureFixturesMenu</span><span class="p">();</span>&#x000A;        <span class="nx">cell</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;addtwitteraccountoperation&quot;</span><span class="p">);</span>&#x000A;        <span class="nx">cell</span><span class="p">.</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      <span class="p">},</span>&#x000A;      &#x000A;      <span class="nx">addEncounters</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">ensureFixturesMenu</span><span class="p">();</span>&#x000A;        <span class="nx">cell</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;addencounterhistoryoperation&quot;</span><span class="p">);</span>&#x000A;        <span class="nx">cell</span><span class="p">.</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      <span class="p">},</span>&#x000A;      &#x000A;      <span class="nx">clearAllData</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">ensureFixturesMenu</span><span class="p">();</span>&#x000A;        <span class="nx">cell</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;clearalldataoperation&quot;</span><span class="p">);</span>&#x000A;        <span class="nx">cell</span><span class="p">.</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      <span class="p">},</span>&#x000A;      &#x000A;      <span class="nx">close</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>&#x000A;        <span class="k">this</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">().</span><span class="nx">rightButton</span><span class="p">().</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">};</span>&#x000A;    </pre>
            </div>
            
            
            <p>With these in place, the final task was explicitly defining the test-fixtures
            for each automation test. Now the pre-requisites for the test are specified
            right in the test, which greatly clarifies the pre-requisites for the test:</p>
            
            <div class="highlight"><pre><span class="err">#</span><span class="kr">import</span> <span class="s2">&quot;tuneup/tuneup.js&quot;</span>&#x000A;    <span class="err">#</span><span class="kr">import</span> <span class="s2">&quot;fixtures.js&quot;</span>&#x000A;    &#x000A;    <span class="nx">test</span><span class="p">(</span><span class="s2">&quot;Additional Account&quot;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">app</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="nx">TestFixtures</span><span class="p">.</span><span class="nx">clearAllData</span><span class="p">();</span>&#x000A;      <span class="nx">TestFixtures</span><span class="p">.</span><span class="nx">addTwitterAccount</span><span class="p">();</span>&#x000A;      <span class="nx">TestFixtures</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>&#x000A;    &#x000A;      <span class="c1">// test continues here</span>&#x000A;    <span class="p">});</span>&#x000A;    </pre>
            </div>
            
            
            <p>Now when the tests run, the test-fixture view controller appears, the test
            pokes a button for each fixture operation it requires, dismisses the
            test-fixture setup and continues on its merry way.</p>
            
            <h1>Conclusion</h1>
            
            <p>This is definitely a step forward, but I think there is some more refinement
            to be had. First, there's still too much duplication for my tastes. For each
            new test-fixture operation I have to update the view controller as well as the
            JavaScript wrapper file. I don't think it would take too much effort to
            automatically generate the view controller and wrapper JavaScript code simply
            by snooping the directory that contains the test-fixture operation classes in
            the same way <a href="http://rentzsch.github.com/mogenerator/" title="mogenerator + Xmo’d">Xmo'd</a>
            does for Core Data models and generated classes.</p>
            
            <h1 id="footnotes">Footnotes</h1>
            
            
            <ol>
              <li>
                <a name="note1"></a>
                It's amazing how much a simple drawing exercise can reveal about your
                project in ways that simply reading the code doesn't. I've found it 
                really helpful to sketch stuff out with paper and pencil or use
                <a href="http://www.omnigroup.com/applications/omnigraffle/" title="OmniGraffle for Mac - Products - The Omni Group">OmniGraffle</a> for quick box-sketches.
              </li>
              <li>
                <a name="note2"></a>
                You could argue that having separate builds isn't strictly necessary.
                All I'm really trying to do is avoid having test-related code in my
                final application bundle. That could simply be expressed by the
                differences between the stock "Debug" and "Release" build configurations.
              </li>
            </ol>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Design Pressures of Mock Objects</title>
      <link>
        http://alexvollmer.com/posts/2010/07/25/design-pressures-of-mock-objects/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/07/25/design-pressures-of-mock-objects/#comments
      </comments>
      <pubDate>
        Sun, 25 Jul 2010 16:41:25 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/07/25/design-pressures-of-mock-objects/
      </guid>
      <description>
        <![CDATA[
            <a href="http://seattlexcoders.org/2010/07/13/july-22-eastside-meeting---alex-vollmer-on-ocmock.html" title="Seattle Xcoders - July 22 Eastside Meeting - Alex Vollmer on OCMock">Last Thursday</a>
            I gave a presentation to the Eastside Xcoders on the topic
            of <a href="http://www.mulle-kybernetik.com/software/OCMock/" title="Mulle kybernetiK -- OCMock">OCMock</a>
            and, more generally, the role of mock objects in test-driven development. One
            of the great things about the process of teaching (or presenting) is getting
            a chance to really solidify the topic which you're sharing with others.
            The process of putting <a href="https://docs.google.com/fileview?id=0BzuECX7-PruNYjEwOWU4ZTUtODhhOC00ZTlmLWE1NzQtNGQzMjJkM2FiMzA1&amp;amp;hl=en">this presentation</a>
            together really clarified some things that I intuitively understood, but
            couldn't necessarily articulate very well about testing and design.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p><a href="http://seattlexcoders.org/2010/07/13/july-22-eastside-meeting---alex-vollmer-on-ocmock.html" title="Seattle Xcoders - July 22 Eastside Meeting - Alex Vollmer on OCMock">Last Thursday</a>
            I gave a presentation to the Eastside Xcoders on the topic
            of <a href="http://www.mulle-kybernetik.com/software/OCMock/" title="Mulle kybernetiK -- OCMock">OCMock</a>
            and, more generally, the role of mock objects in test-driven development. One
            of the great things about the process of teaching (or presenting) is getting
            a chance to really solidify the topic which you're sharing with others.
            The process of putting <a href="https://docs.google.com/fileview?id=0BzuECX7-PruNYjEwOWU4ZTUtODhhOC00ZTlmLWE1NzQtNGQzMjJkM2FiMzA1&amp;amp;hl=en">this presentation</a>
            together really clarified some things that I intuitively understood, but
            couldn't necessarily articulate very well about testing and design.</p>
            
            <p>One of the biggest "a-ha!" moments was triggered by creating my favorite slide
            in the whole presentation, which came near the end after we'd covered all the
            ins and outs of OCMock.</p>
            
            <p><img src="/images/2010/07/abstract.png" title="Where I'm willing to mock, I'm willing to abstract"/></p>
            
            <p>This phrase came to me as I thought about the "design pressures" that TDD
            often brings to your code. To me, these pressures are one of most important
            (yet subtle) forces that TDD brings to bear. TDD practitioners often refer
            to TDD as a feedback mechanism. To me, this notion of where to draw the lines
            of responsibility became really clear when I thought about the first place
            I often do it&mdash;in my tests.</p>
            
            <p>Let me explain what I mean by that phrase. First, I should say that I tend to
            bring in mock objects in a limited set of circumstances. It's not the first
            tool I reach for in my unit-tests. I don't like tests that simply re-assert
            the implementation as I think it gives you a false sense of security. The
            times when I <em>will</em> use mocks are:</p>
            
            <ul>
            <li>When I'm replacing third-party collaborators that I don't control</li>
            <li>When creating a stub would just obscure the test</li>
            <li>Writing single use-case test stubs. I'll wait until I get three of them
            before I factor out a common stub.</li>
            <li>When I need to test for side-effects (e.g. logging or caching)</li>
            </ul>
            
            
            <p>The first reason is the primary motivation I'd have to consider a layer of
            abstraction. First, because (obviously) the third-party is under someone
            else's control, but also because I usually want to simplify a more
            fully-featured and general API to something more specific to my domain. By
            encapsulating the details of something like GameKit into a little façade
            class, I've built a nice little box around it that doesn't leak into other
            classes.</p>
            
            <p>So maybe it's not an earth-shattering realization. Maybe it's just that I
            finally have a clearer articulation of the idea in my head. Like I said,
            it's amazing what you learn when you teach it to someone else.</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>More UIAutomation</title>
      <link>
        http://alexvollmer.com/posts/2010/07/09/more-uiautomation/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/07/09/more-uiautomation/#comments
      </comments>
      <pubDate>
        Fri, 09 Jul 2010 07:14:06 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <category>
        <![CDATA[
            uiautomation
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/07/09/more-uiautomation/
      </guid>
      <description>
        <![CDATA[
            After having spent another week with Apple's UI Automation framework, it's
            clear that to really wring the most benefit out of it, you need to roll up
            your sleeves and extend what's already there. One area that UI Automation
            gives you no help is establishing an initial state for your application to run
            your tests against. So this week I hacked something to do just that.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>After having spent another week with Apple's UI Automation framework, it's
            clear that to really wring the most benefit out of it, you need to roll up
            your sleeves and extend what's already there. One area that UI Automation
            gives you no help is establishing an initial state for your application to run
            your tests against. So this week I hacked something to do just that.</p>
            
            <h1>Why We Do What We Do</h1>
            
            <p>Before moving forward, it's probably worth reviewing what my goal is with
            UI Automation (or any integration testing setup for that matter). To me,
            testing, whether it's  unit-testing or integration-testing, is all a matter
            of economics. There is a balance to be struck between the up-front investment
            in the test harness and the long-term risk mitigation that it provides. One
            of the things that has frustrated me about test automation in Cocoa is how
            expensive it can get to build and maintain this stuff compared to other
            environments I've worked in. At a certain point, if the cost is too high,
            I'm perfectly willing to abandon the effort.</p>
            
            <p><img src="/images/2010/07/thx1138.png" class="right"/></p>
            
            <p>I like to think of it like the last scene of the film <em>THX-1138</em>. There's a
            wonderful shot in the command and control center that shows the running cost
            of pursuing the escaped fugitives. At a certain point the cost exceeds the
            budget of the pursuit and the hounds are called off. That's somewhat like my
            attitude toward test automation. It's not an absolute, totalitarian,
            philosophical must-have. I only insist on it when it makes sense.</p>
            
            <h1>Setting the Stage</h1>
            
            <p>The UI Automation toolkit provides <em>a portion</em> of what I think we need for an
            effective integration-test suite, but not all of it. A good suite would have
            the following properties:</p>
            
            <ol>
            <li>runs on the device or simulator with equal ease</li>
            <li>has a rich API to dig deep into the details of the running system</li>
            <li>is extensible so that we can build abstractions over the aforementioned
            rich API</li>
            <li>is completely automatable from the command-line for continuous integration
            builds</li>
            <li>provides a way to set your application in particular states as a
            pre-condition for tests</li>
            </ol>
            
            
            <p>UI Automation covers the first three items, but completely misses on the
            fourth item. It doesn't help with the last item, but doesn't necessarily
            preclude a solution either.</p>
            
            <p>What I did was create a special block of code in my application delegate that
            looks for some extra configuration in the application plist file. Since I
            don't plan on ever needing any of this stuff in a release, it's all guarded
            by an <code>#ifdef</code> statement.</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">applicationDidFinishLaunching:</span><span class="p">(</span><span class="n">UIApplication</span> <span class="o">*</span><span class="p">)</span><span class="n">application</span> <span class="p">{</span>    &#x000A;    <span class="cp">#ifdef MEECHU_RESET_FOR_TESTING</span>&#x000A;      <span class="n">NSArray</span> <span class="o">*</span><span class="n">operations</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSBundle</span> <span class="n">mainBundle</span><span class="p">]</span> <span class="nl">objectForInfoDictionaryKey:</span><span class="s">@&quot;MUTestHarnessOperations&quot;</span><span class="p">];</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="n">operations</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="n">NSOperationQueue</span> <span class="o">*</span><span class="n">queue</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSOperationQueue</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>&#x000A;        <span class="p">[</span><span class="n">queue</span> <span class="nl">setMaxConcurrentOperationCount:</span><span class="mi">1</span><span class="p">];</span>&#x000A;        <span class="k">for</span> <span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="n">opName</span> <span class="k">in</span> <span class="n">operations</span><span class="p">)</span> <span class="p">{</span>&#x000A;          <span class="n">Class</span> <span class="n">clazz</span> <span class="o">=</span> <span class="n">NSClassFromString</span><span class="p">(</span><span class="n">opName</span><span class="p">);</span>&#x000A;          <span class="n">NSOperation</span> <span class="o">*</span><span class="n">op</span> <span class="o">=</span> <span class="p">(</span><span class="n">NSOperation</span> <span class="o">*</span><span class="p">)[[[</span><span class="n">clazz</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;          <span class="p">[</span><span class="n">queue</span> <span class="nl">addOperation:</span><span class="n">op</span><span class="p">];</span>&#x000A;          <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Enqueued operation: %@&quot;</span><span class="p">,</span> <span class="n">NSStringFromClass</span><span class="p">(</span><span class="n">clazz</span><span class="p">));</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="p">[</span><span class="n">queue</span> <span class="n">waitUntilAllOperationsAreFinished</span><span class="p">];</span>&#x000A;        <span class="p">[</span><span class="n">queue</span> <span class="n">release</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="cp">#endif</span>&#x000A;    &#x000A;      <span class="p">[</span><span class="n">window</span> <span class="nl">addSubview:</span><span class="p">[</span><span class="n">navigationController</span> <span class="n">view</span><span class="p">]];</span>&#x000A;      <span class="p">[</span><span class="n">window</span> <span class="n">makeKeyAndVisible</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>In the special block, if I find the string array associated with the key
            <code>MUTestHarnessOperations</code> in the application plist, I treat each string as a
            class name which is instantiated and added to an operation queue. Now I don't
            have any concurrency requirements which led me to use an <code>NSOperationQueue</code>.
            Instead, it seemed like a nice way to package up discrete bits of work.</p>
            
            <p>One of these setup classes creates an account (an instance of <code>MUAccount</code>)
            that some of my tests rely on. It looks something like this:</p>
            
            <div class="highlight"><pre><span class="k">@interface</span> <span class="nc">AddTwitterAccountOperation</span> : <span class="nc">NSOperation</span> <span class="p">{</span>&#x000A;    <span class="p">}</span>&#x000A;    <span class="k">@end</span>&#x000A;    </pre>
            </div>
            
            
            
            
            <div class="highlight"><pre><span class="cp">#import &lt;CoreData/CoreData.h&gt;</span>&#x000A;    &#x000A;    <span class="cp">#import &quot;AddTwitterAccountOperation.h&quot;</span>&#x000A;    <span class="cp">#import &quot;MUAccount.h&quot;</span>&#x000A;    <span class="cp">#import &quot;AccountType.h&quot;</span>&#x000A;    <span class="cp">#import &quot;MeechuAppDelegate.h&quot;</span>&#x000A;    &#x000A;    &#x000A;    <span class="k">@implementation</span> <span class="nc">AddTwitterAccountOperation</span>&#x000A;    &#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">main</span> <span class="p">{</span>&#x000A;      <span class="n">MeechuAppDelegate</span> <span class="o">*</span><span class="n">meechu</span> <span class="o">=</span> <span class="p">(</span><span class="n">MeechuAppDelegate</span> <span class="o">*</span><span class="p">)[[</span><span class="n">UIApplication</span> <span class="n">sharedApplication</span><span class="p">]</span> <span class="n">delegate</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">NSPersistentStoreCoordinator</span> <span class="o">*</span><span class="n">coordinator</span> <span class="o">=</span> <span class="p">[</span><span class="n">meechu</span> <span class="n">persistentStoreCoordinator</span><span class="p">];</span>&#x000A;      <span class="n">NSManagedObjectContext</span> <span class="o">*</span><span class="n">moc</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSManagedObjectContext</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">moc</span> <span class="nl">setPersistentStoreCoordinator:</span><span class="n">coordinator</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">MUAccount</span> <span class="o">*</span><span class="n">newAccount</span> <span class="o">=</span> <span class="p">[</span><span class="n">MUAccount</span> <span class="nl">insertInManagedObjectContext:</span><span class="n">moc</span><span class="p">];</span>&#x000A;      <span class="n">newAccount</span><span class="p">.</span><span class="n">identifier</span> <span class="o">=</span> <span class="s">@&quot;alexvollmer&quot;</span><span class="p">;</span>&#x000A;      <span class="n">newAccount</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="s">@&quot;twitter&quot;</span><span class="p">;</span>&#x000A;      <span class="n">newAccount</span><span class="p">.</span><span class="n">password</span> <span class="o">=</span> <span class="s">@&quot;supersekret&quot;</span><span class="p">;</span>&#x000A;      <span class="n">newAccount</span><span class="p">.</span><span class="n">enabled</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSNumber</span> <span class="nl">numberWithBool:</span><span class="n">YES</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">NSError</span> <span class="o">*</span><span class="n">error</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>&#x000A;      <span class="k">if</span> <span class="p">([</span><span class="n">moc</span> <span class="nl">save:</span><span class="o">&amp;</span><span class="n">error</span><span class="p">])</span> <span class="p">{</span>&#x000A;        <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Added twitter account for &#39;alexvollmer&#39;&quot;</span><span class="p">);</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">else</span> <span class="p">{</span>&#x000A;        <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;ERROR: Unable to create test twitter account: %@&quot;</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>&#x000A;      <span class="p">}</span>&#x000A;       &#x000A;      <span class="p">[</span><span class="n">moc</span> <span class="n">release</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="k">@end</span>&#x000A;    </pre>
            </div>
            
            
            <p>Once I've built up a library of these setup actions, I create a different
            build configuration for each combination of setup actions. Each of those
            configurations uses a specific application plist file with the
            <code>MUTestHarnessOperations</code> key set to an array with the appropriate setup
            class names.</p>
            
            <p><img src="/images/2010/07/plist.png"/></p>
            
            
            <p>To create a new build configuration, I just duplicate the existing debug and
            modify two settings: the name of the application plist file, and defining the
            <code>MEECHU_RESET_FOR_TESTING</code> symbol for the preprocessor.</p>
            
            <p><img src="/images/2010/07/plist-configuration.png"></img></p>
            
            
            
            
            <p><img src="/images/2010/07/cflags-configuration.png"></img></p>
            
            
            <p>If I build and run a configuration of the application with a particular
            collection of setup actions, that application will <em>always</em> run with those
            setup actions. This is exactly what you need for repeatable testing.</p>
            
            <p>Now it's simply a matter of choosing the correct application build and test
            script in Instruments:</p>
            
            <p><img src="/images/2010/07/select-app.png"></img></p>
            
            
            <p>You can save your Instruments files off to capture the combination of the test
            script and executable. One thing to keep in mind is that Instruments won't
            build your code. If you have a failing test and you're making fixes, you
            need to re-build the executable in Xcode then re-run the test in Instruments.
            You don't need to reconfigure Instruments, it will just use whatever version
            of the executable you have at the specified path.</p>
            
            <h1>Conclusion</h1>
            
            <p>OK, this works, but I think it's pretty hacky. There are still way too many
            steps to go through and interface points that need to be configured correctly.
            I'm sure there's a more elegant, less error-prone way to do this. If you think
            of it, please tell me. I'm only 50% satisfied with this.</p>
            
            <p>There's a lot I really like about UI Automation, but it is missing a few key
            ingredients that make me think long and hard about using it long-term. This
            test setup approach is somewhat workable. Now we just need to address the
            remaining issues of scriptability and complete automation.</p>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Working with UIAutomation</title>
      <link>
        http://alexvollmer.com/posts/2010/07/03/working-with-uiautomation/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/07/03/working-with-uiautomation/#comments
      </comments>
      <pubDate>
        Sat, 03 Jul 2010 08:55:23 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <category>
        <![CDATA[
            uiautomation
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/07/03/working-with-uiautomation/
      </guid>
      <description>
        <![CDATA[
            In this post we're going to look at the UI Automation library/tool that Apple
            added to iOS SDK 4.0. This is a huge step forward for test automation on the
            iOS platform. While it's not without some compromises, it's worth looking at
            to see if you can reduce the time you spend on manual testing.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>In this post we're going to look at the UI Automation library/tool that Apple
            added to iOS SDK 4.0. This is a huge step forward for test automation on the
            iOS platform. While it's not without some compromises, it's worth looking at
            to see if you can reduce the time you spend on manual testing.</p>
            
            <p>UI Automation is both a probe for Instruments as well as a JavaScript library
            provided by Apple to exercise and validate a running application. In this case,
            "running application" isn't restricted to the simulator&mdash;you can also
            automate the application on a real device. To my knowledge, this is the first
            time I've heard of anyone being able to do this.</p>
            
            <p>This is huge. Having the ability to automate workflows in your application
            yields two benefits: you cut down on manual testing which saves you time,
            <em>and</em> you can rely less on your memory to execute all your tests. Instead, you
            just push a button (okay, two or three buttons) and run your full regression
            suite. Have I piqued your interest yet?</p>
            
            <h1>Preparing Your Application</h1>
            
            <p>First, you need to do a little groundwork to prepare your application to work
            with the automation tool. The UI Automation library relies on accessibility
            information in your UI, so adding a little accessibility info to your UI will
            make testing it easier<sup><a href="#note1">1</a></sup>. More specifically,
            the UI Automation framework looks for the <code>accessibilityLabel</code> property of
            your <code>UIViews</code>. If you've built any web applications, this is somewhat akin to
            sprinkling <code>id</code> attributes in your HTML markup so that you can find particular
            DOM nodes easily with JavaScript.</p>
            
            <p><img src="/images/2010/07/ib-accessibility.jpg" class="right, break"/></p>
            
            <p>For views constructed in Interface Builder, you can set this property in the
            Inspector in the "View Identity" tab (the fourth one). Note that not every
            kind of view provides accessibility configuration in Interface Builder
            <sup><a href="#note2">2</a></sup>. You need to enable Accessibility and you
            need to provide a Label value. You'll use these later in your tests to
            identify particular views.</p>
            
            <p>If you aren't using IB or your view doesn't expose accessibility information
            graphically, you can still set it manually in your code. You can set the
            <code>isAccessibilityElement</code> and <code>accessibilityLabel</code> properties to get the same
            effect:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="n">UITableViewCell</span> <span class="o">*</span><span class="p">)</span><span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">cellForRowAtIndexPath:</span><span class="p">(</span><span class="n">NSIndexPath</span> <span class="o">*</span><span class="p">)</span><span class="n">indexPath</span> <span class="p">{</span>&#x000A;      <span class="k">static</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">CellIdentifier</span> <span class="o">=</span> <span class="s">@&quot;Cell&quot;</span><span class="p">;</span>&#x000A;      &#x000A;      <span class="n">UITableViewCell</span> <span class="o">*</span><span class="n">cell</span> <span class="o">=</span> <span class="p">[</span><span class="n">tableView</span> <span class="nl">dequeueReusableCellWithIdentifier:</span><span class="n">CellIdentifier</span><span class="p">];</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="n">cell</span> <span class="o">==</span> <span class="nb">nil</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="n">cell</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">UITableViewCell</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithStyle:</span><span class="n">UITableViewCellStyleDefault</span> <span class="nl">reuseIdentifier:</span><span class="n">CellIdentifier</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;      &#x000A;      <span class="c1">// cell configuration elided</span>&#x000A;      &#x000A;      <span class="n">cell</span><span class="p">.</span><span class="n">isAccessibilityElement</span> <span class="o">=</span> <span class="n">YES</span><span class="p">;</span>&#x000A;      <span class="n">cell</span><span class="p">.</span><span class="n">accessibilityLabel</span> <span class="o">=</span> <span class="s">@&quot;user name&quot;</span>&#x000A;      <span class="k">return</span> <span class="n">cell</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <h1>Writing Your Tests</h1>
            
            <p>The next step is to write your first test in JavaScript<sup><a href="#note3">3</a></sup>
            in your editor of choice. This step is a bit like being dropped off in a field
            somewhere with no map, tools or supplies and being told you need to build a
            house. There's no built-in structure for your tests. When you execute a test
            script, Instruments will run it from beginning to end in linear fashion.</p>
            
            <p>To get started you need to get a reference to the running application from
            which you can access all the other parts of the app. Put these two lines of
            boilerplate at the top of your test:</p>
            
            <div class="highlight"><pre><span class="nx">target</span> <span class="o">=</span> <span class="nx">UIATarget</span><span class="p">.</span><span class="nx">localTarget</span><span class="p">();</span>&#x000A;    <span class="nx">application</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">frontMostApp</span><span class="p">();</span>&#x000A;    </pre>
            </div>
            
            
            <p>The <code>UIATarget</code> is your primary portal into the application running on the
            device or simulator. It acts as a sort of proxy for the user of the
            application and is the object you interact with when you want to perform
            operations on the device such as fiddling with volume controls, shaking, or
            performing user gestures. The application object (a <code>UIAApplication</code>
            instance), gives you access to the top-level structure of your application for
            things like the navigation bar, tab bars, and the main window.</p>
            
            <p>The <code>UIAApplication</code> class has a <code>mainWindow()</code> method that returns a
            <code>UIAWindow</code> instance. This class is an extension of <code>UIAElement</code> which nearly
            all of the other UI-related classes derive from. This class provides access
            to things like the parent view, child views, links, pickers, sliders, table
            views and nearly anything else you can imagine.</p>
            
            <p>While Apple didn't provide much high-level information about UI Automation in
            the form of a Programming Guide, the UI Automation Reference Guide is worth
            bookmarking or keeping handy in PDF format. This is an essential reference
            that describes the JavaScript API in great detail. Check the Xcode
            documentation.</p>
            
            <p>So let's look at a real example <sup><a href="#note4">4</a></sup>.
            Let's say we have an application connects
            to a variety of popular web sites. When the user launches the app for the
            first time, we want to detect that they don't have any accounts configured
            and prompt them to create one. Our screen might look something like this:</p>
            
            <p><img src="/images/2010/07/account-types.png" alt="Choose an account type" /></p>
            
            <p>We want to verify that when we launch the application we see this screen. Once
            we've verified this, we want to create a twitter account, so we'll select the
            "twitter" table cell. Here's the test script so far:</p>
            
            <div class="highlight"><pre><span class="nx">test</span><span class="p">(</span><span class="s2">&quot;Initial screen&quot;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">app</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="c1">// check navigation bar</span>&#x000A;      <span class="nx">navBar</span> <span class="o">=</span> <span class="nx">mainWindow</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">();</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Add Account&quot;</span><span class="p">,</span> <span class="nx">navBar</span><span class="p">.</span><span class="nx">name</span><span class="p">());</span>&#x000A;      <span class="nx">button</span> <span class="o">=</span> <span class="nx">navBar</span><span class="p">.</span><span class="nx">leftButton</span><span class="p">();</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Back&quot;</span><span class="p">,</span> <span class="nx">button</span><span class="p">.</span><span class="nx">name</span><span class="p">());</span>&#x000A;    &#x000A;      <span class="c1">// check tables</span>&#x000A;      <span class="nx">table</span> <span class="o">=</span> <span class="nx">mainWindow</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span>&#x000A;      <span class="nx">tableGroup</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">groups</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;What type of account?&quot;</span><span class="p">,</span> <span class="nx">tableGroup</span><span class="p">.</span><span class="nx">name</span><span class="p">());</span>&#x000A;    &#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">length</span><span class="p">);</span>&#x000A;      <span class="p">[</span><span class="s2">&quot;facebook&quot;</span><span class="p">,</span> <span class="s2">&quot;flickr&quot;</span><span class="p">,</span> <span class="s2">&quot;github&quot;</span><span class="p">,</span> <span class="s2">&quot;twitter&quot;</span><span class="p">].</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="nx">e</span><span class="p">));</span>&#x000A;      <span class="p">});</span>&#x000A;      &#x000A;      <span class="c1">// more to come...</span>&#x000A;    <span class="p">});</span>&#x000A;    </pre>
            </div>
            
            
            <p>The <code>test</code>, <code>assertNotNull</code> and <code>assertEquals</code> functions are ones I wrote to
            add some structure and high-level validation to the testing process. I found
            the way the UI Automation suite does test case declaration to be really
            verbose and crude so I boiled test declaration into something simpler. First,
            the <code>test()</code> method takes a string title and a function to execute as the
            body:</p>
            
            <div class="highlight"><pre><span class="kd">function</span> <span class="nx">test</span><span class="p">(</span><span class="nx">title</span><span class="p">,</span> <span class="nx">f</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="nx">options</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>&#x000A;          <span class="nx">logTree</span><span class="o">:</span> <span class="kc">true</span>&#x000A;        <span class="p">};</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="nx">target</span> <span class="o">=</span> <span class="nx">UIATarget</span><span class="p">.</span><span class="nx">localTarget</span><span class="p">();</span>&#x000A;      <span class="nx">application</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">frontMostApp</span><span class="p">();</span>&#x000A;      <span class="nx">UIALogger</span><span class="p">.</span><span class="nx">logStart</span><span class="p">(</span><span class="nx">title</span><span class="p">);</span>&#x000A;      <span class="k">try</span> <span class="p">{</span>&#x000A;        <span class="nx">f</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">application</span><span class="p">);</span>&#x000A;        <span class="nx">UIALogger</span><span class="p">.</span><span class="nx">logPass</span><span class="p">(</span><span class="nx">title</span><span class="p">);</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="nx">UIALogger</span><span class="p">.</span><span class="nx">logError</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">logTree</span><span class="p">)</span> <span class="nx">target</span><span class="p">.</span><span class="nx">logElementTree</span><span class="p">();</span>&#x000A;        <span class="nx">UIALogger</span><span class="p">.</span><span class="nx">logFail</span><span class="p">(</span><span class="nx">title</span><span class="p">);</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">};</span>&#x000A;    </pre>
            </div>
            
            
            <p>This handles the boilerplate of getting the target and application references.
            It also provides some structure around <code>UIALogger.logStart()</code>,
            <code>UIALogger.logPass()</code> and <code>UIALogger.logFail()</code>. These three methods are how
            the UI Automation framework demarcates tests. However I found that using <code>if</code>
            checks and calling <code>logFail()</code> really muddied the tests, so I wrote some
            assertion methods that throw exceptions and the test structure automatically
            catches them and logs the test as a failure.</p>
            
            <p>Here are the assertion methods:</p>
            
            <div class="highlight"><pre><span class="kd">function</span> <span class="nx">assertEquals</span><span class="p">(</span><span class="nx">expected</span><span class="p">,</span> <span class="nx">received</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="nx">received</span> <span class="o">!=</span> <span class="nx">expected</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nx">message</span><span class="p">)</span> <span class="nx">message</span> <span class="o">=</span> <span class="s2">&quot;Expected &quot;</span> <span class="o">+</span> <span class="nx">expected</span> <span class="o">+</span> <span class="s2">&quot; but received &quot;</span> <span class="o">+</span> <span class="nx">received</span><span class="p">;</span>&#x000A;        <span class="k">throw</span> <span class="nx">message</span><span class="p">;</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="kd">function</span> <span class="nx">assertTrue</span><span class="p">(</span><span class="nx">expression</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nx">expression</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="nx">message</span><span class="p">)</span> <span class="nx">message</span> <span class="o">=</span> <span class="s2">&quot;Assertion failed&quot;</span><span class="p">;</span>&#x000A;        <span class="k">throw</span> <span class="nx">message</span><span class="p">;</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="kd">function</span> <span class="nx">assertFalse</span><span class="p">(</span><span class="nx">expression</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="nx">assertTrue</span><span class="p">(</span><span class="o">!</span> <span class="nx">expression</span><span class="p">,</span> <span class="nx">message</span><span class="p">);</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="kd">function</span> <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">thingie</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="nx">thingie</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="nx">thingie</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;[object UIAElementNil]&quot;</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="k">if</span> <span class="p">(</span><span class="nx">message</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="nx">message</span> <span class="o">=</span> <span class="s2">&quot;Expected not null object&quot;</span><span class="p">;</span>&#x000A;        <span class="k">throw</span> <span class="nx">message</span><span class="p">;</span>&#x000A;      <span class="p">}</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>Whew. Still with me? OK, back to our test. Next we want to fill out the text
            fields in the next view with our twitter credentials:</p>
            
            <p><img src="/images/2010/07/twitter-creds.png" alt="Enter twitter credentials" /></p>
            
            <p>We extend the test code above with the next set of stimuli and assertions:</p>
            
            <div class="highlight"><pre>  <span class="c1">// create a new account</span>&#x000A;      <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;twitter&quot;</span><span class="p">).</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      <span class="nx">mainWindow</span> <span class="o">=</span> <span class="nx">app</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">();</span>&#x000A;      <span class="nx">table</span> <span class="o">=</span> <span class="nx">mainWindow</span><span class="p">.</span><span class="nx">tableViews</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span>&#x000A;    &#x000A;      <span class="nx">userName</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;user name&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">userName</span><span class="p">,</span> <span class="s2">&quot;No username field found&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">userName</span><span class="p">.</span><span class="nx">textFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;mrfoobar&quot;</span><span class="p">);</span>&#x000A;    &#x000A;      <span class="nx">password</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;password&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">password</span><span class="p">,</span> <span class="s2">&quot;No password field found&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">password</span><span class="p">.</span><span class="nx">secureTextFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">&quot;No text field found for password&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">password</span><span class="p">.</span><span class="nx">secureTextFields</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">setValue</span><span class="p">(</span><span class="s2">&quot;sekret&quot;</span><span class="p">);</span>&#x000A;      &#x000A;      <span class="nx">finish</span> <span class="o">=</span> <span class="nx">table</span><span class="p">.</span><span class="nx">cells</span><span class="p">().</span><span class="nx">firstWithName</span><span class="p">(</span><span class="s2">&quot;finish&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">assertNotNull</span><span class="p">(</span><span class="nx">finish</span><span class="p">,</span> <span class="s2">&quot;No finish button found&quot;</span><span class="p">);</span>&#x000A;      <span class="nx">finish</span><span class="p">.</span><span class="nx">tap</span><span class="p">();</span>&#x000A;      &#x000A;      <span class="c1">// more to come...</span>&#x000A;    </pre>
            </div>
            
            
            <p>The first line above finds the "twitter" cell by calling the <code>firstWithName()</code>
            method on the collection of cells in the table view. This table view was
            generated programmatically, so that "twitter" label came from setting the
            cell's <code>isAccessibilityElement</code> property to <code>YES</code> and its <code>accessibilityLabel</code>
            property to <code>@"twitter"</code>. Next we touch that table cell via the <code>tap()</code> method
            to navigate forward in our application.</p>
            
            <p>The next two stanzas validate that we have user name and password fields, and
            also fills them out using the <code>setValue()</code> method. Finally we look for the cell
            that contains the "Finish" button and tap it to finish creating our account.</p>
            
            <p><img src="/images/2010/07/settings-screen.png" alt="Our landing point, the settings screen" /></p>
            
            <p>The last bit of testing to do here is to validate that we did indeed land
            on our settings screen. So we add a few more assertions to our test:</p>
            
            <div class="highlight"><pre>  <span class="c1">// validate settings screen</span>&#x000A;      <span class="nx">finish</span><span class="p">.</span><span class="nx">waitForInvalid</span><span class="p">();</span>&#x000A;      <span class="nx">mainWindow</span> <span class="o">=</span> <span class="nx">app</span><span class="p">.</span><span class="nx">mainWindow</span><span class="p">();</span>&#x000A;      <span class="nx">assertEquals</span><span class="p">(</span><span class="s2">&quot;Settings&quot;</span><span class="p">,</span> <span class="nx">mainWindow</span><span class="p">.</span><span class="nx">navigationBar</span><span class="p">().</span><span class="nx">name</span><span class="p">());</span>&#x000A;    </pre>
            </div>
            
            
            <p>Here I call the <code>waitForInvalid()</code> method on the finish button object. Without
            this, I found that the other code executed too quickly before the window
            transition completed. The <code>waitForInvalid()</code> will wait (up to a configurable
            timeout value) for that object to be invalidated. Our last assertion is that
            the title in the navigation bar is "Settings".</p>
            
            <h1>Running Your Tests</h1>
            
            <p>Now that we have a test, we need to run it in Instruments. When you launch
            Instruments, choose "Automation" from the iPhone templates.</p>
            
            <p><img src="/images/2010/07/choose-automation.png" alt="Automation template in Instruments" /></p>
            
            <p>In the details for the Automation instrument, choose your script via the
            "Choose Script&hellip;" drop-down. Next, you need to choose your target from
            the toolbar. Once you have these setup, you run the flow by (somewhat
            counter-intuitively) hitting the record button (or using ⌘+R). This will
            launch your application, wait a few seconds and then run your test. Note that
            even if your test completes, Instruments will keep running your application.
            To formally end the test toggle the red record button, or hit ⌘+R again.</p>
            
            <p>Tests are listed in the detail view, with the test name in the "Log Messages"
            column. If your test passes, the "Log Type" value will be "Pass" in comforting
            green. If your test fails, the value is "Fail" in scary red. You can expand
            the test to see the details of what happened. Because of the way I wrote the
            test structure above, any test failures automatically log the view hierarchy
            for inspection.</p>
            
            <p><img src="/images/2010/07/test-failure.png" alt="A test failure" /></p>
            
            <h1>Debugging Your Tests</h1>
            
            <p>When things go wrong with your tests you don't have a lot to look at. However
            there are a few things you can inspect to try to figure out what's broken.
            First, log the element tree (via <code>UIATarget.logElementTree()</code>) liberally and
            often. Although view hierarchy is a tree and it's presented in a tree control,
            it's "flattened-out" out for display purposes. However, the numeric prefix
            listed in each row indicates the level that node is at, so you can infer
            parent-child relationships:</p>
            
            <p><img src="/images/2010/07/tree-hierarchy.png" alt="The tree hierarchy" /></p>
            
            <p>In this case, the tree looks something like this:</p>
            
            <ul>
            <li><code>UIATarget</code>
            
            <ul>
            <li><code>UIAApplication</code>
            
            <ul>
            <li><code>UIAWindow</code>
            
            <ul>
            <li><code>UIATableView</code>
            
            <ul>
            <li><code>UIATableGroup</code>
            
            <ul>
            <li><code>UIAStaticText</code></li>
            </ul>
            </li>
            </ul>
            </li>
            </ul>
            </li>
            </ul>
            </li>
            </ul>
            </li>
            </ul>
            
            
            <p>You don't always have to traverse the entire tree, node-by-node, to find what
            you're looking for. Take a look at the various methods on the <code>UIAElement</code>
            class and experiment a bit.</p>
            
            <p>You can also log any message you choose using any of these log methods on
            the <code>UIALogger</code> class:</p>
            
            <ul>
            <li><code>logDebug()</code></li>
            <li><code>logMessage()</code></li>
            <li><code>logWarning()</code></li>
            <li><code>logError()</code></li>
            </ul>
            
            
            <p>All of these just log messages of varying severity, but don't affect whether
            or not the test is marked as passing or a failure.</p>
            
            <h1>Building on UI Automation</h1>
            
            <p>While Apple may not have provided much support for automation testing beyond
            a JavaScript API and a reference doc, they (wisely) left the whole mechanism
            open to easy extension. You can import other JavaScript into your tests with
            the <code>#import</code> statement. I'm not 100% sure how smart that statement is
            with regard to paths, but I found that if you put supporting scripts in the
            same directory as the test script you're executing, Instruments will
            automatically pick it up.</p>
            
            <p>So I took the extensions I mentioned earlier, plus a few more, and put them
            into a small, but growing, JavaScript library I call <a href="http://github.com/alexvollmer/tuneup_js" title="alexvollmer's tuneup_js at master - GitHub">tuneup_js</a>.</p>
            
            <p>You can simply copy all of the JavaScript files into the same directory as
            your automation tests. For my project, I created a separate directory called
            "Automation Tests" and dumped everything in there. This is pretty crude and
            I'd like to improve it, but I need to spend some more time figuring out the
            nuances of how Instruments handles paths in <code>#import</code> statements.</p>
            
            <p>Please check it out, file bugs, send patches and/or your feedback.</p>
            
            <h1>Stepping Back</h1>
            
            <p>These kind of tests are high-level, flow-oriented tests that exercise entire
            scenarios. As much as possible, these run against a "real" system though,
            at times, you may swap out external dependencies with mocked ones in order
            to control the test environment and execution.</p>
            
            <p>There have been other third-party open-source projects that have addressed the
            lack of good automation testing. In particular
            <a href="http://github.com/unboxed/icuke" title="unboxed's icuke at master - GitHub">iCuke</a>
            and <a href="http://code.google.com/p/uispec/" title="uispec - Project Hosting on
            Google Code">UISpec</a> both have a lot going for them. If you like
            <a href="http://cukes.info/" title="Cucumber - Making BDD fun">Cucumber</a>, iCuke is nice for
            writing integration tests. It's pretty impressive what they've been able to
            accomplish on their own. Personally I prefer the Cucumber approach to
            integration tests. However, because iCuke uses a small embedded web server and
            XML to exercise and validate the UI, I found that I often ran into time-out
            issues and got frustrated wrestling with XPath expressions to validate my UI.</p>
            
            <p>What iCuke has going for it, and what Instruments can't do, is the fact that
            you can automate the entire process. As far as I can tell, there isn't a good
            way to automate getting Instruments to run your automation tests. I hope this
            is something that either Apple addresses, or somebody figures out a clever
            hack for.</p>
            
            <p><img src="/images/2010/07/robholland-twitter.png" alt="iCuke responds" /></p>
            
            <p>I like the way the Apple library is connected to the running application. It
            definitely feels "first-class" compared to iCuke's implementation
            <sup><a href="#note5">5</a></sup>. Let's hope that we can bring the two
            approaches together to have one fantastic automation tool.</p>
            
            <p>One thing that <strike>none of these tools</strike> UI Automation can't really help you with
            is building reliable, repeatable test harnesses. One of the hardest parts of
            making good integration tests is setting up application state to test various
            modes of your application. This is one of the reasons why xUnit-style tests
            don't work well for automation. Too often people write fine-grained tests that
            have an implicit order, each test relying on the side-effects of the previous
            one. This makes your tests highly-coupled and extremely brittle.</p>
            
            <p>In my application I have a couple of initial application states to test. None
            of these tools provides much help for that. For now, I've chosen to sprinkle
            a few <code>#ifdefs</code> around in my app delegate to setup the application in a
            known state. Then I use different build configurations to build separate
            binaries, each with a different known initial state. There's no doubt that
            it's a bit Rube Goldberg-esque, but it's a start.</p>
            
            <p>There is a growing list of options available out there for writing automated
            integration tests for your iPhone apps. Apple's UI Automation tool is just
            one of them. It has it's pros and cons, but it's a big step forward in the
            right direction. Now it's up to us to figure out how to build upon them,
            develop extensions and idioms around them and, ultimately, build better
            apps.</p>
            
            <h1>Resources</h1>
            
            <p>As I stated earlier, there isn't much out there in the way of documentation,
            but here are a couple things to look at:</p>
            
            <ul>
            <li><a href="http://developer.apple.com/iphone/library/documentation/DeveloperTools/Reference/UIAutomationRef/Introduction/Introduction.html" title="UI Automation Reference Collection">UI Automation Reference Collection</a></li>
            <li><a href="http://answers.oreilly.com/topic/1646-how-to-use-uiautomation-to-create-iphone-ui-tests/" title="How to use UIAutomation to create iPhone UI tests - O'Reilly Answers">O'Reilly Answers Post on UI Automation</a></li>
            </ul>
            
            
            <h1 id="footnotes">Footnotes</h1>
            
            
            <ol>
              <li>
                <a name="note1"></a>
                I don't know if this was a ploy to get developers to be more mindful
                of disabled users or not, but the net-result is a win for everyone. You 
                get better test automation and disabled users get better apps.
              </li>
              <li>
                <a name="note2"></a>
                I haven't spent the time to figure out which ones do and don't so perhaps 
                there's some kind of rhyme and reason to this.
              </li>
              <li>
                <a name="note3"></a>
                I have to admit that I was surprised to see JavaScript as the language
                of choice given Apple's support of the <a href="http://www.macruby.org/" title="MacRuby &raquo; Home">MacRuby</a> 
                project. JavaScript has had to weather a lot of bad press over the 
                years. It's a language that has a lot of quirks but, once you separate 
                it from the vagaries of various browser implementations, you'll find that
                it's a pretty flexible and expressive language.
              </li>
              <li>
                <a name="note4"></a>
                This comes from a real app that I've been working on. You can't beat
                learning new things from a real project.
              </li>
              <li>
                <a name="note5"></a>
                No disrespect meant for the iCuke team. Honestly, they've done an 
                awesome job, I can't wait to see where they go next. Definitely keep
                your eye on this project.
              </li>
            </ol>
        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Making Fun of Things with OCMock</title>
      <link>
        http://alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/
      </link>
      <comments>
        http://alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/#comments
      </comments>
      <pubDate>
        Mon, 28 Jun 2010 09:35:27 PDT
      </pubDate>
      <dc:creator>
        alex
      </dc:creator>
      <category>
        <![CDATA[
            cocoa
        ]]>
      </category>
      <category>
        <![CDATA[
            TDD
        ]]>
      </category>
      <guid isPermaLink='false'>
        http://alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/
      </guid>
      <description>
        <![CDATA[
            OK, I've done <a href="http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/" title="Alex Vollmer &mdash; Cocoa's Broken Tests">plenty of ranting about the state of TDD in Cocoa development</a>.
            So instead of inflicting more
            whining on your ears, I've decided to figure out how to get better at this.
            This is the first in a series of posts I'll be doing about testing in Cocoa.
            We're going to look at OCMock, a framework for creating and
            using mock objects in your Cocoa tests.
        ]]>
      </description>
      <content:encoded>
        <![CDATA[
            <p>OK, I've done <a href="http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/" title="Alex Vollmer &mdash; Cocoa's Broken Tests">plenty of ranting about the state of TDD in Cocoa development</a>.
            So instead of inflicting more
            whining on your ears, I've decided to figure out how to get better at this.
            This is the first in a series of posts I'll be doing about testing in Cocoa.
            We're going to look at OCMock, a framework for creating and
            using mock objects in your Cocoa tests.</p>
            
            <p>This isn't the only tutorial out there on OCMock, but hopefully it's the
            clearest. I found the documentation on the site to be a bit, ahem, lacking. As
            a result I ended up figuring out how to use it by going through the source
            code<sup><a href="#note1">1</a></sup>.</p>
            
            <h1>Installation</h1>
            
            <p>First, you need to download the <a href="http://www.mulle-kybernetik.com/software/OCMock/" title="Mulle kybernetiK -- OCMock">OCMock project</a>.
            Before Xcode 3.2.3, you used to be able to simply add the <code>OCMock.framework</code>
            to the "Link Binary With Libraries" build phase of your unit tests. This
            <a href="http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&amp;t=73" title="Mulle kybernetiK &bull; Information">appears to have stopped working</a>,
            so you have two options: you can include the OCMock source Xcode project
            and declare a build dependency on its static library target, or you can build
            the static library once and put the following header files somewhere accessible
            to your Xcode build:</p>
            
            <ul>
            <li><code>NSNotificationCenter+OCMAdditions.h</code></li>
            <li><code>OCMArg.h</code></li>
            <li><code>OCMConstraint.h</code></li>
            <li><code>OCMock.h</code></li>
            <li><code>OCMockObject.h</code></li>
            <li><code>OCMockRecorder.h</code></li>
            </ul>
            
            
            <p>I didn't want to rebuild the library over and over so I built the static
            library once and put the <code>libOCMock.a</code> and <code>OCMock.h</code> files in a directory
            in my project and added that directory to the <code>LIBRARY_SEARCH_PATHS</code> in the
            unit-test target configuration <sup><a href="#note2">2</a></sup>.</p>
            
            <h1>Underlying Concepts</h1>
            
            <p>I'm assuming that you already know what <a href="http://en.wikipedia.org/wiki/Mock_object" title="Mock object - Wikipedia,
            the free encyclopedia">mock
            objects</a> are and how to use them. I'm not going to explain
            their value here, or the design changes you end up making to accommodate them.
            Mock objects are simply one of many tools you can employ in your testing. They
            have their pros and cons so let experience and intuition be your guide.
            Instead, I want to focus on how to use OCMock.</p>
            
            <p>The general recipe for using mocks in unit-tests is:</p>
            
            <ol>
            <li>Create the mock object</li>
            <li>Specify the expected invocations and return values</li>
            <li>Associate the mock object with the code under test</li>
            <li>Execute the code under test</li>
            <li>Validate that your assertions are correct</li>
            </ol>
            
            
            <p>It's worth spending some time looking at the test cases that come with the
            OCMock source code. The coverage is quite good so it's a great demonstration
            of OCMock's capabilities.</p>
            
            <h2>Making Mocks</h2>
            
            <p>To create a mock object, use one of the factory methods available on the
            <code>OCMockObject</code> class: <code>+mockForClass:</code>, <code>+mockForProtocol:</code> or
            <code>+partialMockForObject:</code>. There are also two variants of this called "nice"
            mocks, which you can get by calling either <code>+niceMockForClass:</code> or
            <code>+niceMockForProtocol:</code>. The difference between a "nice" mock and regular
            (mean? stand-offish?) mock, is how they behave when they receive an unexpected
            method invocation. A "nice" mock will simply ignore the unexpected invocation,
            whereas a regular mock will raise a <code>NSException</code>.</p>
            
            <table>
            <thead>
            <tr>
            <th>Factory Method           </th>
            <th> Description                                        </th>
            </tr>
            </thead>
            <tbody>
            <tr>
            <td><code>+mockForClass:</code>         </td>
            <td> Create a mock based on the given class             </td>
            </tr>
            <tr>
            <td><code>+mockForProtocol:</code>      </td>
            <td> Create a mock based on the given protocol          </td>
            </tr>
            <tr>
            <td><code>+niceMockForClass:</code>     </td>
            <td> Create a "nice" mock based on the given class      </td>
            </tr>
            <tr>
            <td><code>+niceMockForProtocol:</code>  </td>
            <td> Create a "nice" mock based on the given protocol   </td>
            </tr>
            <tr>
            <td><code>+partialMockForObject:</code> </td>
            <td> Create a mock based on the given <em>object</em>          </td>
            </tr>
            <tr>
            <td><code>+observerMock:</code>         </td>
            <td> Create a notification observer (more on this later)</td>
            </tr>
            </tbody>
            </table>
            
            
            <p>If you're like me and you like to keep your builds free of compiler warnings,
            declare the returned object to be of type <code>id</code> to shut the compiler up.</p>
            
            <div class="highlight"><pre><span class="kt">id</span> <span class="n">myMock</span> <span class="o">=</span> <span class="p">[</span><span class="n">OCMockObject</span> <span class="nl">mockForClass:</span><span class="p">[</span><span class="n">MyClass</span> <span class="n">class</span><span class="p">]];</span>&#x000A;    </pre>
            </div>
            
            
            <p>The <code>+partialMockForObject:</code> method allows you to turn an existing object into
            a mock. This can be useful in cases where a collaborating object has several
            of its methods invoked, but you only want to override one or two. The obvious
            dangers here are that, 1) your collaborating class probably violates the
            <a href="http://en.wikipedia.org/wiki/Single_responsibility_principle" title="Single responsibility principle - Wikipedia, the free encyclopedia">Single-Responsibility
            Principle</a> and 2)
            your tests now indirectly rely on the subtleties of which methods you mocked
            and which you didn't. Use at your own peril.</p>
            
            <h2>Setting Expectations</h2>
            
            <p>The object returned by any of these factory methods allows you to both
            setup expectations, invoke methods and verify its configuration. OCMock does
            a clever little trick to distinguish between invocation configuration and
            handling method invocations. Calling either the <code>-expect</code> or <code>-stub</code> method
            will return an object that you can use to setup your expectations. The cool
            thing about this object is that you setup your expectations by (more or less)
            invoking the methods on it that you want your class under test to invoke.</p>
            
            <p>Let's imagine that we have a simple stock-portfolio management application.
            Our portfolio model is encapsulated by the <code>AVStockPortfolio</code> class. An
            instance of that class is given an object that implements the <code>AVQuoteService</code>
            protocol, which is our gateway to a real-live stock quote service. When we
            test the <code>AVStockPortfolio</code> class, we don't want to be encumbered with a
            "production" implementation of <code>AVQuoteService</code>. Instead we want to craft
            a stand-in object to exercise and validate the portfolio class.</p>
            
            <p>Our first test is to see that the portfolio class initiates a connection
            with the quote service in its <code>init</code> method:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">testInit</span> <span class="p">{</span>&#x000A;      <span class="kt">id</span> <span class="n">mockService</span> <span class="o">=</span> <span class="p">[</span><span class="n">OCMockObject</span> <span class="nl">mockForProtocol:</span><span class="err">@</span><span class="n">protocol</span><span class="p">(</span><span class="n">AVQuoteService</span><span class="p">)];</span>&#x000A;      <span class="p">[[</span><span class="n">mockService</span> <span class="n">expect</span><span class="p">]</span> <span class="n">initiateConnection</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">AVStockPortfolio</span> <span class="o">*</span><span class="n">portfolio</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVStockPortfolio</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithService:</span><span class="n">mockService</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="p">[</span><span class="n">mockService</span> <span class="n">verify</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>When the <code>-expect</code> method is called, it returns a <a href="http://www.cocoadev.com/index.pl?TrampolineObject" title="CocoaDev: TrampolineObject">"trampoline" object</a>
            that captures additional method calls dynamically. Any methods invoked on
            the service that I haven't explicitly configured will raise an exception. I
            can also check that the methods I've configured were all invoked by calling
            the mock object's <code>-verify</code> method.</p>
            
            <p>You can also configure your mock object to act as a more forgiving "stub" for
            particular methods by using <code>-stub</code> instead of <code>-expect</code>
            <a href="#note3"><sup>3</sup></a>. Admittedly, the ability to turn a so-called
            "mock" object into a "stub" for particular method invocations muddies the
            nomenclature a bit, but it can be handy to have this ability at times.</p>
            
            <h3>Return Values</h3>
            
            <p>If methods on your mocks need to return values, you have a variety of methods
            to call on the object returned by <code>-expect</code> or <code>-stub</code>. Any method we call on
            this object that isn't one of the built-in OCMock methods, is captured
            dynamically as an expected method invocation.</p>
            
            <table>
            <thead>
            <tr>
            <th>Method               </th>
            <th> Explanation                                        </th>
            </tr>
            </thead>
            <tbody>
            <tr>
            <td><code>-andReturn:</code>        </td>
            <td> Return the given object                            </td>
            </tr>
            <tr>
            <td><code>-andReturnValue:</code>   </td>
            <td> Return a non-object value (wrapped in a <code>NSValue</code>) </td>
            </tr>
            <tr>
            <td><code>-andThrow:</code>         </td>
            <td> Throw the given exception                          </td>
            </tr>
            <tr>
            <td><code>-andPost:</code>          </td>
            <td> Post the given notification                        </td>
            </tr>
            <tr>
            <td><code>-andCall:onObject:</code> </td>
            <td> Call the selector on the given object              </td>
            </tr>
            <tr>
            <td><code>-andDo:</code>            </td>
            <td> Invoke the given block (only on OS X 10.6 or iOS 4)</td>
            </tr>
            </tbody>
            </table>
            
            
            <p>Since each of these methods returns the same expectation object, you can
            chain these method calls, where it makes sense. For example to post a
            notification <em>and</em> return a specified value we could do this:</p>
            
            <div class="highlight"><pre><span class="n">NSNotification</span> <span class="o">*</span><span class="n">notfication</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSNotification</span> <span class="nl">notificationWithName:</span><span class="s">@&quot;foo&quot;</span> <span class="nl">object:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;    <span class="p">[[[</span><span class="n">mock</span> <span class="n">expect</span><span class="p">]</span> <span class="nl">andPost:</span><span class="n">notfication</span><span class="p">]</span> <span class="nl">andReturn:</span><span class="s">@&quot;FOOBAR&quot;</span><span class="p">]</span> <span class="n">doSomethingMagical</span><span class="p">];</span>&#x000A;    </pre>
            </div>
            
            
            <p>The <code>-andDo:</code> option is one of my favorites since it uses blocks and blocks
            are the most awesome addition to Objective-C in a long time. You can do a lot
            of validation locally within a block which keeps the code very succinct and
            clean:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">testSellSharesInStock</span> <span class="p">{</span>&#x000A;      <span class="kt">id</span> <span class="n">quoteService</span> <span class="o">=</span> <span class="p">[[</span><span class="n">OCMockObject</span><span class="p">]</span> <span class="nl">mockForProtocol:</span><span class="err">@</span><span class="n">protocol</span><span class="p">(</span><span class="n">AVQuoteService</span><span class="p">)];</span>&#x000A;      <span class="p">[[[</span><span class="n">quoteService</span> <span class="n">expect</span><span class="p">]</span> <span class="nl">andDo:</span><span class="o">^</span><span class="p">(</span><span class="n">NSInvocation</span> <span class="o">*</span><span class="n">invocation</span><span class="p">)</span> <span class="p">{</span>&#x000A;        <span class="c1">// validate arguments, set return value on the invocation object</span>&#x000A;      <span class="p">}]</span> <span class="nl">priceForStock:</span><span class="s">@&quot;AAPL&quot;</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">AVStockPortfolio</span> <span class="o">*</span><span class="n">portfolio</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVStockPortfolio</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithService:</span><span class="n">quoteService</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">portfolio</span> <span class="nl">sellShares:</span><span class="mi">100</span> <span class="nl">inStock:</span><span class="s">@&quot;AAPL&quot;</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="c1">// other validations and assertions</span>&#x000A;      &#x000A;      <span class="p">[</span><span class="n">quoteService</span> <span class="n">verify</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <h3>Arguments &amp; Return Values</h3>
            
            <p>Basic method expectations are useful, but we also want to validate the
            arguments given to methods. Back to our stock portfolio, imagine that when
            we buy a stock, we know that part of that process is to ask for the current
            price of a stock from a stock service, so we want to assert that when we
            sell a particular stock, our portfolio object queries the quote service for
            the latest price for the same stock symbol:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">testBuyShares</span> <span class="p">{</span>&#x000A;      <span class="kt">id</span> <span class="n">mockService</span> <span class="o">=</span> <span class="p">[</span><span class="n">OCMockObject</span> <span class="nl">mockForProtocol:</span><span class="err">@</span><span class="n">protocol</span><span class="p">(</span><span class="n">AVQuoteService</span><span class="p">)];</span>&#x000A;      <span class="p">[[</span><span class="n">mockService</span> <span class="n">expect</span><span class="p">]</span> <span class="nl">andReturn:</span><span class="p">[</span><span class="n">NSNumber</span> <span class="nl">numberWithFloat:</span><span class="mf">214.57</span><span class="p">]]</span> <span class="nl">priceQuoteForSymbol:</span><span class="s">@&quot;AAPL&quot;</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="n">AVPortfolio</span> <span class="o">*</span><span class="n">portfolio</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVPortfolio</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithQuoteService:</span><span class="n">mockService</span><span class="p">];</span>&#x000A;      <span class="p">[</span><span class="n">portfolio</span> <span class="nl">buyShares:</span><span class="mi">100</span> <span class="nl">inStock:</span><span class="s">@&quot;AAPL&quot;</span><span class="p">];</span>&#x000A;      &#x000A;      <span class="c1">// other validation and assertions</span>&#x000A;    &#x000A;      <span class="p">[</span><span class="n">mockService</span> <span class="n">verify</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>In this case, we're declaring the expected argument to be the string
            literal <code>@"AAPL"</code>. We've also configured the method with a return value, in
            this case a <code>NSNumber</code> instance with the value <code>214.57</code>. However, OCMock can
            do more. You can use any of the following <code>OCMArg</code> class methods in place of
            a real argument when setting up your method expectations:</p>
            
            <table>
            <thead>
            <tr>
            <th><code>OCMArg</code> method                </th>
            <th> Description                                                 </th>
            </tr>
            </thead>
            <tbody>
            <tr>
            <td><code>+any</code>                         </td>
            <td> Any argument is accepted.</td>
            </tr>
            <tr>
            <td><code>+anyPointer</code>                  </td>
            <td> Accepts any pointer                                         </td>
            </tr>
            <tr>
            <td><code>+isNil</code>                       </td>
            <td> The given argument <em>must</em> be <code>nil</code>                          </td>
            </tr>
            <tr>
            <td><code>+isNotNil</code>                    </td>
            <td> The given argument must <em>not</em> be <code>nil</code>                      </td>
            </tr>
            <tr>
            <td><code>+isNotEqual:</code>                 </td>
            <td> Given argument is not object-equivalent with expectation    </td>
            </tr>
            <tr>
            <td><code>+checkWithSelector:onObject:</code> </td>
            <td> Check the argument with the given action/target pair        </td>
            </tr>
            <tr>
            <td><code>+checkWithBlock:</code>             </td>
            <td> Check the argument with the given block (OS X 10.6 or iOS 4)</td>
            </tr>
            </tbody>
            </table>
            
            
            <p>OCMock also provides a few handy macros for argument matching:</p>
            
            <table>
            <thead>
            <tr>
            <th>Macro                         </th>
            <th> Description                                                        </th>
            </tr>
            </thead>
            <tbody>
            <tr>
            <td><code>OCMOCK_ANY()</code>                </td>
            <td> Equivalent to <code>[OCMArg any]</code>                                       </td>
            </tr>
            <tr>
            <td><code>OCMOCK_VALUE(value)</code>         </td>
            <td> A quick way to match a non-object argument                         </td>
            </tr>
            <tr>
            <td><code>CONSTRAINT(selector)</code>        </td>
            <td> Validate with a given selector on <code>self</code>                           </td>
            </tr>
            <tr>
            <td><code>CONSTRAINTV(selector,value)</code> </td>
            <td> Validate with a given selector on <code>self</code> and an additional argument</td>
            </tr>
            </tbody>
            </table>
            
            
            <h3>But Wait&hellip;There's More!</h3>
            
            <p>One nice little feature of OCMock is its handy support for testing
            notifications. To create a mock for notifications, call the <code>+observerMock</code>
            factory method on the <code>OCMockObject</code> class. This will return a mock that works
            differently from the mocks/stubs described earlier. Instead of setting up
            method invocation expectations, you can set up notification expectations which
            are useful when you want to assert that your class under test posts
            notifications. Let's say that we want our aforementioned portfolio class to
            post notifications whenever stocks are bought or sold:</p>
            
            <div class="highlight"><pre><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">testSellSharesInStock</span> <span class="p">{</span>&#x000A;      <span class="kt">id</span> <span class="n">mock</span> <span class="o">=</span> <span class="p">[</span><span class="n">OCMockObject</span> <span class="n">observerMock</span><span class="p">];</span>&#x000A;      <span class="c1">// OCMock adds a custom methods to NSNotificationCenter via a category</span>&#x000A;      <span class="p">[[</span><span class="n">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="p">]</span> <span class="nl">addMockObserver:</span><span class="n">mock</span>&#x000A;                                                       <span class="nl">name:</span><span class="n">AVStockSoldNotification</span>&#x000A;                                                     <span class="nl">object:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;                                                   &#x000A;      <span class="p">[[</span><span class="n">mock</span> <span class="n">expect</span><span class="p">]</span> <span class="nl">notificationWithName:</span><span class="n">AVStockSoldNotification</span> <span class="nl">object:</span><span class="p">[</span><span class="n">OCMArg</span> <span class="n">any</span><span class="p">]];</span>&#x000A;    &#x000A;      <span class="n">AVPortfolio</span> <span class="o">*</span><span class="n">portfolio</span> <span class="o">=</span> <span class="p">[</span><span class="n">self</span> <span class="n">createPortfolio</span><span class="p">];</span> <span class="c1">// made-up factory method</span>&#x000A;      <span class="p">[</span><span class="n">portfolio</span> <span class="nl">sellShares:</span><span class="mi">100</span> <span class="nl">inStock:</span><span class="s">@&quot;AAPL&quot;</span><span class="p">];</span>&#x000A;    &#x000A;      <span class="p">[</span><span class="n">mock</span> <span class="n">verify</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    </pre>
            </div>
            
            
            <p>If the <code>AVStockSoldNotification</code> isn't posted by the time we call <code>verify</code>,
            the mock will raise an exception. Note that you need to add the mock as an
            observer, which you can do by the handy <code>-addMockObserver:name:object:</code>
            category method on <code>NSNotificationCenter</code> provided by OCMock.</p>
            
            <h2>Execution &amp; Validation</h2>
            
            <p>Any method invoked on your mock object will be checked against the configured
            invocations. Any unexpected invocations will result in an exception being
            thrown (unless it's a stub or the mock is in "nice" mode). Also, any configured
            invocations that did <em>not</em> happen will trigger an exception when the mock's
            <code>-verify</code> method is called. As a matter of habit, you want to call this at the
            end of your test.</p>
            
            <h1>Conclusion</h1>
            
            <p>Using mocks, stubs and test-doubles in your testing is a handy way to keep
            your tests lean and focused on one class at a time. This is especially
            helpful when you have dependent classes that require a lot of setup that
            you would rather avoid in your test-harness (e.g. Core Data).</p>
            
            <p>The downside to testing with mocks and stubs is that you lose some test
            coverage for the objects you're replacing with test-doubles. This approach
            probably works best when your code is interacting with objects from other
            libraries that you don't want to deal with in your tests.</p>
            
            <h1 id="footnotes">Footnotes</h1>
            
            
            <ol>
              <li>
                <a name="note1"></a>
                I know it seems like a drag, but it's hard to overestimate the value of
                reading the original source code for any tool that you use. You'll be
                amazed at how much more of an intimate understanding it gives you of
                the tool and the rationale behind its design.
              </li>
              <li>
                <a name="note2"></a>
                I forked the OCMock codebase and have started to make a few tweaks to it.
                Feel free to take a look at it on <a href="http://github.com/alexvollmer/OCMock" title="alexvollmer's OCMock at master - GitHub">GitHub</a>.
              </li>
              <li>
                <a name="note3"></a>
                If you aren't familiar with mocks vs. stubs, Martin Fowler has written
                the <a href="http://martinfowler.com/articles/mocksArentStubs.html" title="Mocks Aren't Stubs">canonical text</a> on the differences.
              </li>
            </ol>
        ]]>
      </content:encoded>
    </item>
    <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/2010/06/13/a-tale-of-two-cultures/#comments
      </comments>
      <pubDate>
        Sun, 13 Jun 2010 15:10:14 PDT
      </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/2010/06/01/cocoas-broken-tests/#comments
      </comments>
      <pubDate>
        Tue, 01 Jun 2010 11:20:51 PDT
      </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/2010/05/21/the-international-colors-of-iphoneos/#comments
      </comments>
      <pubDate>
        Fri, 21 May 2010 08:46:32 PDT
      </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/2010/05/07/visual-affordance-in-a-touch-enabled-world/#comments
      </comments>
      <pubDate>
        Fri, 07 May 2010 10:46:39 PDT
      </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></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/2010/04/30/on-technical-presentations/#comments
      </comments>
      <pubDate>
        Fri, 30 Apr 2010 07:51:51 PDT
      </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/2010/04/23/menubar-ghetto/#comments
      </comments>
      <pubDate>
        Fri, 23 Apr 2010 08:49:57 PDT
      </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/2010/04/17/thanks-mom/#comments
      </comments>
      <pubDate>
        Sat, 17 Apr 2010 20:23:21 PDT
      </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/2010/03/06/scripting-build-selection-in-xcode/#comments
      </comments>
      <pubDate>
        Sat, 06 Mar 2010 00:20:30 PST
      </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/2010/02/27/rvm-meets-zsh/#comments
      </comments>
      <pubDate>
        Sat, 27 Feb 2010 17:19:45 PST
      </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/2010/02/22/static-cling/#comments
      </comments>
      <pubDate>
        Mon, 22 Feb 2010 17:40:40 PST
      </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/2010/01/31/the-ipad/#comments
      </comments>
      <pubDate>
        Sun, 31 Jan 2010 08:12:05 PST
      </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/2010/01/10/prototyping-with-briefs/#comments
      </comments>
      <pubDate>
        Sun, 10 Jan 2010 17:40:40 PST
      </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/2010/01/07/tools-of-2009/#comments
      </comments>
      <pubDate>
        Thu, 07 Jan 2010 04:35:42 PST
      </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/2009/12/15/all-time-lineup/#comments
      </comments>
      <pubDate>
        Tue, 15 Dec 2009 06:14:09 PST
      </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/2009/12/11/building-a-knowledge-base/#comments
      </comments>
      <pubDate>
        Fri, 11 Dec 2009 16:39:09 PST
      </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/2009/11/07/cleaning-out-the-closet/#comments
      </comments>
      <pubDate>
        Sat, 07 Nov 2009 22:12:45 PST
      </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/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/#comments
      </comments>
      <pubDate>
        Fri, 09 Oct 2009 15:44:04 PDT
      </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/2009/10/03/clip-version-1-0-2-has-been-released/#comments
      </comments>
      <pubDate>
        Sat, 03 Oct 2009 16:03:14 PDT
      </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/2009/10/02/the-end-of-an-era-2/#comments
      </comments>
      <pubDate>
        Fri, 02 Oct 2009 21:55:55 PDT
      </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/2009/09/15/iphone-screencasts/#comments
      </comments>
      <pubDate>
        Tue, 15 Sep 2009 04:13:03 PDT
      </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/2009/08/19/evriverse-2-0/#comments
      </comments>
      <pubDate>
        Wed, 19 Aug 2009 16:27:18 PDT
      </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/2009/06/25/cocoas-ways-of-talking/#comments
      </comments>
      <pubDate>
        Thu, 25 Jun 2009 01:53:32 PDT
      </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/2009/05/27/the-iphone-and-web-apis/#comments
      </comments>
      <pubDate>
        Wed, 27 May 2009 03:57:39 PDT
      </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/2009/05/15/peepcode-meets-macruby/#comments
      </comments>
      <pubDate>
        Fri, 15 May 2009 21:38:30 PDT
      </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/2009/05/15/typeahead-search-on-the-iphone/#comments
      </comments>
      <pubDate>
        Fri, 15 May 2009 04:55:38 PDT
      </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/2009/05/12/introducing-the-evriverse/#comments
      </comments>
      <pubDate>
        Tue, 12 May 2009 17:28:15 PDT
      </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/2009/05/08/the-great-git-setup/#comments
      </comments>
      <pubDate>
        Fri, 08 May 2009 04:17:14 PDT
      </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/2009/03/14/using-git-as-a-safety-net/#comments
      </comments>
      <pubDate>
        Sat, 14 Mar 2009 18:11:32 PDT
      </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/2009/03/04/what-jersey-means-to-java/#comments
      </comments>
      <pubDate>
        Wed, 04 Mar 2009 18:42:49 PST
      </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/2009/02/11/you-put-merb-in-my-jetty/#comments
      </comments>
      <pubDate>
        Wed, 11 Feb 2009 23:31:53 PST
      </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/2009/01/31/rewriting-history-with-git/#comments
      </comments>
      <pubDate>
        Sat, 31 Jan 2009 20:04:13 PST
      </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&amp;#8230;of Hell!!</title>
      <link>
        http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/
      </link>
      <comments>
        http://alexvollmer.com/posts/2009/01/27/opening-the-gatesof-hell/#comments
      </comments>
      <pubDate>
        Tue, 27 Jan 2009 06:01:11 PST
      </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<
