<?xml version='1.0' encoding='utf-8' ?>
<feed xmlns='http://www.w3.org/2005/Atom'>
  <title>
    Alex Vollmer
  </title>
  <link href='http://alexvollmer.com/feeds/atom.xml' rel='self' />
  <link href='http://alexvollmer.com/' />
  <updated>2011-06-11T10:23:44-07:00</updated>
  <id>http://alexvollmer.com/</id>
  <author>
    <name>
      Alex Vollmer
    </name>
    <email>
      alex.vollmer@gmail.com
    </email>
  </author>
  <entry>
    <title>
      <![CDATA[
          WWDC 2011
      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2011/06/11/wwdc-2011/' />
    <updated>2011-06-11T10:23:44-07:00</updated>
    <id>http://alexvollmer.com/posts/2011/06/11/wwdc-2011/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
            One Year In Orbit
        ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2011/05/21/one-year-in-orbit/' />
    <updated>2011-05-21T10:13:35-07:00</updated>
    <id>http://alexvollmer.com/posts/2011/05/21/one-year-in-orbit/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
              Amazing Times
          ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2011/04/24/amazing-times/' />
    <updated>2011-04-24T15:01:07-07:00</updated>
    <id>http://alexvollmer.com/posts/2011/04/24/amazing-times/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                The Dumbest Thing I've Ever Done
            ]]>
    </title>
    <link href="http://alexvollmer.com/posts/2011/04/17/the-dumbest-thing-i've-ever-done/" />
    <updated>2011-04-17T09:10:18-07:00</updated>
    <id>http://alexvollmer.com/posts/2011/04/17/the-dumbest-thing-i've-ever-done/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                  Tools of the Estate
              ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2011/01/30/tools-of-the-estate/' />
    <updated>2011-01-30T19:15:19-08:00</updated>
    <id>http://alexvollmer.com/posts/2011/01/30/tools-of-the-estate/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                    Muscle Memory
                ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/11/10/muscle-memory/' />
    <updated>2010-11-10T12:50:48-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/11/10/muscle-memory/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                      Assert Yourself!
                  ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/10/17/assert-yourself/' />
    <updated>2010-10-17T09:46:11-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/10/17/assert-yourself/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                        NSOperations for Fun & Profit
                    ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/09/19/nsoperations-for-fun-and-profit/' />
    <updated>2010-09-19T16:54:43-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/09/19/nsoperations-for-fun-and-profit/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                          Launching the Radiant Capsule
                      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/09/12/launching-the-radiant-capsule/' />
    <updated>2010-09-12T12:26:30-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/09/12/launching-the-radiant-capsule/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                            UIAutomation Test Fixtures Redux
                        ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/09/06/uiautomation-test-fixtures-redux/' />
    <updated>2010-09-06T14:41:13-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/09/06/uiautomation-test-fixtures-redux/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                              Design Pressures of Mock Objects
                          ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/07/25/design-pressures-of-mock-objects/' />
    <updated>2010-07-25T16:41:25-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/07/25/design-pressures-of-mock-objects/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                More UIAutomation
                            ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/07/09/more-uiautomation/' />
    <updated>2010-07-09T07:14:06-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/07/09/more-uiautomation/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                  Working with UIAutomation
                              ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/07/03/working-with-uiautomation/' />
    <updated>2010-07-03T08:55:23-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/07/03/working-with-uiautomation/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                    Making Fun of Things with OCMock
                                ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/' />
    <updated>2010-06-28T09:35:27-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/</id>
    <content type='html'>
      <![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>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                      A Tale of Two Cultures
                                  ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/' />
    <updated>2010-06-13T15:10:14-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/06/13/a-tale-of-two-cultures/</id>
    <content type='html'>
      <![CDATA[
                                        <p><a href="http://www.flickr.com/photos/adamjackson/4670520309/" target="_new">
                                        <img class="right" src="http://farm5.static.flickr.com/4011/4670520309_fbac12cd42_m.jpg"/>
                                        </a></p>
                                        
                                        <p>I just returned from the 2010 edition of Apple's WWDC. The week before I took
                                        a week off from my iPhone and lived with an Android Nexus One. Both my personal
                                        experience with Android and the following week's announcements left a
                                        strong impression that, in the so-called "smartphone" space, we are really
                                        seeing the success of two very different mind-sets, cultures and philosophies.
                                        I'm not interested in a winner-takes-all kind of war. Instead I wanted to look
                                        at the differences between these two companies in the context of them
                                        co-existing and each having a happy, satisfied base of customers.</p>
                                        
                                        <p>I <em>was</em> going to write about how capable the Nexus One seems to me, but how
                                        amateurish the UI appears. At times, the look and feel of the Android UI
                                        looks like its designers simply couldn't figure out how to fill the space
                                        with something interesting.</p>
                                        
                                        <p>I <em>was</em> going to write about how the ubiquity of the four hardware buttons are
                                        both a blessing and curse. I understand that the designers were trying to
                                        provide a set of near-universal options in a consistent place. Unfortunately
                                        it was too easy to accidentally hit the "home" key while typing on the soft
                                        keyboard.</p>
                                        
                                        <p><a href="http://www.flickr.com/photos/oyf/4255429887/" target="_new">
                                          <img src="http://farm3.static.flickr.com/2770/4255429887_e16b119a2d_m.jpg" class="left"/>
                                        </a></p>
                                        
                                        <p>I <em>was</em> going to write about the moment I realized just how different the
                                        design philosophies between Android and iOS (nee iPhoneOS) are when I wanted
                                        Instapaper integration with a good Twitter client. I needed to find an
                                        Instapaper app, not a Twitter app with Instapaper integration. I simply didn't
                                        grok the universal plugin architecture of Android at first. In hindsight it
                                        makes perfect sense&mdash;if you're a software developer or tech-geek. It
                                        seems insane to require the user to have a mental model that's so intimate
                                        with Android's implementation details.</p>
                                        
                                        <p>I <em>was</em> going to write about how delighted I was with Android's GMail
                                        integration and how much I wish something similar existed on the iPhone. I
                                        love GMail. I couldn't care less about other mail configurations (POP or
                                        IMAP). Maybe the built-in regular mail app is as clunky as Apple's, but I
                                        didn't use it. Kudos to Google for such a seamless integration with not only
                                        Gmail, but the calendar and contacts too.</p>
                                        
                                        <p>I <em>was</em> going to write about all these little bits of evidence that showed
                                        just how different the philosophies are between these two companies and
                                        these two platforms. I was going to write about how it's a bit odd to put
                                        them in competition with each other because, in a sense, they are really
                                        trying to build two different things: Google wants to build the most bad-ass
                                        feature-rich, piece of mobile technology there ever was. Apple wants to build
                                        a mobile experience.</p>
                                        
                                        <p>I <em>was</em> going to write about all of these things, but after attending the
                                        keynote at WWDC last week, I realized that there was only one thing that I
                                        needed to point to that most effectively highlights the differences
                                        between the two:</p>
                                        
                                        <p><a href="http://www.apple.com/iphone/features/facetime.html" target="_new">
                                          <img src="/images/2010/06/facetime.png">
                                        </a></p>
                                        
                                        <p>At the end of this video, you had a room full of five-thousand geeks drying
                                        their eyes. You can call the video cheesy or manipulative. You can call it a
                                        piece of marketing fluff. But that video was <em>not</em> about protocols,
                                        compatibility, specifications or any of the myriad technical details we debate
                                        on a daily basis. That video was about telling human stories that we can all
                                        relate to.</p>
                                        
                                        <p>I haven't yet been to a Google I/O event. I'd really like to attend one. But
                                        right, wrong or indifferent, you would never see something like this from
                                        Google. I can't think of anything that does a better job of summing up the
                                        completely different views that Google and Apple have of the world.</p>
                                    ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                        Cocoa's Broken Tests
                                    ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/' />
    <updated>2010-06-01T11:20:51-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/06/01/cocoas-broken-tests/</id>
    <content type='html'>
      <![CDATA[
                                          <p>I'm a long-time TDD kinda guy. I've had the great fortune of learning TDD
                                          first-hand from <a href="http://en.wikipedia.org/wiki/Kent_Beck" title="Kent Beck - Wikipedia,the free encyclopedia">one of its greatest practitioners</a>
                                          and consider it one of the core disciplines of the way I go about my
                                          profession. So when I first started doing Cocoa programming in earnest I was
                                          shocked at the state of automated testing. Compared to my experiences on other
                                          platforms, the tools are archaic and backwards. Moreover, the philosophy of
                                          testing just doesn't seem to be baked into the DNA of the Cocoa community.
                                          Nobody seems to be talking about it much. So I've just suffered with
                                          old-fashioned head-against-wall development without the comforting support of
                                          TDD. But I don't know how much longer I can take it. Am I crazy for wanting
                                          TDD in Cocoa, or are the two simply incompatible?</p>
                                          
                                          <p>Given the current state of affairs, it's not hard to see why there's a
                                          <a href="http://www.wilshipley.com/blog/2005/09/unit-testing-is-teh-suck-urr.html" title="Call Me Fishmeal.: Unit testing is teh suck, Urr.">bias against unit-testing</a>
                                          in the Cocoa community. <sup><a href="#note1">1</a></sup> Unit-testing tools,
                                          support and idioms within Cocoa are nowhere close to where they are in, say,
                                          the Java, .Net, Ruby or Python communities. Compared to those environments,
                                          unit-testing in Cocoa is just flat out <em>difficult</em>. I can easily understand
                                          why a developer would conclude that the cost and effort of TDD outweighs the
                                          benefits.</p>
                                          
                                          <h1>The Dismal Science</h1>
                                          
                                          <p><a href="http://www.flickr.com/photos/janbrasna/399875844/" title="Currencies on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/178/399875844_16660fd4bf_m.jpg" class="left" alt="It's all about the money"></a></p>
                                          
                                          <p>Think of every "best practice" you've ever been exposed to in software. They
                                          all come down to cost-benefit tradeoffs in the end. Up-front requirements
                                          gathering? It's an attempt to manage change and indemnify certain parties when
                                          things go awry. Iterative development? It's merely a short-term review process
                                          to evaluate the cost of future development against opportunities in the
                                          future. Automated testing? Computers (generally) work more cheaply than
                                          humans, so invest in automating repeated tasks so that, over the long-haul,
                                          more work is accomplished by cheaper workers. Hell, even the oft-cited goals
                                          of code-reuse in object-oriented programming are economic ones. The list goes
                                          on and on and on.</p>
                                          
                                          <p>But, even as a long-time practitioner of test-driven development, I don't view
                                          it as axiomatic. In this big, bad world of ours there have to be cases where
                                          the economics simply don't add up, and it simply isn't <em>cost effective</em> to
                                          build stuff using TDD.<sup><a href="#note2">2</a></sup> Returning to
                                          Cocoa, I can see how developers come to the conclusion that TDD in Cocoa
                                          simply isn't worth the price of admission.</p>
                                          
                                          <p>So what makes TDD in Cocoa so expensive? Would things look different if we
                                          could change the balance sheet?</p>
                                          
                                          <h1>Bear-Skins &amp; Stone Knives</h1>
                                          
                                          <p><a href="http://www.flickr.com/photos/g_originals/368093250/" title="working hand on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/169/368093250_8fa93d209a_m.jpg" class="right"/></a></p>
                                          
                                          <p>Back in the day, <a href="http://www.sente.ch/software/ocunit/" title="Sen:te - OCUnit">OCUnit</a>
                                          was <em>the</em> xUnit toolkit of choice for Cocoa programming. In 2006
                                          Apple put OCUnit right into Xcode and TDD received its first official
                                          blessing. Now I don't have a beef in particular with OCUnit&mdash;it's
                                          essentially a faithful implementation of xUnit patterns for Objective-C. What
                                          is surprising is how weakly it's integrated with Xcode.</p>
                                          
                                          <p>To unit-test, you have to create an entirely new target to execute your
                                          unit-tests within. However, you don't run it like a normal executable. It's
                                          baked into the build process for that target so that testing errors show up
                                          just like build errors. I'll admit that's kind of cute and at least makes an
                                          attempt to integrate TDD into the development process. But keeping unit-tests
                                          as a separate target means more drop-down flipping in Xcode to go between
                                          unit-testing and running my application. Oh and the bloody drop-downs in
                                          Xcode&hellip;don't even get me started&hellip;</p>
                                          
                                          <p>The other issue is debugging. If your unit-tests are failing, god help you if
                                          you want to find out why. It takes <a href="http://chanson.livejournal.com/120740.html" title="Chris Hanson - Xcode: Debugging Cocoa application unit tests">a lot of environment-variable hijinks</a>
                                          to be able to actually debug your unit-tests &mdash;something that is
                                          significantly easier on every other platform I've ever worked on. All of this
                                          leaves me with the distinctly uneasy feeling that Apple and the Cocoa community
                                          at-large are merely paying lip-service to TDD.</p>
                                          
                                          <p>Compare this to how JUnit is integrated into your standard Java IDE or
                                          awesome Ruby testing tools like
                                          <a href="http://www.zenspider.com/ZSS/Products/ZenTest/" title="ZenTest: Automated test scaffolding for Ruby">autotest</a>.
                                          These tools are so much more immediate and easier to reach for. Xcode looks
                                          like it came from the era of the horse and buggy. These kind of tools and this
                                          kind of support needs to be a part of the development environment in a
                                          more natural way. Right now it's just a primitive, bolted-on afterthought.
                                          It's a wonder anyone has the patience to use it.</p>
                                          
                                          <h1>A New Mentality</h1>
                                          
                                          <p>Another challenge in Cocoa is figuring out where TDD fits in such a
                                          framework-driven environment. To Apple's credit, the frameworks that Cocoa
                                          provides do a pretty good job of "making the simple easy and the difficult
                                          possible". However because Cocoa is <em>so</em> prescriptive, it can be difficult for
                                          developers to stand back and figure out what to test. It's just so easy to
                                          just let the idioms fly off the fingers, that testing them seems like a silly
                                          exercise.</p>
                                          
                                          <p>I think a common conclusion for the the would-be TDD'er is that they often
                                          find their tests essentially repeating the implementation. These are most
                                          expensive tests to write and maintain. Not only do you end up duplicating the
                                          code (thus adding coupling and brittleness), but they also take up a lot of
                                          time to write and can be pretty error-prone.</p>
                                          
                                          <p>There has been a lot of thought about similar problems in other communities,
                                          so why not steal these ideas and apply them to Cocoa development? Surely
                                          strategies like <a href="http://martinfowler.com/bliki/InversionOfControl.html" title="MF Bliki: InversionOfControl">inversion of control</a>
                                          and <a href="http://www.mulle-kybernetik.com/software/OCMock/" title="Mulle kybernetiK -- OCMock">mocks</a>
                                          would help make TDD in Cocoa an economic possibility. <sup><a href="#note3">3</a></sup></p>
                                          
                                          <p>The Cocoa community simply hasn't evolved a good set of testing practices the
                                          way others have. Given the benefits I've seen in other environments, it's hard
                                          for me to believe that Cocoa and Objective-C are exceptional in this regard. I
                                          think that there are ways to do it, we just haven't discovered them yet. I
                                          recall from my Java and Ruby days that testing idioms and practices evolved <em>a
                                          lot</em> before we got somewhere reasonable. Simply put, the Cocoa world's
                                          collective testing skills and knowledge lag severely behind a lot of other
                                          languages.</p>
                                          
                                          <p><img class="right" src="/images/2010/06/kim-jong-il.jpg" alt="Kim Jong Il"></p>
                                          
                                          <p>Facing this requires the Cocoa community to face its own isolationist and
                                          exceptionalist attitudes. There's nothing so special about Cocoa and
                                          Objective-C that <em>conceptually</em> invalidates the effectiveness of TDD. <sup><a
                                          href="#note4">4</a></sup> Cocoa folks need to look outside of their walled
                                          garden to see what others have done. This is not something I've seen much,
                                          if any of, in the Cocoa community. Frankly, the dominant attitude seems to be
                                          one of snobbery and elitism. It's an unfortunate attitude that holds us all back.</p>
                                          
                                          <h1 id="footnotes">Footnotes</h1>
                                          
                                          
                                          <ol>
                                          <li>
                                          <a name="note1"></a>
                                          Normally it wouldn't be fair to link to a five-year old post and call
                                          it "representative" of a community's attitude, but I think for an insular
                                          group like Cocoa-nerds, this is totally reasonable.
                                          </p>
                                          </li>
                                          
                                          <li>
                                          <a name="note2"></a>
                                          I'm not saying that I, personally, have encountered such a thing, but
                                          I don't think it's unreasonable to assume that the possibility <em>exists</em>.
                                          </li>
                                          
                                          <li>
                                          <a name="note3"></a>
                                          There is, of course, a pathological extreme to this line of thinking. That
                                          extreme is called <a href="http://www.springsource.org/" title="SpringSource.org |">Spring</a>.
                                          </li>
                                          
                                          <li>  
                                          <a name="note4"></a>
                                          OK, I'll admit that iPhone development is a little different because of
                                          having to deal with the device vs. the simulator. Getting tests running on the
                                          device is a non-trivial exercise. But I'm not convinced that unit-tests have
                                          to run on the device. Yes, there are differences between the real and
                                          simulated environments, but those differences should be accounted for in
                                          <em>integration tests</em>&mdash;a topic I'm not going to address here.
                                          </li>
                                          </ol>
                                          
                                          
                                          <p></div></p>
                                      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                          The International Colors of iPhoneOS
                                      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/' />
    <updated>2010-05-21T08:46:32-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/05/21/the-international-colors-of-iphoneos/</id>
    <content type='html'>
      <![CDATA[
                                            <p>Like flossing or saving for retirement, localizing
                                            and internationalizing your applications is one of those things "you should
                                            do". Cocoa, and by extension Cocoa Touch, has pretty decent localization
                                            (l10n) and internationalization (i18n) support. If you use the
                                            <code>NSLocalizedString</code> macro along with locale-specific strings files, you will
                                            handle 99.9% of your localization needs.</p>
                                            
                                            <p><img src="http://revoir1printemps.canalblog.com/albums/benetton/m-benetton654.jpg" height="100" class="left"></p>
                                            
                                            <p>But what if you're integrating with a web service? What's the best way to
                                            convey the user's current settings to an external party? I've run into this
                                            exact situation a couple of times and wanted to share the approach I like to
                                            take.</p>
                                            
                                            <h1>The Server-Side</h1>
                                            
                                            <p>The first thing you need to determine is how you'll express the user's
                                            current locale settings. If you own the servers-side, you can implement this in
                                            whatever way you see fit. Personally, I like to take advantage of as much
                                            of the HTTP specification as I can. Rather than overloading every request
                                            with a request parameter, I like to use the <code>Accept-Language</code> header.
                                            <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4" title="HTTP/1.1: Header Field Definitions">The specification</a>
                                            says that the format of the <code>Accept-Language</code> header allows multiple locales with
                                            <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.10" title="HTTP/1.1: Protocol Parameters">"quality values"</a>
                                            optionally given to each one to express order of preference.
                                            For example, a valid <code>Accept-Language</code> header might look like this:</p>
                                            
                                            <div class="highlight"><pre>Accept-Language: da, en-gb;q<span class="o">=</span>0.8, en;q<span class="o">=</span>0.7&#x000A;    </pre>
                                            </div>
                                            
                                            
                                            <p>In this example, Danish (with no specific region) is preferred first, followed
                                            by English (in the Great Britain region), followed by English in any region. The
                                            language and region are delicately intertwined in a bunch of different ways.
                                            Depending on the combination, the region may affect how words are spelled
                                            (for example "armor" in American English vs. "armour" in British English). Not
                                            all locales and regions work this way so there are plenty of corner-cases.</p>
                                            
                                            <p>Ruby on Rails is my server-side stack of choice these days. Like Cocoa, Rails
                                            is pretty good at making it easy to localize and internationalize your
                                            application. However, despite Rails claim to being "opinionated", it's
                                            surprisingly indecisive about the best way to express language and region
                                            preferences. The <a href="http://guides.rubyonrails.org/i18n.html" title="Rails Internationalization (I18n) API">Rails i18n Guide</a> suggests that you can get the locale
                                            as a query parameter (blech), via the domain name (if you've set your
                                            application and client up this way), via URL parameters (i.e. as a path
                                            segment within a larger URI structure), via built-in user settings, via GeoIP
                                            or using the <code>Accept-Language</code> header. As I stated before, I like the latter
                                            solution the most. However parsing the header, dealing with the quality scores
                                            and then figuring out the best one is something that has already been solved.
                                            For that, I like the <a href="http://rubygems.org/gems/http_accept_language" title="http_accept_language |
                                            RubyGems.org | your community gem host"><code>http_accept_language</code>
                                            gem</a>.</p>
                                            
                                            <p>In the <code>ApplicationController</code>, I setup a <code>before_filter</code> that uses the gem to
                                            parse the <code>Accept-Language</code> header. Since I may not have localized the web
                                            server to match a given request, I use the <code>compatible_language_from</code> method
                                            to figure out what, if any, language match there is.</p>
                                            
                                            <div class="highlight"><pre><span class="n">before_filter</span> <span class="ss">:check_language</span>&#x000A;    &#x000A;    <span class="k">def</span> <span class="nf">check_language</span>&#x000A;      <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span> <span class="o">=</span> <span class="k">if</span> <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">].</span><span class="n">nil?</span>&#x000A;        <span class="n">request</span><span class="o">.</span><span class="n">compatible_language_from</span><span class="p">(</span><span class="no">MyApp</span><span class="o">::</span><span class="no">AVAILABLE_LANGUAGES</span><span class="p">)</span>&#x000A;      <span class="k">else</span>&#x000A;        <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span>&#x000A;      <span class="k">end</span>&#x000A;      <span class="no">I18n</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="n">params</span><span class="o">[</span><span class="ss">:locale</span><span class="o">]</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
                                            </div>
                                            
                                            
                                            <p><code>MyApp::AVAILABLE_LANGUAGES</code> is constant array defined in a Rails
                                            initializer (in <code>config/intializers</code>) that figures out all of the possible
                                            locales I have configured:</p>
                                            
                                            <div class="highlight"><pre><span class="k">module</span> <span class="nn">MyApp</span>&#x000A;      <span class="no">AVAILABLE_LANGUAGES</span> <span class="o">=</span> <span class="no">Dir</span><span class="o">[</span><span class="no">RAILS_ROOT</span> <span class="o">+</span> <span class="s2">&quot;/config/locales/*&quot;</span><span class="o">].</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span>&#x000A;        <span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">first</span>&#x000A;      <span class="k">end</span>&#x000A;    <span class="k">end</span>&#x000A;    </pre>
                                            </div>
                                            
                                            
                                            <p>Despite my aversion to using request parameters, it can be handy for ad-hoc
                                            testing to be able to tack a query parameter on to change the locale. Also,
                                            once you've determined the locale, you need to notify the <code>I18n</code> framework
                                            as I've done in the last line of the <code>check_language</code> method.</p>
                                            
                                            <h1>The Client-Side</h1>
                                            
                                            <p>OK, great. Now we've figure out how to vary the locale on the web-side. How
                                            do we extract this information from the device and ship it off in our
                                            HTTP headers?</p>
                                            
                                            <p>Here you have two tasks: the first is to determine what the value of the
                                            <code>Accept-Language</code> header should be and second, to actually make sure you send
                                            those values. Since there are several ways of making HTTP requests in iPhoneOS
                                            I'm not going to go into the details. Whether you're using <code>NSURLRequest</code>,
                                            <a href="http://allseeing-i.com/ASIHTTPRequest/" title="ASIHTTPRequest Documentation - All-Seeing Interactive">ASIHTTPRequest</a>,
                                            <a href="http://alternateidea.com/blog/articles/2009/7/11/introducing-httpriot-easily-consume-rest-resources-on-the-iphone-and-os-x" title="AlternateIdea:  Introducing HTTPRiot - Easily Consume REST Resources on the iPhone and OS X">HTTPRiot</a>
                                            or your own homegrown thing, presumably you have
                                            some reasonable way of setting the <code>Accept-Language</code> header in a consistent
                                            way.</p>
                                            
                                            <p>To figure out what locale your user is in, you need to consult the
                                            <code>NSLocale</code> class. This provides several class methods that yield a
                                            <code>NSLocale</code> instance that reflects the user's current settings. If you look
                                            at the docs, there are three class-methods that return a <code>NSLocale</code> instance:
                                            <code>+systemLocale</code>, <code>+currentLocale</code> and <code>+autoupdatingCurrentLocale</code>. The
                                            differences between the three are not apparently obvious and, I think, reflect
                                            <code>NSLocale</code>'s original desktop heritage.</p>
                                            
                                            <p>The <code>+systemLocale</code> method will return a default <code>NSLocale</code> instance when one
                                            cannot otherwise be determined. In my experience, I've never seen this return
                                            anything but a blank and useless <code>NSLocale</code> instance. Don't bother using it.</p>
                                            
                                            <p>The <code>+currentLocale</code> method returns a <code>NSLocale</code> instance that reflects the
                                            user's current setting. However there is a bit of language in the docs that
                                            I initially found confusing:</p>
                                            
                                            <blockquote><p>Settings you get from this locale do not change as System Preferences are
                                            changed so that your operations are consistent. Typically you perform some
                                            operations on the returned object and then allow it to be disposed of.
                                            Moreover, since the returned object may be cached, you do not need to hold on
                                            to it indefinitely.</p></blockquote>
                                            
                                            <p><em>Huh?</em> To understand what's going on here, we need to take a look at the docs
                                            for the <code>+autoupdatingCurrentLocale</code> method:</p>
                                            
                                            <blockquote><p>Settings you get from this locale do change as the user’s settings change
                                            (contrast with currentLocale).</p></blockquote>
                                            
                                            <p>Remember, a lot of CocoaTouch came from the desktop Cocoa environment. On the
                                            desktop you can open the System Preferences and change your region and
                                            language settings anytime <em>while applications are running.</em> However, until
                                            iPhone OS 4.0 is released, this is <em>not</em> something you can do on any iPhoneOS
                                            device. So the net effect, and this matches my own observations, is that on
                                            iPhone OS 3.x <code>+currentLocale</code> and <code>+autoupdatingCurrentLocale</code> are
                                            essentially the same. But, if you want to be prepared for the future, go ahead
                                            and use the <code>+autoupdatingCurrentLocale</code> method. Once you have a <code>NSLocale</code>
                                            instance, you call the <code>-localeIdentifier</code> method on it to get a <code>NSString</code>
                                            like <strong>en_US</strong> or <strong>fr_FR</strong>.</p>
                                            
                                            <p>So if you're like me, you want to test that this actually works. So, naturally,
                                            you would figure out how to modify the settings on your phone to yield
                                            different responses. What you'll soon discover is that the current locale
                                            settings are derived from two separate and independent settings and that
                                            various combinations of the two can produce unexpected results.</p>
                                            
                                            <p>Start by launching the "Settings" application. Select <em>General ⇢
                                            International</em>. You'll get a screen where you can pick your language, your
                                            keyboards and your region format. What may surprise you is that <em>changing the
                                            language does not affect the current locale.</em> I'm in the United States so my
                                            region format is set to "United States". If I change my language to French,
                                            but leave the region format setting alone, all localization within the system
                                            and applications will use the French language, but my locale remains
                                            <strong>en_US</strong>.</p>
                                            
                                            <p><img src="/images/2010/05/international-iphone.jpg" alt="International Settings on iPhone" /></p>
                                            
                                            <p>OK, so <code>NSLocale</code> doesn't quite work as expected, but where does the system
                                            store the current language? It turns out the <code>NSLocale</code> provides yet another
                                            class method, named <code>+preferredLanguages</code>, that returns an array of language
                                            codes as strings. With the settings described above, the first entry in that
                                            array is "fr".</p>
                                            
                                            <p>If you change your settings where you leave the language set to English, but
                                            change the region format to French (in the "France" region), the current locale
                                            will now be set to <strong>fr_FR</strong> and the first entry in the <code>preferredLanguages</code>
                                            array will be "en" for English.</p>
                                            
                                            <h1>What It All Means</h1>
                                            
                                            <p>Out of the box, Rails doesn't provide full-blown region-specific localization.
                                            You can either hack something or use one of many <a href="http://rails-i18n.org/wiki" title="Rails I18n">i18n plugins</a>
                                            or <a href="http://github.com/joshmh/globalize2" title="joshmh's globalize2 at master - GitHub">Globalize2</a>.
                                            So if you try to send a language-region combination to Rails (such as <strong>en_US</strong>),
                                            chances are good that you won't have the right localization setup and you'll
                                            fall-back to your default locale.</p>
                                            
                                            <p>You have two choices: you can make the client send something that the server
                                            understands, or teach the server to respect more fine-grained localization
                                            values. If you want to go the first route, I would suggest simply querying the
                                            <code>+preferredLanguages</code> array and using the first entry as the value for your
                                            <code>Accept-Language</code> header. However if your server-side localization can handle
                                            it, use the <code>+currentLocale</code> instead so that you can handle regional
                                            differences and spelling much better.</p>
                                        ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                            Visual Affordance in a Touch-Enabled World
                                        ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/' />
    <updated>2010-05-07T10:46:39-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/05/07/visual-affordance-in-a-touch-enabled-world/</id>
    <content type='html'>
      <![CDATA[
                                              <p><em>Ooooh</em>, you must be thinking, <em>what a posh title this is!</em> Okay, I'll admit
                                              to copping a bit of a grandiose attitude when I came up with this, but hear
                                              me out on this one.</p>
                                              
                                              <p><img src="/images/2010/05/mad-as-hell.jpg" class="left" alt="I was mad as hell
                                              about a mouse and keyboard until I got an iPad!"/> The iPad has generated a
                                              lot of criticism, scrutiny and analysis in recent months. The debate about the
                                              ills and assets of the platform have, and will continue to be, debated
                                              endlessly. I think one thing is pretty clear though&mdash; whether you like
                                              Apple or not, whether you have an iPad or not, whether you think it's the most
                                              awesome-est thing ever or not, it <em>is</em> revolutionary device. I don't mean in
                                              terms of technical execution (yes the A6 chip is a marvel, the
                                              power-consumption is amazing, blah blah blah). What I mean is that somebody
                                              with Apple's clout finally stood up and threw away the last three decades of
                                              user-interface paradigm <em>and they're laughing all the way to the bank doing
                                              it</em>.</p>
                                              
                                              <p>So, if you jettison The Way We've Always Done Things &trade;, what do you replace
                                              it with? More importantly, which things from The Old Way are no longer
                                              applicable to The New Way? This is a big topic that will take some time to
                                              settle itself. We've had this CPU/mouse/keyboard setup for nearly thirty years
                                              and we're <em>still</em> learning how to make it work for humans. I don't expect us
                                              to settle the micro-debates of touch-interface design for quite a while, but
                                              I do want drill down to something pretty specific.</p>
                                              
                                              <p>Take a moment and ponder what the mouse <em>really is</em> in a graphic user
                                              interface. It's a proxy. It's a loosely-connected device where movement and
                                              gestures in one space are translated to movement and gestures in another
                                              virtual space. To operate a mouse well, you have to perform constant mental
                                              transform operations from the physical world to the world you are trying to
                                              manipulate on the screen. The mouse is, effectively, a rather thick layer
                                              between you and what you're trying to do.</p>
                                              
                                              <h1>Exploiting the Gap</h1>
                                              
                                              <p>As we got better and better with the mouse <sup><a href="#note1">1</a></sup>
                                              software started to exploit this gap between you and your machine. The first
                                              place this showed up was in context menus. Once we already had to make a
                                              mental stop on the train ride from our brain to the machine, why not make the
                                              station more useful to folks? <em>Hell, let's put in some vending machines,
                                              and perhaps some couches. We could even install</em> Wi-Fi <em>and people could
                                              get</em> even more <em>productive.</em> Pile it on, pile it on.</p>
                                              
                                              <p>Taken to an extreme, the mouse becomes the primary means by which we
                                              interact with our machines. If you don't believe me, take a look at any
                                              professional CAD workstation or that god-awful OpenOffice mouse.</p>
                                              
                                              <p><img src="/images/2010/05/context_menu.png" class="right" alt="The ubiquitous,
                                              right-click-able, context menu"/> However these are extremes. There isn't
                                              necessarily anything wrong with things like extra mice buttons or context
                                              menus. But, in a world of touch, where the mental and physical distance
                                              between our intentions and execution is much smaller, that thick
                                              layer/opportunity is gone. <em>Context menus?</em> How the hell do I "right-touch"
                                              the screen? <em>Mouse-overs?</em> Current touch interfaces don't have any proximity
                                              sensors <sup><a href="#note2">2</a></sup>&mdash;either you touch something or
                                              you don't. Yet these two very simple interaction models have become a crucial
                                              part of the UI vocabulary we have all acquired over the years.</p>
                                              
                                              <p>Think about a mouse-over. What is it there for? Mouse-overs offer two things:
                                              a preview mechanism allowing you to learn more about something without having
                                              to commit to it, and as a backup when a pictorial icon's meaning isn't clear
                                              enough. We don't have these on the iPad <sup><a href="#note3">3</a></sup>. So
                                              as an application designer and builder, how do we give people some notion of
                                              what this thing can do? What kind of <em>affordance</em> can we offer?</p>
                                              
                                              <h1>Spelunking</h1>
                                              
                                              <p>As you start using and learning an application, you generally have two
                                              questions:</p>
                                              
                                              <ul>
                                              <li>What can this thing do?</li>
                                              <li>How can I get this to do ______?</li>
                                              </ul>
                                              
                                              
                                              <p>These are asked from two opposing angles, but both are about discovering the
                                              capabilities of the software. When a user doesn't know what your application
                                              can do, how can you build it in a way that they can discover it? An equally
                                              important question is how can they explore your application without having to
                                              commit to any action, particularly a destructive one?</p>
                                              
                                              <p><img src="/images/2010/05/nnw-ipad.png" class="left" alt="The 'next unread'
                                              button in NNW"/> Let's look at one of my favorite iPad apps in particular,
                                              <a href="http://netnewswireapp.com/ipad/" title="NetNewsWire for iPad &laquo; NetNewsWire">Net News Wire</a>.
                                              A nice feature of the application is the ability to progress through all of your unread items
                                              with a single tap. When I first got the app, I <em>knew</em> that there had to be a
                                              way to do this, but I couldn't find it. There <em>was</em> a mysterious-looking button
                                              in the corner of the screen, but I wasn't sure what it was for. I mean, it
                                              might do <em>anything</em>. How was I to know what would happen? It wasn't until I saw a
                                              <a href="http://seattlexcoders.org/2010/04/20/april-22-meeting---brent-simmons-and-brad-ellis.html" title="Seattle Xcoders - April 22 Meeting - Brent Simmons and Brad Ellis">presentation by Brent Simmons and Brad Ellis on the design of NNW</a> that I
                                              actually found out where that button was. You can't really figure out what it
                                              does unless you poke it. If you poke that button, there isn't a corresponding
                                              "undo" button for that action.</p>
                                              
                                              <p>That's not a dig against Brent and Brad, I think they did a wonderful job
                                              with NNW. But it does highlight how difficult it can be to convey such a
                                              feature to the user. I think it may be one of the biggest challenges on the
                                              platform. How do we let the user know what our application can do?</p>
                                              
                                              <p>Let's be honest here, if you're relying on documentation to teach the user
                                              the basics, you've already lost the battle. Documentation is fine for really
                                              deep, detailed information (see OmniGraffle on the iPad for an example). But
                                              requiring a user to read the Owner's Manual before they can even use your
                                              software went out about the same time as floppy disks. On the iPad an
                                              up-front documentation requirement is just laughable.</p>
                                              
                                              <h1>Little Gets Big</h1>
                                              
                                              <p>One final thought is that although the iPhone and iPad obviously share the
                                              same DNA, the difference in size makes this acutely problematic on the iPad.
                                              On the iPhone you simply can't cram that much stuff into an application. Read
                                              the iPhone Human Interface Guidelines and you'll quickly get the message that
                                              on the iPhone, <em>less is more</em>. By and large, the best iPhone apps simply don't
                                              have that many features integrated into them. This gives application designers
                                              more freedom to make clear the intent of the features that are implemented.</p>
                                              
                                              <p>On the iPad, it's a different story. There's so much more real-estate. Running
                                              an iPhone application on the iPad is so laughably awkward that it starkly
                                              highlights just how different the platforms really are. So now, as iPad
                                              application builders, we have more space than ever. While we're freed from the
                                              space constraints of the iPhone, we now have a challenge (and responsibility)
                                              to use it effectively. It's not hard to imagine some developers embracing
                                              these new green fields to produce some truly awful interfaces. Please, don't
                                              be one of them.</p>
                                              
                                              <h2>Tangents</h2>
                                              
                                              <p> <a name="note1"></a>1. Make no mistake here, we've had to <em>train</em>
                                              ourselves to use the mouse. Just watch your grandparents struggle with a 
                                              mouse and you'll realize how un-intuitive the device really is.</p>
                                              
                                              
                                              <p></p>
                                              
                                              <p><a name="note2"></a>2. I'm not even sure if they did that it would be such a good
                                              idea. Requiring that level of fine-finger dexterity immediately makes such a
                                              device exclusive to the young and facile.</p>
                                              
                                              
                                              
                                              
                                              <p><a name="note3"></a>3. OK, there <em>is</em> a common trick
                                              of touching and holding a hyperlink long enough to get a menu of
                                              options.</p>
                                          ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                              On Technical Presentations
                                          ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/' />
    <updated>2010-04-30T07:51:51-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/04/30/on-technical-presentations/</id>
    <content type='html'>
      <![CDATA[
                                                <p>I spent last weekend at the Seattle version of the <a href="http://www.voicesthatmatter.com/iphone2010/" title="iPhone
                                                Developers Conference - Using the iPhone OS to build apps for the iPad and
                                                iPhone">Voices That Matter iPhone
                                                Developer's conference</a>. The content was great, but aside from John "Wolf" Rentzch's Core
                                                Data talk, the quality of the slides and presentation was pretty lacking. I'm
                                                not here to dogpile on those speakers. I still got a lot out of their talks,
                                                but the experience crystallized some important rules for me about technical
                                                presentations.</p>
                                                
                                                <h2>Size and Geometry</h2>
                                                
                                                <p><a href="http://www.flickr.com/photos/laffy4k/405446783/" title="Huntington
                                                University: Zurcher Auditorium on Flickr - Photo Sharing!"><img src="http://farm1.static.flickr.com/122/405446783_a88c63ce0c_m.jpg"
                                                class="left"/></a></p>
                                                
                                                <p>There is a axiom in military science that says no plan survives contact with
                                                the enemy. In a similar vein, no slide layout survives contact with an actual
                                                display screen. As we craft presentations it's easy to get so locked into
                                                looking at our screens that we often forget about the context of the room in
                                                which it will be given. There are two important things to consider about the
                                                room: how far back the audience stretches from the screen and the angle of the
                                                audience. In a room with a "deep" audience and shallow angle, anywhere from
                                                the bottom 20% - 30% of the screen will only be visible to the front row. Some
                                                professional presenters make it a matter of habit to simply avoid the bottom
                                                quarter of the screen. Think of this as a creative constraint to embrace and
                                                help you focus your message.</p>
                                                
                                                <p>The dimensions of the audience also affect the size of the content in your
                                                slides —specifically the font size you choose. Somehow font sizes that look
                                                like billboards on your laptop are diminished to footnotes once they are
                                                projected. In practice, it's pretty hard to make text too big. If you have a
                                                problem fitting what you want to say on the slide, perhaps you need to
                                                reconsider the phrasing.</p>
                                                
                                                <p>Aside from direct quotations, I find that it's rarely useful to have full
                                                paragraphs of text in your slides. You want your audience to be focused on
                                                <em>you</em>, not your slides. Think of the slides as simply the supporting cast to
                                                what you're telling the audience verbally. How can you craft your slides to
                                                complement what you're trying to convey?</p>
                                                
                                                <h2>Live Demos</h2>
                                                
                                                <p>Slides can only take us so far, especially for technical presentations.
                                                Sometimes we need to turn away from the "what", and explain the "how" of
                                                something. We want to demonstrate how something works. For coders, this often
                                                means a live coding or tool demonstration. If you're trying to convince your
                                                audience that technology XYZ is the greatest thing since sliced bread and will
                                                save them all sorts of time and headaches, you want to be able to <em>show</em> it,
                                                not just tell it.</p>
                                                
                                                <p>Fantastic. Good for you. Here's the problem: <em>live</em> coding demos are a recipe
                                                for disaster. I can't think of a better scenario that demonstrates Murphy's
                                                law than trying to execute a live coding demo. You may not have an internet
                                                connection (oops, there goes the ubiquitous twitter client demo). You may have
                                                installed some beta software on the plane ride out and, unknowingly, destroyed
                                                your development environment. The list of things that could go wrong is
                                                unbounded.</p>
                                                
                                                <p>The other problem with live demos is the switching in and out of the
                                                presentation software you're using. Not only is it visually jarring for the
                                                audience, but there is invariably some down-time as you switch displays and
                                                try to figure out which windows are where. Don't give your audience the
                                                opportunity to tune you out during these noisy transitions.</p>
                                                
                                                <p>So, just like you wouldn't create your slides on-the-fly as you present, you
                                                shouldn't demonstrate live without a net. Instead, record a video of it and
                                                embed it in your presentation. With a video you get a chance to edit out all
                                                of the hiccups and noise of the demonstration process. Mistyped something? Got
                                                a compilation error? Tools are running really slow for some reason? Great,
                                                just edit those frames out.</p>
                                                
                                                <p>Leaving these blemishes in only gives the third-grader part of your audience's
                                                brain time to sneak in and distract them. You want to keep your audience
                                                engaged with you every step of the way. Introducing these interruptions into
                                                the continuity of your presentation breaks the audience's concentration and your
                                                flow.</p>
                                                
                                                <p>Once you get your video captured and edited, practice speaking over it. Really
                                                make sure that what you say matches well with the video. Get the timing down
                                                and stay focused on what you're trying to show. Is there something you want to
                                                say that you isn't in the video? Get back in there and record the right video.
                                                Don't half-ass it. When you put the time in to make a good supporting video,
                                                you keep your audience longer.</p>
                                                
                                                <h3>Keynote Specifics</h3>
                                                
                                                <p><img src="/images/2010/04/keynote-video.png" alt="Video prefs in Keynote" class="right"/></p>
                                                
                                                <p>If you're using Apple's Keynote, here are a couple of tips. Once you've
                                                captured and edited your video, simply drag the video object onto a new slide.
                                                Open the inspector palette and select the last tab with the Quicktime logo on
                                                it. Select the checkbox labeled "Start movie on click". This way your video
                                                won't start running before you're ready to talk about it.</p>
                                                
                                                <div class="clear"></div>
                                                
                                                
                                                <p><img src="/images/2010/04/apple-remote.jpg" class="left"/> Also, with a stock
                                                Apple remote, you can pause and resume your video as needed. This is
                                                especially helpful when you have a multi-step process to explain that you want
                                                to cover in bite-sized chunks. This means that you should consider
                                                pause-points in your capture and editing process. Practicing your speech along
                                                with the video will help you figure out where the natural breakpoints are.
                                                Alternatively, you could split the process up into multiple videos on
                                                different slides.</p>
                                                
                                                <h2>Eschew Style</h2>
                                                
                                                <p>Customization and personal style are well and good. On your machine you should
                                                feel free to tweak every little setting to your heart's content. But, please,
                                                don't force these styles on your audience. Ditch the alpha blend on your
                                                terminal. Turn off your crazy four-line shell prompt. Pick a color theme in
                                                your editor that is easy to read in a large font. Pick a display font that is
                                                appropriate for large projection, not just what you prefer.</p>
                                                
                                                <p><img src="http://ecx.images-amazon.com/images/I/51toYiHF35L._SL500_AA300_.jpg" height="150" width="150" class="left"/></p>
                                                
                                                <p>Make those fonts BIG. Just like your regular speaking voice needs to be
                                                amplified to carry to the back of the room, so does the visual volume of your
                                                content. When recording your coding demos, pick unusually large font sizes and
                                                take up all of the screen. Also, when capturing your video, try to keep the
                                                capture frame focused on the essential parts of the demo. For example, if
                                                you're only editing text, don't clutter the video capture up with a toolbar
                                                full of things you won't use. Remember, keep it focused! Don't give your
                                                audience a chance to get distracted by clutter.</p>
                                                
                                                <div class="clear"></div>
                                                
                                                
                                                <h2>Keep It Focused</h2>
                                                
                                                <p>When presenting a technical topic, it can be frustrating having to jam a large
                                                amount of content into a small space. There's just so much to share! How can I
                                                possibly discuss Core Animation in forty-five minutes? The answer is, <em>you
                                                don't</em>. What you <em>can</em> do is give your audience a taste of the topic you're
                                                trying to present. Give them enough information for them to decide if they
                                                want to pursue more on their own. Give them enough terminology and background
                                                concepts to help them continue the journey.</p>
                                                
                                                <p>Presentations are <em>not</em> a good vehicle for in-depth training. Books or
                                                workshops are much more appropriate for real hands-on learning. Presentations
                                                are good at giving people a mental roadmap to get started. Get them excited
                                                by your topic, but don't exhaust them with it.</p>
                                            ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                Menu Bar Ghetto
                                            ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/' />
    <updated>2010-04-23T08:49:57-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/04/23/menubar-ghetto/</id>
    <content type='html'>
      <![CDATA[
                                                  <p>The menu bar has become a dumping ground. With each new application I install
                                                  another grubby child is dropped off at the doorstep of the orphanage known
                                                  as the OS X menu bar. This has simply got to stop.</p>
                                                  
                                                  <p><img src="/images/2010/04/status-bar.png"/></p>
                                                  
                                                  <p>Just look at that. Do you think that fits on anything but a large display? I
                                                  can't even see most of these icons on my built-in MacBook display. Only
                                                  humble little Finder, with its spartan set of menus, yields enough real
                                                  estate to display all of these items.</p>
                                                  
                                                  <p>Sadly, I had gotten into the habit of knowing which applications hid status
                                                  bar items from me and would automatically switch to Finder just to reveal
                                                  them. It was the classic mistake we all make of giving in to bad design
                                                  instead of addressing the problem.</p>
                                                  
                                                  <p>So I waged a small holy-war this morning to kick out all but the essential
                                                  applications from my status bar. I feel a little better that I've reclaimed
                                                  my territory, but can't help but feel frustrated that I'll have to do it
                                                  again soon. Why? Because, somehow, application developers got it in their
                                                  heads that they <em>all</em> have to have menu bar items.</p>
                                                  
                                                  <p>I want this to stop. Right now. Please. Do it for the children.</p>
                                                  
                                                  <p>I can't help but think that this reflects a dangerous attitude underlying a
                                                  lot of applications. Stop for a moment and think of the reasons why an
                                                  application provides a menu bar item. Menu bar items exist for applications
                                                  running in the background. These come in two flavors: applications with no
                                                  other user interface (like a window or a preference pane), and ones that do.I
                                                  don't have much of a beef for the ones that can only provide a menu bar item
                                                  as their sole interaction mechanism. It's the applications that <em>do</em> have a
                                                  main UI that I want to give a stern talking-to.</p>
                                                  
                                                  <p>In a windowing system users get to choose what they focus on (save for a few
                                                  cases with alerts and modal dialogs and such). Applications are supposed to do
                                                  the bidding of the user. When I switch away from application XYZ, it means I
                                                  have something more important I need to do. Having that application pop back
                                                  in my face drives me nuts. It drives everyone nuts. I think most folks would
                                                  agree that this is a Bad Experience.</p>
                                                  
                                                  <p>But some applications want to keep your attention. So they compromise by
                                                  creating a little persistent bit of goo and sticking it in the menu bar.
                                                  Because these apps are <em>so fabulous</em>, how could you not want them around all the
                                                  time?</p>
                                                  
                                                  <p>The best menu bar items are ones that provide the essential capabilities of
                                                  the application <em>and</em> give you a quick way to expand to the full application.
                                                  I run iStat menus because it gives me a lot of information in the small
                                                  space it takes up. Why is my machine so slow? Ah, the CPUs are pegged. Why
                                                  are they pegged? Well, just click the menu item and see that application XYZ
                                                  is taking up 90% of my cycles. It's a great example progressive disclosure.</p>
                                                  
                                                  <p>Some applications like <a href="http://www.shinywhitebox.com/home/home.html" title="iShowU">iShowU</a> or <a href="http://www.realmacsoftware.com/littlesnapper/" title="Little Snapper">Little Snapper</a> provide a menu bar item because they need to get out of your
                                                  way. You don't want to screen capture the screen capture tool itself, right?
                                                  For these kinds of apps that provide functionality that spans multiple
                                                  applications, I think this is okay.</p>
                                                  
                                                  <p>What I can't stand are applications that provide a menu bar item, then keep it
                                                  there after I've quit the application. <a href="http://www.evernote.com" title="Evernote">Evernote</a> is a good example of this. You have to <em>really</em> go out of your way
                                                  to make Evernote not do this. Worse yet, its default behavior is to install
                                                  itself as a startup item so that it's sitting there in your menu bar until you
                                                  take time out of your busy day to turn it off. Boo. Hiss.</p>
                                                  
                                                  <p>I like Evernote quite a bit, but I get the impression its creators think it's
                                                  so special that it deserves to be in your face, all the time. It's like that
                                                  annoying guy you got stuck talking to at the company party that you can't rid
                                                  yourself of. Go away.</p>
                                                  
                                                  <p>The worst case of this is VMWare. I can't, for the life of me, figure out how
                                                  to disable VMWare's menu bar item. For folks that need to run a lot of non-Mac
                                                  apps I can see the advantage. The Unity stuff in VMWare is pretty freaking
                                                  cool. But if you're <em>not</em> one of those people, it's pretty rude to have this
                                                  whole other application-launcher sitting there, taking up space, that you only
                                                  occasionally use. Shame on you VMWare. I'm happy to pay for a license because
                                                  I think it's a great product, but that doesn't mean I want to see your
                                                  goddamned menu item in my status bar all the time.</p>
                                                  
                                                  <p>So if you're building a Mac application and considering a menu bar item,
                                                  please consider the following advice. If you're building a background utility
                                                  with no other UI, think hard about how much the user needs to interact with
                                                  your application. Is it something they need to fiddle with more than once a
                                                  session? If not, try to make a Preference Pane and leave it at that. If it's
                                                  something the user is going to use a lot, or displays some kind of realtime
                                                  information (à la iStat menus) then adding to the menu bar is okay.</p>
                                                  
                                                  <p>If you're building an application with a main UI component, think long and
                                                  hard about the necessity of menu bar item. If it can integrate with other
                                                  applications (like Little Snapper) there's a reasonable case to be made for
                                                  providing a menu bar item. Even then, you should consider providing a Services
                                                  menu item and/or a global keyboard shortcut. This is an especially good idea
                                                  if your application only provides one or two actions that users can take. It's
                                                  hard to justify a two-item menu bar item, so sometimes you see applications
                                                  put other non-essential items in there like Preferences or an About dialog.
                                                  Don't do this.</p>
                                                  
                                                  <p>For these sorts of applications, the menu bar item should <em>always</em> be
                                                  optional. The app should still be able to do what it needs to without having
                                                  that menu bar item enabled. Also, leave it off by default and make it easy for
                                                  the user to turn it on. Make it an opt-in feature rather than an opt-out
                                                  feature. As much as I love Tweetie, the opt-out nature of its menu bar item is
                                                  the kind of stuff that drives me nuts. The option is enabled (or not
                                                  disabled?) and the language is confusing. Worse yet, it doesn't take effect
                                                  until you restart the application.</p>
                                                  
                                                  <p><img src="/images/2010/04/tweetie-prefs.png"/></p>
                                                  
                                                  <p>Finally, unless you have some kind of special papal dispensation, never, ever,
                                                  ever keep your menu bar item running when the application is gone. OK,
                                                  technically if there's a menu bar item the application is still running, but
                                                  that's a distinction that user's don't care about (nor should they have to).</p>
                                                  
                                                  <p>There's been a long, ongoing debate about the necessity of optimizing the
                                                  performance of applications. As horsepower has increased, programmers have
                                                  been afforded some laziness in optimizing their applications. I only have a
                                                  problem with that in extreme cases because hardware power has increased at
                                                  such an impressive rate. However, our displays aren't growing at the same
                                                  rate. We need to treat that screen real estate as precious. The menu bar is a
                                                  great place to put global, cross-application functionality, but there's only
                                                  so much space for all of these applications. Think long and hard about the
                                                  necessity of taking up that space and always put the power in the users' hands
                                                  to choose.</p>
                                              ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                  Thanks, mom
                                              ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/04/17/thanks-mom/' />
    <updated>2010-04-17T20:23:21-07:00</updated>
    <id>http://alexvollmer.com/posts/2010/04/17/thanks-mom/</id>
    <content type='html'>
      <![CDATA[
                                                    <p>It's been a while since I last posted. Normally I wouldn't preface a post with
                                                    that (it drives me crazy when I read it elsewhere), but my world changed
                                                    completely last month when, on March 5th, my mom unexpectedly passed
                                                    away. I found out the following morning, and things haven't been the same
                                                    ever since.</p>
                                                    
                                                    <p><img class="left" src="/images/2010/04/rosebowl.jpeg" title="My last day with mom at the 2010 Rose Bowl"/></p>
                                                    
                                                    <p>Since her death, I've been tossed into the deep-end of estate-management as
                                                    I try to clean up the remnants of her financial and legal life. It's amazing
                                                    how much a person leaves behind. There are all sorts of things to clean up like
                                                    calling her dentist and canceling a pending appointment, or telling the local
                                                    pharmacy that she won't ever be coming in again to pick up her prescription.</p>
                                                    
                                                    <p>In the last month, I've realized I'm not the same person I used to be. It sounds
                                                    trite, but this event has given me a serious perspective
                                                    adjustment. Things that used to seem scary to me now seem insignificant.
                                                    Things I always wanted to do but put off for some day in the future, get
                                                    addressed now. Life is short. You never know what can happen.</p>
                                                    
                                                    <p>By nature, my wife and I inveterate planners. My god, I started an IRA when
                                                    I was 21. Who the hell does that? But now it's time to think more about
                                                    the present. We haven't completely abandoned our careful planning, but we've
                                                    stopped putting off things we want to do.</p>
                                                    
                                                    <p>One of those things has been a growing desire to be my own boss. For
                                                    the longest time I could never imagine running my own show. There was
                                                    too much work, stress and responsibility. I was happy trading independence for
                                                    the comfort and security of a steady paycheck. But over the last few years
                                                    I've been feeling a deep and acute dissatisfaction working for someone else.
                                                    I came to the conclusion that I wasn't going to be happy until I stopped
                                                    working on other people's ideas and took a shot (or two) at working on my own.</p>
                                                    
                                                    <p>So now it's time to stop being so unhappy about it. As of May, I'm on my own.
                                                    My plan is to build a small product-development company. I don't need to make
                                                    scads of money, I just want to support my family. I want to work on things that
                                                    I deeply care about. I want to spend my time doing things that matter to me,
                                                    and as little time as possible on "shoulds", "musts", and "have-tos". I'll
                                                    pick up contracting work as needed (tell all your friends),
                                                    but the long-term plan is to live off of product revenue. I guess some people
                                                    might call it a "lifestyle business". I call it dropping out of the rat-race
                                                    and living the life more fully.</p>
                                                    
                                                    <p>How am I going to do this? What's my plan? Beats the hell out of me. I'll
                                                    figure it out as I go. All I know is that everything I've gone through in the
                                                    last month has made me realize that it's going to work out fine. There's
                                                    nothing that could happen that would equal what I've recently gone through.</p>
                                                    
                                                    <p>So what about the title of this post? What exactly am I so thankful for?
                                                    Well, certainly not about the loss of my mother. Nothing could replace her.
                                                    Nothing will bring her back. She was my moral compass. She was the greatest
                                                    teacher I ever had. I didn't really appreciate the tools she left me with
                                                    until she was gone. Now I realize that she left me with everything I needed
                                                    to cope with this tragedy as well as being able to move beyond it. I don't
                                                    know if I would ever have been shaken out of my day-to-day routine without her
                                                    loss. I wouldn't trade this epiphany for her, but I don't have that option.
                                                    What I can do is move forward and live a life that honors her memory.</p>
                                                    
                                                    <p>My mom was a survivor. She survived the breakup of my family. She survived
                                                    cancer. She survived my brother's death. After her divorce she rebuilt her
                                                    life from scratch, eventually becoming an assistant Dean at the School of
                                                    Education at the University of Oregon. Her crowning achievement was completion
                                                    of school's new building on the U of O campus. Over the span of nearly a decade
                                                    she raised funds from private donors&mdash;mostly teachers. But the final
                                                    dollar amount isn't what's impressive about her work. What's impressive is
                                                    how she took a group of people, turned them into a community and got them to
                                                    believe in themselves. Mom, I wish I could have told you just how proud I am
                                                    of you.</p>
                                                    
                                                    <p>So, mom, this life is for you. You always had a strong independent streak. You
                                                    didn't get a chance to enjoy the future that you worked so hard for. You
                                                    gave me so much. The best way I can think to pay it back, is to live the life
                                                    you would have wanted for me, and to pass that on to my daughter.</p>
                                                    
                                                    <p>Thanks, mom. Thank you, so very much.</p>
                                                ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                    Scripting Build Selection in Xcode
                                                ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/' />
    <updated>2010-03-06T00:20:30-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/03/06/scripting-build-selection-in-xcode/</id>
    <content type='html'>
      <![CDATA[
                                                      <p>When I'm doing iPhone development, I constantly
                                                      switch between running on the device and the simulator. As far
                                                      as I can tell, Xcode doesn't provide an easily-accessible keyboard
                                                      shortcuts for switching between SDKs. Since I <em>hate</em> breaking up my flow by
                                                      having to reach for the mouse, I put together a couple of
                                                      AppleScripts that bind hot-keys to switching between SDKs. Download
                                                      these two scripts to wherever you like to store your AppleScripts.
                                                      I like to put mine in <code>~/Library/Scripts</code>.</p>
                                                      
                                                      <p>First, is the script that selects the SDK for the device:</p>
                                                      
                                                      <div>
                                                      <a href="/files/SwitchToDevice.scpt" class="attachment">
                                                        SwitchToDevice.scpt
                                                      </a>
                                                      
                                                      
                                                      <div class="highlight"><pre><span class="k">tell</span> <span class="nb">application</span> <span class="s2">&quot;Xcode&quot;</span>&#x000A;      <span class="k">set</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="na">active</span> <span class="nv">project</span> <span class="na">document</span>&#x000A;      <span class="k">set</span> <span class="na">active</span> <span class="nv">SDK</span> <span class="k">of</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="s2">&quot;iphoneos3.1.3&quot;</span>&#x000A;    <span class="k">end</span> <span class="k">tell</span>&#x000A;    </pre>
                                                      </div>
                                                      
                                                      </div>
                                                      
                                                      
                                                      <p>Next up, the script that selects the simulator SDK:</p>
                                                      
                                                      <div> 
                                                      <a href="/files/SwitchToSimulator.scpt" class="attachment">
                                                        SwitchToSimulator.scpt
                                                      </a>
                                                      
                                                      
                                                      <div class="highlight"><pre><span class="k">tell</span> <span class="nb">application</span> <span class="s2">&quot;Xcode&quot;</span>&#x000A;      <span class="k">set</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="na">active</span> <span class="nv">project</span> <span class="na">document</span>&#x000A;      <span class="k">set</span> <span class="na">active</span> <span class="nv">SDK</span> <span class="k">of</span> <span class="nv">myProject</span> <span class="k">to</span> <span class="s2">&quot;iphonesimulator3.1.3&quot;</span>&#x000A;    <span class="k">end</span> <span class="k">tell</span>&#x000A;    </pre>
                                                      </div>
                                                      
                                                      </div>
                                                      
                                                      
                                                      <p>Now, open up Xcode and and select "Edit User Scripts..." in the
                                                      scripts menu:</p>
                                                      
                                                      <p><img src="/images/2010/02/xcode-script-menu.png" class="plain"/></p>
                                                      
                                                      <p>This opens the script organizer. In the left-hand pane is a list of
                                                      all the script groups. Which group you put a script in effects what
                                                      submenu they are available from in the main scripts menu. But we like
                                                      shortcut keys so who cares where it goes? I put these in the "Build"
                                                      group, but feel free to put them wherever makes the most sense to
                                                      you. Select the group you want to add these scripts to and click the "+"
                                                      button and choose "Add Script File&hellip;":</p>
                                                      
                                                      <p><img src="/images/2010/02/edit-user-scripts-dropdown.png" class="plain"/></p>
                                                      
                                                      <p>Use the standard Finder dialog to find the scripts you just downloaded
                                                      and select one of them. To set the shortcut key for the script,
                                                      double-click the right-hand column of the newly-added script. For the
                                                      simulator script I use <code>⌃⌘⎇S</code> and <code>⌃⌘⎇D</code> for the device script. You
                                                      can try out different combinations. If you come up with a key-chord
                                                      that clobbers an existing key-binding Xcode will give you a warning at
                                                      the bottom of the window.</p>
                                                      
                                                      <p><img src="/images/2010/02/edit-user-scripts-warning.png" class="plain"/></p>
                                                      
                                                      <p>One thing to be aware of is that while you're setting the shortcut
                                                      key for the script <em>all</em> of your keyboard input is directed to that
                                                      field. So you can't use ESC to cancel or Enter to set the value. You
                                                      need to grab that infernal mouse and click somewhere else.</p>
                                                      
                                                      <p>Before you close the dialog, be sure to set the "Output" drop-down
                                                      menu to "Discard Output" otherwise Xcode will paste some odd gibberish
                                                      into your current file. And, just in case there's some kind of
                                                      unforseeable error, set "Errors" drop down to "Display in Alert". Once
                                                      you have both scripts configured you can close the dialog and try your
                                                      new hot-keys out.</p>
                                                      
                                                      <p>I don't claim to have any proficiency with AppleScript, so there
                                                      may very well be a better way to do this. Certainly one thing that is
                                                      brittle about these scripts is how they are hard-coded to a particular
                                                      version of the SDK. Whenever a new SDK is released I'll have to update
                                                      the strings in the script. Oh well, it beats having to reach for the
                                                      mouse several more times a day.</p>
                                                  ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                      RVM meets zsh
                                                  ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/' />
    <updated>2010-02-27T17:19:45-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/02/27/rvm-meets-zsh/</id>
    <content type='html'>
      <![CDATA[
                                                        <p><a href="http://rvm.beginrescueend.com/">RVM</a> is a nifty tool for managing
                                                        multiple ruby installations. Not only does it make it easy to install
                                                        and switch between multiple rubies, but you can also install
                                                        gems without <code>sudo</code> access. But, as great as RVM is, I still have to
                                                        remember to switch between rubies and often I don't remember to do it
                                                        until I see some weird behavior or a test breaks. I'm very lazy and
                                                        I want even <em>more</em>.</p>
                                                        
                                                        <p>So I've setup a tiny bit of zsh-fu to automatically switch which ruby
                                                        implementation to use based on the directory that I'm in. To do this, one
                                                        needs to take advantage of <a href="http://zsh.sourceforge.net/Doc/Release/Functions.html#SEC45">zsh's
                                                        hooks</a>,
                                                        particular the one invoked when you change directories. By default,
                                                        you can simply declare a function named <code>chdir()</code> and it will
                                                        automatically be invoked whenever you change directories. Mine looks
                                                        like this:</p>
                                                        
                                                        <div class="highlight"><pre>chpwd<span class="o">()</span> <span class="o">{</span>&#x000A;        <span class="o">[[</span> -t 1 <span class="o">]]</span> <span class="o">||</span> <span class="k">return</span>&#x000A;    <span class="k">    case</span> <span class="nv">$TERM</span> in&#x000A;          sun-cmd<span class="o">)</span> print -Pn <span class="s2">&quot;\e]l%~\e\\&quot;</span>&#x000A;            ;;&#x000A;          *xterm*|rxvt|<span class="o">(</span>dt|k|E<span class="o">)</span>term<span class="o">)</span> print -Pn <span class="s2">&quot;\e]2;%3~\a&quot;</span>&#x000A;            ;;&#x000A;        <span class="k">esac</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>This function just prints out the name of the directory I've change
                                                        into and it's found in a lot of zsh distributions. To keep things clean
                                                        I want to have a separate function that just manages the RVM
                                                        updating. For the moment, let's ignore the fact that I already have an
                                                        existing <code>chdir()</code> function, and look at the hook function I created
                                                        to invoke RVM:</p>
                                                        
                                                        <div class="highlight"><pre>chpwd_check_rvm<span class="o">()</span> <span class="o">{</span>&#x000A;        <span class="nv">current_version</span><span class="o">=</span><span class="k">$(</span>rvm info | grep <span class="s2">&quot; version:&quot;</span> | cut -d <span class="s1">&#39;&quot;&#39;</span> -f2<span class="k">)</span>&#x000A;        <span class="nv">dir</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>&#x000A;        <span class="k">while</span> <span class="o">[</span> <span class="s2">&quot;${dir}&quot;</span> !<span class="o">=</span> <span class="s2">&quot;&quot;</span> <span class="o">]</span>; <span class="k">do</span>&#x000A;    <span class="k">        </span><span class="nv">cfg</span><span class="o">=</span><span class="s2">&quot;${dir}/.rvminfo&quot;</span>&#x000A;            <span class="k">if</span> <span class="o">[</span> -f <span class="k">${</span><span class="nv">cfg</span><span class="k">}</span> <span class="o">]</span>; <span class="k">then</span>&#x000A;    <span class="k">            </span><span class="nv">want_version</span><span class="o">=</span><span class="k">$(</span>cat <span class="k">${</span><span class="nv">cfg</span><span class="k">})</span>&#x000A;                <span class="k">if</span> <span class="o">[</span> <span class="s2">&quot;${want_version}&quot;</span> !<span class="o">=</span> <span class="s2">&quot;${current_version}&quot;</span> <span class="o">]</span>; <span class="k">then</span>&#x000A;    <span class="k">                </span>rvm use <span class="k">${</span><span class="nv">want_version</span><span class="k">}</span>&#x000A;                <span class="k">fi</span>&#x000A;    <span class="k">            </span><span class="nb">break</span>&#x000A;    <span class="nb">        </span><span class="k">else</span>&#x000A;    <span class="k">            </span><span class="nv">dir</span><span class="o">=</span><span class="k">${</span><span class="nv">dir</span><span class="p">%/*</span><span class="k">}</span>&#x000A;            <span class="k">fi</span>&#x000A;    <span class="k">    done</span>&#x000A;    <span class="o">}</span>&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>This function looks for a file named <code>.rvminfo</code> in the current
                                                        directory (this function is invoked <em>after</em> we've changed
                                                        directories). If the file isn't found in the new directory, it searches
                                                        upward through each parent directory to see if it can find one. If
                                                        it's found, the function invokes <code>rvm use</code> with the version string
                                                        found in that file.</p>
                                                        
                                                        <div class="highlight"><pre><span class="nv">$ </span>cat .rvminfo&#x000A;    1.8.6&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>There's also some additional checking to avoid extra <code>rvm</code> invocations
                                                        if we're already set to the desired version. This is done more to
                                                        reduce the chatter in the shell than for performance reasons.</p>
                                                        
                                                        <p>Now let's get back to invoking multiple hook functions.
                                                        If you have more than one function you'd like to have called when
                                                        you change directories, you can declare these in an array named
                                                        <code>chpwd_functions</code>. After declaring the <code>chpwd_check_rvm()</code> function
                                                        above, having two functions for the <code>cd</code> hook is trivial. I just add
                                                        this declaration to my <code>~/.zshrc</code> file:</p>
                                                        
                                                        <div class="highlight"><pre><span class="c">#--- chpwd_functions</span>&#x000A;    <span class="nv">chpwd_functions</span><span class="o">=(</span> chpwd_check_rvm chpwd <span class="o">)</span>&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>Now, whenever I change into a directory with a <code>.rvminfo</code> file, my
                                                        hooks are automatically executed and I get the right ruby version:</p>
                                                        
                                                        <div class="highlight"><pre><span class="o">[</span>island<span class="o">]</span> ~/Development: <span class="nb">cd </span>alexvollmer.com &#x000A;    &lt;i&gt; Now using ruby 1.8.6 p383 &lt;/i&gt;&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>One final note is that I put all of my specific functions in the
                                                        <code>~/.zsh/functions</code> directory, and automatically load all of them in my
                                                        <code>~/.zshrc</code> file with the snippet below. I do all of this <em>before</em> I
                                                        declare the <code>chpwd_functions</code> array.</p>
                                                        
                                                        <div class="highlight"><pre><span class="c">#--- Shell Functions ---</span>&#x000A;    <span class="c">#</span>&#x000A;    fpath+<span class="o">=(</span>&#x000A;      <span class="k">${</span><span class="nv">HOME</span><span class="k">}</span>/.zsh/functions&#x000A;    <span class="o">)</span>&#x000A;    &#x000A;    autoload -U ~/.zsh/functions/*<span class="o">(</span>:t<span class="o">)</span>&#x000A;    </pre>
                                                        </div>
                                                        
                                                        
                                                        <p>You may want to organize your functions differently. Just be aware
                                                        that zsh needs to know about your functions before you can put them in
                                                        the <code>chpwd_functions</code> array.</p>
                                                        
                                                        <p><em>UPDATE (3/1/2010):</em> Per comments below from RVM's creator, Wayne Seguin, RVM
                                                        actually comes with it's own built-in way of handling this. Somehow I
                                                        completely missed <a href="http://rvm.beginrescueend.com/workflow/rvmrc/">the rvmrc
                                                        documentation</a> for this
                                                        feature (how embarassing!). I'm usually inclined to avoid re-inventing
                                                        the wheel, but there are two small things I like about the way I
                                                        implemented this. First, the solution proposed here doesn't redefine
                                                        the <code>cd</code> command, which feels a bit like duck-punching the shell to
                                                        me. I don't know if bash has the same kind of hooks that zsh does, so
                                                        the implementation is understandable. As for me, I like the hooks
                                                        better.  Second, the solution I show here works for any sub-directory
                                                        within a project that has a specific RVM setting. That said, I'll
                                                        probably just use what's already been implemented in RVM.</p>
                                                    ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                        Static Cling
                                                    ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/02/22/static-cling/' />
    <updated>2010-02-22T17:40:40-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/02/22/static-cling/</id>
    <content type='html'>
      <![CDATA[
                                                          <p>Lord knows why, but in the last couple of months I felt compelled to
                                                          move off of Wordpress and onto one of those new static content
                                                          generators for this site. Part of it was motivated by getting fed up
                                                          with constantly upgrading Wordpress. I suppose another part of it was
                                                          because all the <a href="http://userprimary.net">cool</a>
                                                          <a href="http://davepeck.org/">kids</a> were doing it. But, most importantly,
                                                          I wanted to give the site design a reboot&mdash;something I did <em>not</em>
                                                          want to do in PHP in the form of Wordpress themes. So with a little
                                                          help from <a href="http://whole-studios.com/">a friend</a>, this site got a
                                                          facelift and a new platform to boot.</p>
                                                          
                                                          <p>I chose to use <a href="http://nanoc.stoneship.org">Nanoc</a> as the
                                                          site-generator. Originally I was going to go with
                                                          <a href="http://github.com/mojombo/jekyll">Jekyll</a>. I really liked its
                                                          simplicity and the fact that it had prescribed locations for
                                                          everything. However, I still wanted to maintain some
                                                          backward-compatability with the old site. This meant a little bending
                                                          of Jekyll's rules and, frankly, Jekyll just isn't as configurable and
                                                          flexible as Nanoc. That's not a dig against Jekyll, nor is it an
                                                          endorsement of Nanoc. Nanoc is a general-purpose solution for
                                                          generating static sites, but it's not necessarily optimized for
                                                          blogging. But with Nanoc I can use HAML, SASS and other Rails-isms
                                                          with which I'm already familiar. If you want to see the gory details,
                                                          I've put the whole thing up on
                                                          <a href="http://github.com/alexvollmer/alexvollmer.com">GitHub</a>.</p>
                                                          
                                                          <p>Sadly, this ended up taking much longer than I anticipated.
                                                          First, I had to import the old posts from Wordpress. The database
                                                          schema for Wordpress is pretty wacky looking when you're used to
                                                          working with Rails. Thankfully, Jekyll already gone down this path and
                                                          I used their Wordpress importer as inspiration for writing my
                                                          own. Along the way I discovered what great gem
                                                          <a href="http://rubygems.org/gems/sequel">Sequel</a> is. A large part of the
                                                          importing process was converting from all of the jacked-up formats
                                                          I've amassed over the years to Markdown. It took a <em>lot</em> of iterations
                                                          to catch every weird character-encoding and formatting issue.</p>
                                                          
                                                          <p>Another large effort was creating the RSS feeds. Now Nanoc has <em>some</em>
                                                          support for Atom, but it didn't quite do what I wanted. I was trying
                                                          to match what Wordpress was generating for me so I basically
                                                          re-implemented feed-generation from scratch.</p>
                                                          
                                                          <p>Moving old comments into <a href="http://disqus.com">Disqus</a> took about
                                                          a week to get right. As a user, the Disqus service is pretty
                                                          cool. As a web API, it's a little&hellip;ahem&hellip; lacking. If
                                                          you're used to well-constructed REST APIs, you'd best drink something
                                                          stiff before settling in with the <a href="http://groups.google.com/group/disqus-dev/web/api-1-1">API
                                                          docs</a>. The
                                                          <a href="http://github.com/norman/disqus">disqus gem</a> borders on useless. So,
                                                          I ended having to write my own importer with httparty. It took several
                                                          iterations to really get this nailed and the process was pretty
                                                          frustrating.</p>
                                                          
                                                          <p>The sad part about this, is that originally I was on the fence about
                                                          adding comments at all. Initially I thought I'd try it out and see if
                                                          I liked it. But I'm a geek, right? I couldn't get it working right
                                                          away and it drove me nuts! I <em>had</em> to figure it out. So eventually I
                                                          figured out the magic recipe, and now I'm wondering if I even really
                                                          wanted comments integrated at all. Oh well.</p>
                                                          
                                                          <p>One trick that I found very helpful throughout this process was
                                                          creating some scripts that dropped me into an IRB session with the
                                                          Nanoc blog or Disqus API objects already initialized. This was
                                                          inspired by the Rails console which I find invaluable for tinkering with
                                                          things in real-time. For example, while I was dickering with the Nanoc
                                                          internals, I found this console script to be quite helpful:</p>
                                                          
                                                          <div class="highlight"><pre><span class="c1">#!/usr/bin/env ruby</span>&#x000A;    &#x000A;    <span class="nb">require</span> <span class="s2">&quot;irb&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;rubygems&quot;</span>&#x000A;    <span class="nb">require</span> <span class="s2">&quot;nanoc3&quot;</span>&#x000A;    <span class="nb">load</span> <span class="s2">&quot;lib/helpers.rb&quot;</span>&#x000A;    &#x000A;    <span class="vi">@site</span> <span class="o">=</span> <span class="no">Nanoc3</span><span class="o">::</span><span class="no">Site</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>&#x000A;    <span class="vi">@site</span><span class="o">.</span><span class="n">load_data</span>&#x000A;    &#x000A;    <span class="no">IRB</span><span class="o">.</span><span class="n">start</span>&#x000A;    </pre>
                                                          </div>
                                                          
                                                          
                                                          <p>Now, Wordpress and I differ on what constitutes a sensible URL
                                                          scheme. So that last bit I needed was to concoct some redirect rules
                                                          to port the old URL scheme to the new one. Currently, this site is
                                                          hosted on <a href="Dreamhost">http://dreamhost.com</a> which, provides support
                                                          for <code>.htaccess</code> files. With a little Apache-fu I was able to get most
                                                          of the old WP URLs to redirect correctly:</p>
                                                          
                                                          <div class="highlight"><pre>RewriteEngine ON&#x000A;    RewriteRule ^index.php/feed/ /feeds/rss_2_0.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/feed/rss/ /feeds/rss_0_9_2.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/feed/atom/ /feeds/atom.xml <span class="o">[</span>R<span class="o">]</span>&#x000A;    RewriteRule ^index.php/<span class="o">(</span>.*<span class="o">)</span> /posts/<span class="nv">$1</span> <span class="o">[</span>R<span class="o">]</span>&#x000A;    &#x000A;    ErrorDocument 404 /missing.html&#x000A;    </pre>
                                                          </div>
                                                          
                                                          
                                                          <p>Well, that took longer than I thought. I can't say that it wasn't
                                                          educational. Now, what was I <em>supposed</em> be doing?</p>
                                                      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                          The iPad
                                                      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/31/the-ipad/' />
    <updated>2010-01-31T08:12:05-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/01/31/the-ipad/</id>
    <content type='html'>
      <![CDATA[
                                                            <p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/IPad-01.jpg/250px-IPad-01.jpg" alt="iPad" class="left">
                                                            After letting the dust settle around Apple's announcement of the iPad,
                                                            I wanted to take a more measured, less reactionary look at the new
                                                            device. The coverage that immediately followed the announcement was
                                                            even more biased to both extremes than coverage of the President's
                                                            State of the Union address which occurred the same day. I know that
                                                            there's a growing body of folks who just don't like Apple, but I was
                                                            surprised at the level of antipathy.</p>
                                                            
                                                            <p>Those that damned the iPad seemed to come in two flavors: those that
                                                            saw the iPad as the embodiment of corporate greed and walled gardens,
                                                            and those that thought the device didn't measure up to their personal
                                                            expectations.</p>
                                                            
                                                            <p>There is a sizable (and growing) population of folks that simply will not
                                                            purchase an Apple product or participate in its eco-system for
                                                            various reasons. I think that's fine. While I personally enjoy their
                                                            products, I don't believe that everyone has to agree with me. I get no
                                                            less enjoyment out of my MacBook or iPhone by someone else having a
                                                            Lenovo ThinkPad or an Android Phone.</p>
                                                            
                                                            <p>Unfortunately, that view isn't shared by many. Take the flame-baiting
                                                            in the aftermath of the iPad announcement and replace the term "iPad"
                                                            with "gay marriage" and the arguments look nearly identical. Gay
                                                            marriage is so upsetting to conservatives that they can't imagine
                                                            being in a world where it exists. It's not that gays are coming into
                                                            their homes and performing unspeakable acts, it's that they can't
                                                            imagine <em>even being on the same planet with them</em>. So it goes with the
                                                            iPad&mdash;there are the FSF types who can't imagine living in a world
                                                            where Apple controls every single thing that goes on a device.</p>
                                                            
                                                            <p><img
                                                            src="http://cache.gawker.com/assets/images/jalopnik/2009/02/obama-state-of-the-union.jpg"
                                                            alt="The Prez" class="left" style="height: 162px; width: 293px;"/>
                                                            I'm not aware of anything in the President's address that said every
                                                            man, woman and child in the U.S. was going to be forced to use an
                                                            iPad. As far as I know, people are still free to choose whether or not
                                                            they wish to purchase and iPad and wander about in Apple's walled
                                                            garden. Don't want an iPad? <em>Fabulous</em>. Don't buy one.</p>
                                                            
                                                            <p>Folks, it's a <em>big</em> world out there. There doesn't have to be a single
                                                            winner. Even as Apple trumpets having over 50 million touch devices,
                                                            that pales in comparison to the worldwide population of those who
                                                            <em>could</em> afford such devices. That's even without considering the fact
                                                            that if you own one iPod/iPhone, you probably own another. In terms of
                                                            real numbers, I don't see a growing "collectivization" movement to dress
                                                            everyone in Apple products. If Apple were interested in market share,
                                                            they would charge a lot less for their products.</p>
                                                            
                                                            <p><a href="http://arstechnica.com/tech-policy/news/2010/01/protestors-ipad-is-nothing-more-than-a-golden-calf-of-drm.ars">
                                                            <img
                                                            src="http://static.arstechnica.com/01-27-2010/apple-ipad-protest.jpg"
                                                            alt="iPad Protest" class="right" style="width: 132px; height: 202px;"/>
                                                            </a>
                                                            Besides calling the iPad a freedom-killer, the other category of
                                                            critiques were that the device was simply disappointing. This reaction
                                                            particularly surprises me. Yes, there are certainly quibbles to make
                                                            about various features of the device (no camera, no multitasking,
                                                            etc.) but the dismissive observations that the iPad is simply "a big
                                                            iPhone" I think misses the point. Yeah, it <em>is</em> a big iPhone, which
                                                            has been a huge success by any measurement. If you love the iPhone,
                                                            then the things you most wish it had were more of are screen
                                                            real-estate and speed. So making one that is bigger and faster is
                                                            totally logical. What did people expect? Roomba integration? A
                                                            toaster? 3D goggles?</p>
                                                            
                                                            <div style="clear: both;"></div>
                                                            
                                                            
                                                            <p>ReadWriteWeb attempted to
                                                            <a href="http://www.readwriteweb.com/archives/how_to_hate_the_ipad_a_break-down_of_the_backlash.php#more" title="How to Hate the iPad: A Break-Down of the Backlash">break down the
                                                            anger</a>
                                                            with this graph:</p>
                                                            
                                                            <p><a href="http://www.tweetpad.com" title="TweetPad"><img src="http://www.readwriteweb.com/images/NegativeiPadStory.jpg" alt="" /></a></p>
                                                            
                                                            <p>Looking at this chart, I would categorize 38% of the complaints as
                                                            just pure snark. The next 27% that dismiss it as a "big iPhone" are
                                                            missing the point. The remaining complaints are all valid and worth
                                                            talking about a bit:</p>
                                                            
                                                            <h3>No Flash</h3>
                                                            
                                                            <p>Hooray, I say. I don't run Flash on my desktop or laptop if I can help
                                                            it. I simply do not like Flash. It rarely enhances my experience on a
                                                            site and often pegs my CPUs for no good reason. Yes, <a href="http://theflashblog.com/?p=1641">I'm aware that
                                                            Adobe has to do a lot of video codec work without the aid of
                                                            hardware</a>, but that doesn't address
                                                            the jarring user experience that is Flash. I have not missed Flash on
                                                            the iPhone either. If you want Flash, don't buy a iPod, iPhone or
                                                            iPad. It's as simple as that.</p>
                                                            
                                                            <p>Oh, and if you're running a Mac and feel the same way, do yourself a
                                                            favor and install the <a href="http://rentzsch.github.com/clicktoflash/">Click to Flash
                                                            plugin</a>, which lets you
                                                            ignore Flash on the web completely.</p>
                                                            
                                                            <h3>No Multitasking</h3>
                                                            
                                                            <p>I'm on the fence about this one. I'm not convinced that multi-tasking
                                                            is essential for a device like the iPhone or the iPad. The truth is, I
                                                            have not had many instances where I thought, "Damn! If only I could
                                                            run two apps at once!" I think a lot of people <em>think</em> they want it
                                                            because their computer has this capability.</p>
                                                            
                                                            <p>I think that's the point that is being missed. The iPad is not, in any
                                                            way, being put forth as a general computing device. In fact, to
                                                            categorize it as a "tablet PC" is to completely misunderstand the
                                                            iPad's underlying design philosophy. When I watched the presentation
                                                            and demonstration video what I saw was easy execution of tasks. Nobody
                                                            was demonstrating bit-rates, frames-per-second, or tail-call
                                                            optimization. The underlying technology and "platform" are simply the
                                                            means to an end.</p>
                                                            
                                                            <p>This is a different enough device that people will have to change
                                                            their thinking about their relationship with their computers. I don't
                                                            think it means a comprimising relationship, but one that is different
                                                            from today. Fraser Speirs eloquently called the inability to
                                                            comprehend this shift as <a href="http://speirs.org/blog/2010/1/29/future-shock.html">Future
                                                            Shock</a>.</p>
                                                            
                                                            <h3>Lock-In</h3>
                                                            
                                                            <p>Another major complaint of the iPad and the entire Apple/iTunes
                                                            ecosystem is that it is a closed system. Users don't get to mix and
                                                            match devices freely from other manufacturers. The party-line from
                                                            Apple is that they want to control every aspect to provide the best
                                                            user experience. Detractors argue that it is part of Apple's plan to
                                                            own all of your content like Big Brother (as Microsoft has attempted
                                                            to in the past).</p>
                                                            
                                                            <p>I get why people feel uncomfortable with handing Apple control of
                                                            their stuff. Personally, I have a lot of Apple products in my house
                                                            and I'm happy to give them that control because, for me, it <em>is</em> a
                                                            better experience. I will happily trade some vague notion of "freedom"
                                                            for stuff that just works. Endless fiddling and integration of
                                                            disparate technologies isn't freedom at all&mdash;it's an enslavement
                                                            of the most precious resource I have, which is my time.</p>
                                                            
                                                            <p>Not everyone is happy with that and they prefer an alternative. Hey,
                                                            no problem. Live and let live. You want to run Boxee on Linux
                                                            connected to an iRiver. More power to you. I won't sneer at you or
                                                            call you a fool. If it makes you happy, your choices <em>don't affect me
                                                            in the slightest</em>.</p>
                                                            
                                                            <p>As an aside, if anyone complaining about the lack of Flash is also
                                                            complaining about lock-in, that person needs to be hit repeatedly with
                                                            a rake.</p>
                                                            
                                                            <h3>No Camera</h3>
                                                            
                                                            <p>Sigh. Yeah, this one is a bit disappointing. I don't really care so
                                                            much about having for video chatting (which I do maybe once a
                                                            year). But I really like using a camera to capture things I would
                                                            otherwise have to take a lot of effort to write down. How cool would it
                                                            be to have your iPad in a brainstorming session where you can still
                                                            jot a few notes down then associate a snapshot of the whiteboard?</p>
                                                            
                                                            <p>Now there is an interesting design conundrum here. Do you put the
                                                            camera on the front or the back? Depending on the tasks you expect to
                                                            perform, this makes a huge difference. If you want people to see
                                                            <em>you</em>, you put it on the front and figure out how to give the user
                                                            the user visual feedback so they can position the camera.</p>
                                                            
                                                            <p>If you want to take pictures of other things, you put the camera on
                                                            the back and use the video display as the viewfinder. However you
                                                            can't reasonably reverse the tasks for these two positions. OK, so do
                                                            you put <em>two</em> cameras on? I don't know. How do you control them? Does
                                                            each bit of software implicitly decide which camera to enable? Does
                                                            the user have to decide?</p>
                                                            
                                                            <p>I don't know the answer, but I would be very surprised if a camera
                                                            didn't show up in the next version of the device. They put cameras in the
                                                            iPod Nanos for cryin' out loud. Surely they can figure out how to
                                                            stick one in an iPad.</p>
                                                            
                                                            <h3>More AT &amp; T</h3>
                                                            
                                                            <p>The amount of bad press AT &amp; T has received via the iPhone has to make
                                                            them wonder what sort of devil they've made a deal with. Are there
                                                            serious issues with AT &amp; T? You betcha. Do they effect everyone? I'm
                                                            not convinced. Coverage in San Francisco and Manhattan seem acutely
                                                            poor, but in my corner of the Northwest coverage is pretty damn good.</p>
                                                            
                                                            <p>The non-iPhone types love to make fun of AT&amp;T, fueled largely (I think)
                                                            by schadenfreude. I'd be very curious to see how other carriers handle
                                                            a similar load. I used to work in that industry and the mentality
                                                            among carriers is <em>all the same</em>. They all want to wring every penny
                                                            they can out of you by charging for every bit you use. Let's not kid
                                                            ourselves.</p>
                                                            
                                                            <p>Kudos to Apple for making a WiFi-only version. For me, this is a
                                                            pretty compelling configuration. I'm an urban kid. There are few
                                                            places I go where I can't get some kind of access to WiFi. In the
                                                            cases where I can't get WiFi, I have an iPhone. Plus, I imagine using
                                                            an iPad primarily at home, or on vacation, but not for commuting.</p>
                                                            
                                                            <p>I'm no AT &amp; T apologist&mdash;there are some serious issues they need
                                                            address&mdash; but I'm not convinced that this makes the iPad a
                                                            "failure".</p>
                                                            
                                                            <h3>Conclusion</h3>
                                                            
                                                            <p>Am I an Apple apologist? I hope not, but people are notoriously bad
                                                            judges of their own character. What I can say is that there are
                                                            certainly things about the company that frustrate both as a user and
                                                            developer. However, I am still more delighted by their products than I
                                                            am frustrated with them. When that balance changes, I'll move on to
                                                            something else.</p>
                                                            
                                                            <p>I'm pretty jazzed about this device, both as a consumer and as a
                                                            developer. What sucked me into the iPhone was how it just oozed with
                                                            <em>utility</em>. Not in terms of potential energy, but in that it fulfills
                                                            the notion of computers as and extension of our own minds. The iPad
                                                            just takes the next step forward. I can't wait to see how it all
                                                            unfolds.</p>
                                                            
                                                            <p>P.S. Just I'm glad to see the iPhone finally get some competition, I'm
                                                            also looking forward to somebody putting up a good fight against the
                                                            iPad.</p>
                                                        ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                            Prototyping with Briefs
                                                        ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/' />
    <updated>2010-01-10T17:40:40-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/01/10/prototyping-with-briefs/</id>
    <content type='html'>
      <![CDATA[
                                                              <p>One of the best sessions I saw at the 2009 WWDC was titled "Prototyping iPhone User Interfaces". In this session, Bret Victor laid out a strategy and some techniques for building cheap prototypes on the the device in lieu of "static" mockups.</p>
                                                              
                                                              <p>After returning from WWDC I was inspired to try this technique out and after playing with the idea for a bit, it was clear that there was a lot of repetition in the process. To really make prototyping cheap, we need a simple framework that makes the process fast and easy. Enter <a href="http://github.com/capttaco/Briefs">Briefs</a>, a lightweight iPhone application that allows you to embed and run simple prototypes built with nothing more than images and a property list.</p>
                                                              
                                                              <p>With Briefs, you don't write a separate application for the device (imagine the provisioning headaches), but instead embed separate prototypes (called "briefs") into a single Briefs application. Briefs is still pretty new and I expect to see (and contribute) many enhancements, but if you like this style of application development, it's certainly worth spending some time with Briefs.</p>
                                                              
                                                              <p>Let's look at how it works. We're going to start with the goal of prototyping the built-in Photos application. Now obviously, nobody is going to actually <em>re-write</em> the Photos app, but since we all have familiarity with it, it's a good example to see how a working application can be expressed as a Briefs prototype.</p>
                                                              
                                                              <h1>Getting Briefs</h1>
                                                              
                                                              <p>Before we do anything, we need to get Briefs on our local machine. Briefs is distributed in source-only form via <a href="http://github.com/capttaco/Briefs">GitHub</a>. You'll need to find a nice place to check out the two main Briefs project, then do the following:</p>
                                                              
                                                              <div class="highlight"><pre><span class="nv">$ </span>git clone git://github.com/capttaco/Briefs.git&#x000A;    <span class="nv">$ </span>git clone git://github.com/capttaco/Briefs-util.git&#x000A;    <span class="nv">$ </span><span class="nb">cd </span>Briefs&#x000A;    <span class="nv">$ </span>git submodule update -i&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>In order to put our first Brief together, we need to build a command-line tool that is part of the Briefs project. Open the Xcode project in the Briefs folder (<code>Briefs.xcodeproj</code>) and select the "Briefs Compactor" target and set the architecture to "Base SDK".</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-7.50.17-AM.png" alt="Screen shot 2010-01-10 at 7.50.17 AM.png" /></p>
                                                              
                                                              <p>Now execute the target to build the <code>compact-briefs</code> executable. When it's finished, Xcode will put the final binary in <code>build/Debug/compact-briefs</code> in the Briefs project directory. Copy this file to a location in your <code>$PATH</code>. Personally I like to keep such stuff in <code>~/bin</code>. We'll need this command in a little bit.</p>
                                                              
                                                              <h1>How it Works</h1>
                                                              
                                                              <p>Before we dive into our project, we should get a little terminology under our belt. Each application prototype you create is called a "Brief". Each Brief is composed of one or more "Scenes". Scenes usually have an associated image, so you can think of a scene and a screen in the application as being more or less equivalent.</p>
                                                              
                                                              <p>Scenes can also have any number of "Actors", which are regions on the screen that perform some action when touched. For example, to mimic navigating to a new view via a view controller, a region on a table view could be rigged to an action that slides another scene into place.</p>
                                                              
                                                              <p>Briefs are expressed as Property List (Plist) files in the Briefs application. If you like writing XML or are proficient with the Property List Editor application, then you're golden. Otherwise there is another format in which you can write your brief that compiles down to a final Plist. This is the route we'll explore in our prototype.</p>
                                                              
                                                              <h1>Protyping Photos.app</h1>
                                                              
                                                              <h2>Generate Image Files</h2>
                                                              
                                                              <p>Now let's generate the image files for our prototype. In the case of the existing Photos app, I just screen-captured the running application on the simulator. Obviously, you won't be in the same position with a new application, so you'll need to generate some images by hand.</p>
                                                              
                                                              <p>If you use OmniGraffle, there are several good iPhone stencil sets on <a href="http://graffletopia.com/categories/iphone">Graffletopia</a>. If you prefer Photoshop, checkout the exhaustive <a href="http://www.teehanlax.com/blog/2009/06/18/iphone-gui-psd-30/">iPhone GUI PSD</a>. Either one of them will generate the appropriate files. There's no requirement that the image files <em>look</em> like the iPhone. You could use a  tool like <a href="http://www.balsamiq.com/products/mockups">Balsamiq</a> or scan hand-drawn sketches to generate very simple wireframe sketches. Regardless, all you need to do is produce PNG, GIF or JPEG files that fit within the normal iPhone dimensions (320 x 480).</p>
                                                              
                                                              <p>Let's create a folder called "photos app" and put our image files in it. I've created <a href="http://alexvollmer-public.s3.amazonaws.com/photos_app.tgz">a tar-ball of this entire project</a>, which you can download, explore and run.</p>
                                                              
                                                              <h2>Writing the Brief</h2>
                                                              
                                                              <p>Let's think a bit about the flow of our application. We're only going to implement a sub-set of Photo.app's full navigation&mdash;we'll just implement the flow for the Hawaii photo album. We have a top-level screen that shows all of the photo albums. From there the user can select "Hawaii" and drill into a display of a few images in the album. Touching any of the images will take the user into the image browser where users can go back and forth between the various images. Each screen has a common "back" button in the top-left. The overall screen layout and flow looks like this:</p>
                                                              
                                                              <p><a name="app-flow"><img src="/images/2010/01/photos-app-flow.png" alt="photos-app-flow.png" /></a></p>
                                                              
                                                              <p>The pink boxes highlight the touchable areas in each scene. The arrows between them show which scene a particular area navigates to. In Briefs-parlance, each screen is a "Scene" and each pink box is an "Actor".</p>
                                                              
                                                              <p>Let's step through the Brief (the <code>photos.bs</code> file), a bit at a time. If you get lost, refer back to the <a href="#app-flow">application flow diagram</a> above.</p>
                                                              
                                                              <p>First we declare that our starting scene is the "Home" scene. Next, we define that scene with the image <code>home.png</code> as the background image and one actor that will navigate to the next scene. The position and size of this actor corresponds to the table cell labeled "Hawaii". If we wanted to support the table rows, we'd need to add an actor for each one.</p>
                                                              
                                                              <p>When the user touches the "Hawaii" row, we'll transition the "Hawaii" scene (defined shortly) by executing a "push left" animation. This will mimic the standard animation of pushing a new view controller onto the navigation controller stack:</p>
                                                              
                                                              <div class="highlight"><pre>start:Home&#x000A;    scene:Home&#x000A;      image:home.png&#x000A;      actor:HawaiiPictures &#x000A;        position:0,123 &#x000A;        wh:320,53&#x000A;        action:goto<span class="o">(</span>Hawaii, push left<span class="o">)</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>Next, we'll define a scene that shows the thumbnail images for each photo in the Hawaii album. This scene will display the <code>hawaii.png</code> background image and has an actor for the return navigation button in the upper-left as well as for each thumbnail image. Note the differences in the direction of the push animation in the actors. The "back" button pushes right (like the normal return navigation animation), while the thumbnails push left.</p>
                                                              
                                                              <div class="highlight"><pre>scene:Hawaii&#x000A;      image:hawaii.png&#x000A;      actor:Home &#x000A;        position:17,30 &#x000A;        wh:87,24 &#x000A;        action:goto<span class="o">(</span>Home, push right<span class="o">)</span>&#x000A;      actor:image1 &#x000A;        position:5,69 &#x000A;        wh:72,72 &#x000A;        action:goto<span class="o">(</span>Image1, push left<span class="o">)</span>&#x000A;      actor:image2&#x000A;        position:84,70&#x000A;        wh:72,72&#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;      actor:image3&#x000A;        position:162,70&#x000A;        wh:72,72&#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>Now we'll define the scenes for each of the three images. Each image scene has an actor for the return navigation button in the top-left. The first image also has two actors to navigate to the next image. The <code>NextImage</code> actor is for the navigation button in the toolbar, whereas the <code>NextImageSwipe</code> actor covers the right side of the image itself. This is done to mimic the swiping motion normally used to navigate photos. Right now, Briefs only supports single-touch interactions so it won't behave <em>exactly</em> like the real application in supporting swipes.</p>
                                                              
                                                              <div class="highlight"><pre>scene:Image1&#x000A;      image:image1.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:NextImage &#x000A;        position:202,450 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;      actor:NextImageSwipe &#x000A;        position:156,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image2, push left<span class="o">)</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>The "Image2" scene is a lot like the "Image1" scene, except that it has button and swipe actors for both the previous and next images:</p>
                                                              
                                                              <div class="highlight"><pre>scene:Image2&#x000A;      image:image2.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:PreviousImage &#x000A;        position:94,452 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image1, push right<span class="o">)</span>&#x000A;      actor:PreviousImageSwipe &#x000A;        position:0,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image1, push right<span class="o">)</span>&#x000A;      actor:NextImage &#x000A;        position:202,450 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;      actor:NextImageSwipe &#x000A;        position:156,60&#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image3, push left<span class="o">)</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>Finally, the last image scene. It only has "backward" navigation in the photo set since we've only put three photos in our album:</p>
                                                              
                                                              <div class="highlight"><pre>scene:Image3&#x000A;      image:image3.png&#x000A;      actor:NavigateBack &#x000A;        position:14,33 &#x000A;        wh:44,23 &#x000A;        action:goto<span class="o">(</span>Hawaii, push right<span class="o">)</span>&#x000A;      actor:PreviousImage &#x000A;        position:94,452 &#x000A;        wh:23,17 &#x000A;        action:goto<span class="o">(</span>Image2, push right<span class="o">)</span>&#x000A;      actor:PreviousImageSwipe &#x000A;        position:0,60 &#x000A;        wh:160,380 &#x000A;        action:goto<span class="o">(</span>Image2, push right<span class="o">)</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>We've just done simple scene-to-scene transitions in this Brief, but there are also several transitions you can perform directly on actors such as moving them, fading them in and out and others. I've created a <a href="http://alexvollmer-public.s3.amazonaws.com/Briefs%20Cheatsheet.pdf">syntax cheatsheet</a> which you can use as a reference for your own Briefs.</p>
                                                              
                                                              <h2>Compiling the Brief</h2>
                                                              
                                                              <p>Once we have our photos, it's time to start writing our Brief. As mentioned earlier, the Briefs application consumes Plist files. However you can't just create one out of the box because it will only have image file <em>references</em> in it, but not the actual data. The reason we built the <code>compact-briefs</code> command earlier, was so that we could take our intermediate Briefs file (usually called a <em>source</em> brieflist) and embed the image data directly in the final product.</p>
                                                              
                                                              <p>However I find editing XML tiresome, whether it's by hand or with a tool. Briefs provides an alternate syntax in which to write briefs which is transformed by a Ruby script into the intermediate Plist format. You can then compile the source brieflist to the final format using the <code>compact-briefs</code> command. The flow between formats and tools looks like this:</p>
                                                              
                                                              <p><img src="/images/2010/01/briefs-flow.png" alt="briefs-flow.png" /></p>
                                                              
                                                              <p>In the <code>Briefs-util</code> project (which you checked out earlier), you can find the Ruby script in <code>BS/bs</code>. I run these tools all at once in a script named <code>compile</code>:</p>
                                                              
                                                              <div class="highlight"><pre><span class="c">#!/bin/bash</span>&#x000A;    ~/Development/Briefs-util/BS/bs photos.bs &gt; photos-source.brieflist <span class="o">&amp;&amp;</span> <span class="se">\</span>&#x000A;        ~/bin/compact-briefs photos-source.brieflist ~/Development/Briefs/sample/photos.brieflist&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <h2>Installing the Brief</h2>
                                                              
                                                              <p>The next step is to build the Briefs application with our newly-compiled Brief. Switch back to the Briefs Xcode project and choose the "Briefs" application target. If you haven't yet added the new brief to the Xcode project, right-click on the "My Briefs" and choose Add > Existing Files. Select the <code>photos.brieflist</code> file in the <code>samples</code> directory and in the following dialog make sure the checkbox at the top is unselected.</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-2.08.27-PM.png" alt="Screen shot 2010-01-10 at 2.08.27 PM.png" /></p>
                                                              
                                                              <p>Now you can build the Briefs application for either the simulator or the device. If you're building for the device, make sure you have a proper provisioning profile in place that matches the bundle identifier of the project. Now we can Build &amp; Run the project, and our <code>photos.brieflist</code> should appear in the list:</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-8.54.47-AM.png" alt="Screen shot 2010-01-10 at 8.54.47 AM.png" /></p>
                                                              
                                                              <p>Select our new Brief and play with the application. To exit a Brief, touch and hold your finger down until a new screen appears asking you if you want to exit the current Brief.</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-11.54.51-AM.png" alt="Screen shot 2010-01-10 at 11.54.51 AM.png" /></p>
                                                              
                                                              <h2>Distributing the Brief</h2>
                                                              
                                                              <p>The idea behind these prototypes is putting a tangible example in front of users to get their feedback. So what do you do if you want to distribute Briefs to a wider audience? Ad-hoc builds are a pain and require access to the physical device. Fortunately, Briefs provides a tool called "Briefcasts", which is simply one or more Briefs embedded in an RSS feed. The Briefs application can retrieve Briefcasts via HTTP, so distributing Briefs is a snap if you have a web server to serve new Briefcasts from. This means you can install the Briefs application once on a device and provide updates anytime without having direct access to the hardware.</p>
                                                              
                                                              <p>Currently, there isn't a tool to easily create a Briefcast directly out of a list of Briefs. For now, the project web site recommends copying and modifying the RSS template below:</p>
                                                              
                                                              <div class="highlight"><pre><span class="cp">&lt;?xml version=&quot;1.0&quot;?&gt;</span>&#x000A;    <span class="nt">&lt;rss</span> <span class="na">version=</span><span class="s">&quot;2.0&quot;</span><span class="nt">&gt;</span>&#x000A;      <span class="nt">&lt;channel&gt;</span>&#x000A;        <span class="nt">&lt;title&gt;</span>*Briefcast Demo*<span class="nt">&lt;/title&gt;</span>&#x000A;        <span class="nt">&lt;link&gt;</span>*http://island.local/~alex/briefcasts/*<span class="nt">&lt;/link&gt;</span>&#x000A;        <span class="nt">&lt;description&gt;</span>*Demonstrate how awesome it is to use a briefcast to get briefs on the iPhone.*<span class="nt">&lt;/description&gt;</span>&#x000A;        <span class="nt">&lt;language&gt;</span>en-us<span class="nt">&lt;/language&gt;</span>&#x000A;        *Thu, 12 Nov 2009 03:05:00 GMT*<span class="nt">&lt;/pubDate&gt;</span>&#x000A;        <span class="nt">&lt;lastBuildDate&gt;</span>*Thu, 12 Nov 2009 03:05:00 GMT*<span class="nt">&lt;/lastBuildDate&gt;</span>&#x000A;        <span class="nt">&lt;item&gt;</span>&#x000A;          <span class="nt">&lt;title&gt;</span>*Photos.app Sketch*<span class="nt">&lt;/title&gt;</span>&#x000A;          <span class="nt">&lt;enclosure</span> <span class="na">url=</span><span class="s">&quot;*http://island.local/~alex/briefcasts/photos.brieflist*&quot;</span> <span class="na">length=</span><span class="s">&quot;*954708*&quot;</span> <span class="na">type=</span><span class="s">&quot;application/brief&quot;</span> <span class="nt">/&gt;</span>&#x000A;          <span class="nt">&lt;description&gt;</span>*An example brief of the built-in Photos.app.*<span class="nt">&lt;/description&gt;</span>&#x000A;          *Sun, 13 Sep 2009 03:05:00 GMT*<span class="nt">&lt;/pubDate&gt;</span>&#x000A;          <span class="nt">&lt;guid&gt;</span>*http://island.local/~alex/cast/1#item1*<span class="nt">&lt;/guid&gt;</span>&#x000A;        <span class="nt">&lt;/item&gt;</span>&#x000A;      <span class="nt">&lt;/channel&gt;</span>&#x000A;    <span class="nt">&lt;/rss&gt;</span>&#x000A;    </pre>
                                                              </div>
                                                              
                                                              
                                                              <p>The bits marked <em>in bold</em> need to replaced with your particular details. In the example above I only have one Brief, but if you had more than one, you would just include additional <code><item></code> elements. You need to have this RSS file on disk as well as the brieflist file referred to in the <code><enclosure></code> tag.</p>
                                                              
                                                              <p>Assuming that you have your web server all setup with the RSS file as well as the Briefs files, you can launch the application and add the Briefcast by selecting the "+" button in the top-right of the home screen. Enter the details on the next dialog and touch the "Save" button:</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.20.37-AM.png" alt="Screen shot 2010-01-10 at 9.20.37 AM.png" /></p>
                                                              
                                                              <p>On the next screen you'll see the details of the Briefcast. Each Brief in the Briefcast will be listed under the section titled "Enclosed Briefs". Touch the "Download this Brief" button to retrieve the associated brief.</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.20.49-AM.png" alt="Screen shot 2010-01-10 at 9.20.49 AM.png" /></p>
                                                              
                                                              <p>Once the brief is downloaded, you end up on a rather unhelpful confirmation screen:</p>
                                                              
                                                              <p><img src="/images/2010/01/Screen-shot-2010-01-10-at-9.16.27-AM.png" alt="Screen shot 2010-01-10 at 9.16.27 AM.png" /></p>
                                                              
                                                              <p>You have to touch the screen, then navigate back to the top. Then you'll find the new Brief in your list of briefs. To update the Brief, you navigate back into the Briefcast section from the home page and download the correct Brief again.</p>
                                                              
                                                              <p>One nice enhancement I'd love to see is a custom application URL for Briefs so that you could just email the link to someone. They could read the email from their device, select the URL and Briefs would launch and download the newest Briefs.</p>
                                                              
                                                              <h1>Conclusion</h1>
                                                              
                                                              <p>Briefs is a great tool for building live prototypes. Since it's a relatively young project, it still has a lot of rough edges, but I expect it to mature over time.</p>
                                                              
                                                              <p>Don't hesitate to dive into the code behind Briefs. There are occasions when Briefs (the application or the command-line tool) will crash without much detail. I found that this is usually the result of bad syntax in the Briefs so a little sleuthing may be required to get things working.</p>
                                                              
                                                              <h1>Resources</h1>
                                                              
                                                              <p>Here's a list of related resources:</p>
                                                              
                                                              <ul>
                                                              <li><a href="http://giveabrief.com/">Briefs Homepage</a></li>
                                                              <li><a href="http://github.com/capttaco/Briefs">Briefs on GitHub</a></li>
                                                              <li><a href="https://alexvollmer-public.s3.amazonaws.com/photos_app.tgz">Sample Brief of Photos.app</a></li>
                                                              <li><a href="https://alexvollmer-public.s3.amazonaws.com/Briefs%20Cheatsheet.pdf">Briefs Syntax Cheatsheet</a></li>
                                                              <li><a href="http://graffletopia.com/categories/iphone">iPhone Templates for OmniGraffle</a></li>
                                                              <li><a href="http://www.teehanlax.com/blog/2009/06/18/iphone-gui-psd-30/">iPhone PSD for PhotoShop</a></li>
                                                              </ul>
                                                          ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                              Tools of 2009
                                                          ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2010/01/07/tools-of-2009/' />
    <updated>2010-01-07T04:35:42-08:00</updated>
    <id>http://alexvollmer.com/posts/2010/01/07/tools-of-2009/</id>
    <content type='html'>
      <![CDATA[
                                                                <p>I suppose if I were really on the ball I would have posted this right after New Year's Day, but I needed to ruminate a bit on what was worth summarizing for 2009. In the end I decided to talk about the tools I found in 2009 that really made a difference in my life.</p>
                                                                
                                                                <h2>LaunchBar</h2>
                                                                
                                                                <p>When I first switched to the Mac, I discovered Quicksilver and it was like discovering something essential that you didn't know you needed. QS was a revelation to me because it drastically reduced the mental distance between the what I wanted to accomplish and executing it.</p>
                                                                
                                                                <p>Over time though, I found some things in QS that just didn't work consistently. It would crash and some of configuration was pretty clumsy. It became pretty clear that there was little, if any, forward progress being made on it. So, on the advice of several local Ruby/Mac nerds, I tried out <a href="http://www.obdev.at/products/launchbar">LaunchBar</a>. At first I was disappointed that it didn't have the breadth of QS, but after investing a little time and effort I found that it handled 99% of the things I wanted. More importantly, there was somebody actually working on it which meant it was going to evolve and improve.</p>
                                                                
                                                                <p>Now I can hardly use a machine that doesn't have it installed. I can't believe people use the dock to launch apps. Yuck.</p>
                                                                
                                                                <h2>Mailplane</h2>
                                                                
                                                                <p>By and large, I'm biased to using the built-in Apple-given tools where possible. Apple usually gets it right and most other tools are designed to work with these apps. I've used Mail.app since I switched to the Mac, but always felt the interface to be inferior to GMail's tag-oriented structure. But since I had some non-GMail accounts, <em>and</em> I wanted to have a single app, I stuck with Mail.app.</p>
                                                                
                                                                <p>However, once I dropped my last IMAP-only account I was ready to switch back. The only parts I really missed were the tight integration with the desktop that Mail.app brought. Lo and behold, along comes <a href="http://mailplaneapp.com">Mailplane</a> to fill the gap. It is, essentially, a WebKit view of GMail with some extra bits to glue the web application to your desktop. I think it's brilliant and was happy to part with some hard-earned money for the privilege to use it.</p>
                                                                
                                                                <h2>zsh completion</h2>
                                                                
                                                                <p>My introduction to zsh came many years ago from a co-worker who boot-strapped my entr&eacute;e into zsh-land with his configuration files. For the longest time I treated them like mystic, sacred tablets to be worshipped, but never to be understood. But over time I found little gaps I wanted to fill in with my zsh setup, especially with command auto-completion.</p>
                                                                
                                                                <p>I'm a keyboard kind of guy. I like the command prompt. I also like going fast, so anything that makes me faster in the command prompt is like gold to me. I love shell auto-completion and found lots of things I wanted completion for, like <a href="http://gist.github.com/164465">RubyGems</a>. So this year I finally pounded through enough documentation and samples to put together a few home-grown completion bits. I still don't understand most of the incantations that make it go (guilty as charged of cargo-culting) but it has made my command-line work-flow that much better.</p>
                                                                
                                                                <h2>Dropbox</h2>
                                                                
                                                                <p>Since switching to the Mac, I've always had at least two machines that I needed to share files between. For the longest time I used to store files in S3 then sync them back and forth. This worked, but it sucked because I had to do it manually and I had to get the order right so I didn't clobber any files.</p>
                                                                
                                                                <p>When <a href="http://www.dropbox.com">Dropbox</a> came along, the clouds parted and the golden light of heaven shown down from above. Dropbox makes sharing files super-duper, idiotically simple. Combined with tools like <a href="http://agilewebsolutions.com/products/1Password">1Password</a>, having consistent data across multiple machines is like magic on a daily basis&mdash;it just works and I don't even have to think about it.</p>
                                                                
                                                                <h2>One Bus Away</h2>
                                                                
                                                                <p>The thing I love about the iPhone is how it's an Swiss Army Knife for information in the modern age. You can find apps that do very specific things, very well and put them in a single box that you keep in your pocket. The <a href="http://www.onebusaway.org">One Bus Away</a> app is one of my favorite iPhone tools.</p>
                                                                
                                                                <p>I ride the bus a lot and to have real-time transit data in the palm of my hand is fantastic. No guessing about when the next bus is coming. No extra waiting. I know just when to leave to catch my next ride.</p>
                                                                
                                                                <h2>Mint.com</h2>
                                                                
                                                                <p>I was a long-time Quicken user but finally had it last January. It's a bloated app with serious usability issues. I finally reached a point where using Quicken had a net-negative impact on my life. It simply drove me crazy to use it.</p>
                                                                
                                                                <p>Enter <a href="http://mint.com">mint.com</a>. At first I was very hesitant to give my information to these guys. But eventually I was convinced to try it because:
                                                                *  if I use Quicken another minute I'll go postal
                                                                *  sometimes the future doesn't start until you acknowledge it, and this looks like the future to me
                                                                *  I'm probably already more open to financial security risk anyway, so what the hell?</p>
                                                                
                                                                <p>I get exactly what I want out of mint: a high-level dashboard that just updates itself. I use a few of the budgeting features which are nice, but really it's all about automated data acquisition and display. Oh yeah, did I mention that they have an iPhone app too?</p>
                                                                
                                                                <h2>Instapaper</h2>
                                                                
                                                                <p>Several years ago I built my own news-feed reader and one of the features I really wanted to implement was a temporary "holding pen" where I could put URLs to visit later. These were things that didn't quite warrant a Delicious bookmark, but I wanted to get back to.</p>
                                                                
                                                                <p>By itself, <a href="http://instapaper.com">Instapaper</a> satisfied my original need and worked great as a bookmarklet in my browser. However it went from a convenient curiosity to an essential tool once other apps started integrating with it (e.g. Net News Wire, Tweetie 2) <em>and</em> Kindle integration (see below).</p>
                                                                
                                                                <p>Oh yeah, did I mention that there's an iPhone app for that too?</p>
                                                                
                                                                <h2>Kindle (device and app)</h2>
                                                                
                                                                <p>The final tool of 2009 that made itself indispensable was the Kindle. It's a great example of "good enough". The Kindle is fraught with polish and usability issues, but they don't overwhelm the utility of the device.</p>
                                                                
                                                                <p>I've been on a long dispense-with-all-physical-media kick, with books being my primary target. I have lots of books, but I don't have lots of space. Since I'm not emotionally wedded to the form-factor of paper books, the Kindle solves my reading-appetite vs. space problem quite well. I can stuff that thing full of books and not take up an inch of extra space in my house.</p>
                                                                
                                                                <p>Like so many of the other tools I've listed, it's the other things that integrate with the Kindle that multiply its utility. First, the Kindle has gained a lot of adoption by other publishers. The <a href="http://pragprog.com">Prags</a> and <a href="http://oreilly.com">O'Reilly</a>, in particular, have been eager to jump into the e-book biz with first-class Kindle support. I probably go through about fifteen to twenty tech books a year and having them on the Kindle is great.</p>
                                                                
                                                                <p>Another great bit of integration is how Instapaper delivers me a weekly digest of links I've captured right to my Kindle. I can read the full content of every page I bookmarked right there on my Kindle without the need for a network connection. This is a great for travel.</p>
                                                                
                                                                <h2>So?</h2>
                                                                
                                                                <p>Looking over this list, if there's one theme that emerges, it's all about ubiquity and convergence. (Did I really just say that?) Despite all of the queasy feelings those "market-tecture" terms give me, I don't quite know how else to define it. For me, 2009 was the year that I could get to my stuff whenever I liked, however I liked, through a multitude of channels.</p>
                                                                
                                                                <p>I wonder what the theme of 2010 will be?</p>
                                                            ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                All-Time Lineup
                                                            ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/12/15/all-time-lineup/' />
    <updated>2009-12-15T06:14:09-08:00</updated>
    <id>http://alexvollmer.com/posts/2009/12/15/all-time-lineup/</id>
    <content type='html'>
      <![CDATA[
                                                                  <p>A little while ago, I was encouraged to put together my "All-Time" baseball lineup. Now, personally I think the game is more difficult to compete in now than ever before. While the old-timers love to gripe about players in the Steroid Era, I don't think those guys had to play with such a uniformly strong level of competition under such high pressure. But that's just my gut feeling. I don't really have the evidence to back that up. I also think that baseball fans have a tendency to romanticize the players of baseball's so-called "Golden Era", making any rational debate even tougher.</p>
                                                                  
                                                                  <p>With the exception of Gehrig, I've purposely ignored anyone before the 50's. In my opinion, the game is just too different. I don't feel like I can trot Cy Young out as my starting pitcher just because of 511 wins. Those wins don't compare at all to wins in the 60's, 70's, 80's or 90's.</p>
                                                                  
                                                                  <p>I'm also not penalizing anyone for being part of the Steroid Era or for even having used PEDs. There are, no doubt, some effects of these substances on the game, but I don't see the evidence being as conclusive as some would have you believe. Did Barry Bonds cheat? Yeah, I'm pretty sure he did. He was a helluva ball-player before he started and he still would have put together a Hall of Fame career without them. Steroids (a rather inaccurate term for PEDs) don't make you see the ball any better or improve your hand/eye coordination. At best they allow athletes to recover faster from working out. They don't build muscle, they amplify the body's own healing process in order to work out more. You can call steroid users cheaters, but I wouldn't call them lazy.</p>
                                                                  
                                                                  <p>So this is my list. If you have a different one, I'd love to hear about it. So, without further ado, here's my list.</p>
                                                                  
                                                                  <h3>Catcher: Roy Campanella</h3>
                                                                  
                                                                  <p>Great all-around athlete, hit the crap out of the ball, threw runners out and worked well with pitchers. He was probably one of the most complete catchers to play in the majors.</p>
                                                                  
                                                                  <h3>First Base: Lou Gehrig</h3>
                                                                  
                                                                  <p>OK, I cheated a little bit here and dipped back in time further than I said I would go. But c'mon&mdash;it's <em>Lou Gehrig</em>.</p>
                                                                  
                                                                  <h3>Second Base: Jackie Robinson</h3>
                                                                  
                                                                  <p>They retired the number 42 for lots of reasons&mdash;those are the same reasons he's my starting second baseman.</p>
                                                                  
                                                                  <h3>Third Base: George Brett</h3>
                                                                  
                                                                  <p>Brett is the last guy to come close to hitting .400. He ended the 1980 season with a .390 average. What's even more impressive is that he had more <em>home runs</em> than <em>strikeouts</em> that year. He's got the longevity, the ring and the career to put him on my list.</p>
                                                                  
                                                                  <h3>Shortstop: Alex Rodriguez</h3>
                                                                  
                                                                  <p>Does A-Rod's admission to using PEDs damage is Hall of Fame credentials? Maybe, but as I contended earlier, I'm not convinced that they can carry a player to greatness. We love to dump on A-Rod's failures, but it's really only because he's been spectacularly successful in his career. Drugs or not, he's my starting shortstop. This, coming from a jilted M's fan too!</p>
                                                                  
                                                                  <h3>Left Field: Ted Williams</h3>
                                                                  
                                                                  <p>The Splendid Splinter. The greatest hitter of all time. Period.</p>
                                                                  
                                                                  <h3>Center Field: Willie Mays</h3>
                                                                  
                                                                  <p>Hard to find a better combination of offensive and defensive skills.</p>
                                                                  
                                                                  <h3>Right Field: Hank Aaron</h3>
                                                                  
                                                                  <p>How could I possibly leave Hank Aaron off the list?</p>
                                                                  
                                                                  <h3>Designated Hitter: Edgar Martinez</h3>
                                                                  
                                                                  <p>Edgar Martinez presents a serious conundrum to Hall of Fame voters. He's really the first "pure" designated hitter that voters will have to face. His career are numbers are impressive for the time he played, but he doesn't have some of the magic totals people like to see. That said, he's my vote for DH. Plus, I named my dog after him.</p>
                                                                  
                                                                  <h3>Starting Pitcher: Sandy Koufax</h3>
                                                                  
                                                                  <p>There's probably no roster spot that would engender more differences of opinion than starting pitcher. There are so many great ones to choose from. Koufax didn't have the career longevity like Satchel Paige or Tom Seaver, but at the height of his powers he was simply jaw-dropping amazing. His years from 1963 through 1966 are some of the <em>sickest</em> consecutive years a pitcher ever put together.</p>
                                                                  
                                                                  <h3>Relief Pitcher: Mariano Rivera</h3>
                                                                  
                                                                  <p>While there may be controversy over starters, the choice for reliever is pretty straight-forward. Seriously, is there any disagreement here?</p>
                                                                  
                                                                  <h3>Manager: Earl Weaver</h3>
                                                                  
                                                                  <p>He managed Hall of Fame players, he won a couple of rings, he wrote the seminal book on baseball strategy and he had a video game named after him. Yup, that fits my criteria.</p>
                                                              ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                  Building a Knowledge Base
                                                              ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/' />
    <updated>2009-12-11T16:39:09-08:00</updated>
    <id>http://alexvollmer.com/posts/2009/12/11/building-a-knowledge-base/</id>
    <content type='html'>
      <![CDATA[
                                                                    <p>Many years ago, I had the fortune of working for a family friend who was a financial planner. Not only did I get to learn a lot about personal finances at an early age, but I also picked up some great professional habits too. One of the things she did was maintain a gigantic set of folders of things she found interesting or useful. She had a four-drawer filing cabinet filled with various tidbits of information she had collected. She had a pretty good index in her head of where these things were and was amazingly proficient in recalling where she had filed things.</p>
                                                                    
                                                                    <p>I always wanted a personal knowledge base like this, but I couldn't do it the way she had. First, I have never had the space to collect that much paper. I cannot have, and do not want, a giant filing cabinet of folders. Second, I don't have the kind of recall she did to find that stuff. I could certainly remember that I once filed something, but wouldn't have a clue <em>where</em> I filed it. Which brings me to the third issue, which is suffering with the restriction of filing information under a single hierarchy.</p>
                                                                    
                                                                    <p>When I first started using GMail I had a major epiphany about the differences between organizing information in folders versus tagging. These days that seems about as earth-shattering as realizing our galaxy is helio-centric, but it seemed like a pretty radical idea at the time. I flat-out love this style of organization. I may not remember <em>where</em> I filed something, but I'm pretty consistent when it comes to labeling things. With systems like GMail and Delicious, I just slap as many tags as I think are reasonable for a message or bookmark and I have a really good chance of finding it again when I need to.</p>
                                                                    
                                                                    <p>But email and bookmarks aren't a knowledge base. For me, they are a reference, but usually aren't in a succinct enough format to be a good reference. I want to boil down newly-acquired knowledge into some quick, efficient prose. What I needed was a system that:
                                                                    *  Works across multiple machines (e.g. work and personal)
                                                                    *  Is fast to add and edit content
                                                                    *  Is (relatively) searchable
                                                                    *  Has some structure
                                                                    *  &hellip;but not so much that I fight with it</p>
                                                                    
                                                                    <p>So over the last few years I've started building a personal knowledge-base in earnest. It's not overly complicated or too involved. I simply keep a set of text files (specifically, files compatible with <a href="http://orgmode.org/">org-mode</a>) in a special <a href="https://www.dropbox.com/">Dropbox</a> folder. Dropbox makes synchronizing stupid-easy. I just treat these files just like local files and they appear on both my work and personal machines.</p>
                                                                    
                                                                    <p>For a while I used <a href="http://flyingmeat.com/voodoopad/">VoodooPad</a>, which is a very cool program. But I like having a <em>little</em> structure in my notes and imparting that structure in VoodooPad took more effort than I wanted. Later, I discovered Emacs' org-mode, which turned out to be a perfect fit for me&mdash;it's a relatively lightweight structure on top of simple text-files. The only thing org-mode doesn't do well is handling non-text media. I've considered moving to something like OmniOutliner, but I've found that org-mode works surprisingly well.</p>
                                                                    
                                                                    <p>The technology isn't particularly interesting, nor is it what makes this work for me. Rather, it's the <em>discipline</em> of writing down little notes on various topics of interest. For example, I can never remember how to enable zombies for Cocoa debugging. I looked it up once, then added a section to my <code>xcode.org</code> file on <code>NSZombieEnabled</code>. I get two benefits out of this: first I've got it somewhere handy that I can easily look up again (via spotlight, <code>grep/ack</code>, whatever). Secondly, the very act of formulating a paragraph or two on the concept somehow reinforces it into my brain. In fact, it's very likely that I won't ever have to look up how to track zombies again.</p>
                                                                ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                    Cleaning out the Closet
                                                                ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/' />
    <updated>2009-11-07T22:12:45-08:00</updated>
    <id>http://alexvollmer.com/posts/2009/11/07/cleaning-out-the-closet/</id>
    <content type='html'>
      <![CDATA[
                                                                      <p>I've had a couple of nascent Ruby gems lurking in my Github account for what seems like ages. So, on a rainy Saturday afternoon, I did a little cleanup and pushed a couple of new gems out to <a href="http://gemcutter.org">Gemcutter</a>.</p>
                                                                      
                                                                      <p>The first, is a gem I started over a year ago, called <a href="http://gemcutter.org/gems/word-salad" target="_new"><code>word-salad</code></a>. It uses the built-in dictionary file to randomly pull words out. This is great when you just need to generate a bunch of English-like text, but don't want to fall back on the boring old "lorem ipsum&hellip;" routine.</p>
                                                                      
                                                                      <div class="highlight"><pre><span class="mi">3</span><span class="o">.</span><span class="n">words</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s1">&#39;draw&#39;</span><span class="p">,</span> <span class="s1">&#39;ameliorate&#39;</span><span class="p">,</span> <span class="s1">&#39;bonanza&#39;</span><span class="o">]</span>&#x000A;    <span class="mi">2</span><span class="o">.</span><span class="n">sentences</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s1">&#39;Shoot jonesing the make castle.&#39;</span><span class="p">,</span> <span class="s1">&#39;Blue murdered slight bastion.&#39;</span><span class="o">]</span>&#x000A;    <span class="mi">2</span><span class="o">.</span><span class="n">paragraphs</span> <span class="o">==&gt;</span> <span class="o">[</span><span class="s2">&quot;Brachypterous gastropod pheretrer overeager toploftily denaturalization stokesite demented benzalhydrazine archaeologic. Haverer hypophonous lenticularly brickliner urocele paucipinnate pik unprintably perhalogen. Subglenoid bearish gesticulative staircase gallop vesuvianite pneumatically overyear conterminous dreamish. Nonalliterated galliwasp superconfirmation Comandra entoil millionth parcellize rarefaction Cynoidea. Podolian metamorphosable nativeness integriously protonematoid undoctor stochastically dissatisfactory unchastity.&quot;</span><span class="p">,</span> <span class="s2">&quot;Increate unloquacious unsatisfiedly flareboard internuncio beguine equivocation snowshoe Rhynchonellacea. Parochially curliewurly vermix consistorial cond consciencelessness Anaxagorize recoct sempiternally Campanulatae. Scorpionida Castalides homoanisic semipenniform Novemberish assessor preterlethal acrotarsial knoller hartin. Procrastination boatwise canonize differentiate faunlike countermarriage obstinance dilatableness drumloid. Gerate squirr Silvanus Physostigma booting thyroarytenoid diminutival legpuller medisance radiobserver.&quot;</span><span class="o">]</span>&#x000A;    </pre>
                                                                      </div>
                                                                      
                                                                      
                                                                      <p>The second is a gem for automatically retrieving and locally storing sales reports from the iTunes Connect site. If you have an iPhone app in the App Store, you already know how much (anti-)fun it is to get reports from Apple's site. So I put the <a href="http://gemcutter.org/gems/itunes-connect" target="_new"><code>itunes-connect</code></a> gem together to help out. It's pretty basic for now, but will probably grow more capabilities as time goes on.</p>
                                                                  ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                      The Cleverest Git Maneuver I Ever Pulled Off
                                                                  ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/' />
    <updated>2009-10-09T15:44:04-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/10/09/the-cleverest-git-maneuver-i-ever-pulled-off/</id>
    <content type='html'>
      <![CDATA[
                                                                        <p>So there I was, reviewing a series of commits, sucking air between my teeth and cringing when I came upon one of those lazy commits that has way too much stuff in it to reasonably digest. I needed a way to go back and split that commit into two or three separate commits. This is pretty easy to do with <code>git rebase</code>. You can just do a mixed reset of the last commit, stage the bits you want in one commit, stage the next bits and put that in a separate commit.</p>
                                                                        
                                                                        <p>This all works great&mdash;until it doesn't. The ability to stage parts of a file is one of my favorite features of <code>git</code>, but there are times when you have changes that <code>git</code> won't let you split apart. Usually I give up at this point and just abort the rebase.</p>
                                                                        
                                                                        <p>But yesterday I must have had too much coffee because I was <em>determined</em> to figure out how to do this. The changes that I wanted to split out were pretty easy to find. It was easy to remove them by hand and commit those. But I didn't want to have to manually add them <em>back</em>&mdash;that was too mistake-prone. What I needed was a way to invert the commit that removed those lines. What I needed was <code>git revert</code>. If I could revert my subtractions (in effect, <em>adding</em> the changes back), then I could squash the commits and rewrite history.</p>
                                                                        
                                                                        <p>So here's what I did:</p>
                                                                        
                                                                        <ol>
                                                                        <li>Started an interactive rebase session (<code>git rebase -i</code>)</li>
                                                                        <li>Marked the commit I wanted to split as an "edit"</li>
                                                                        <li>Manually removed the code I didn't want in the first commit, staged the changes and made a new commit</li>
                                                                        <li>Revert the subtraction with <code>git revert HEAD</code></li>
                                                                        <li>Complete that rebase with <code>git rebase --continue</code></li>
                                                                        <li>Start a new rebase and squash the original commit with the manual changes one</li>
                                                                        </ol>
                                                                        
                                                                        
                                                                        <p>Note that I didn't use <code>git reset</code> after step 2. It wouldn't have helped me because interactive staging wasn't working for me. I also marked all the commits in the second rebase as "edits", so I could fix the commit messages.</p>
                                                                        
                                                                        <p>Put another way, the commits transformed like this, from left to right:</p>
                                                                        
                                                                        <p><img src="/images/2009/10/git-revert.png" alt="git revert.png" /></p>
                                                                        
                                                                        <p>Maybe I'm overly fussy about clean commits. I'll admit that at times that my attention to cleanliness borders on the obsessive, but having the ability to go back and clean things up is one of my favorite things about <code>git</code>. Maybe I'm just not smart enough, but I usually don't know nearly as much at the beginning of a commit as I do at the end. With <code>git</code>, I can make it look like I do.</p>
                                                                    ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                        clip version 1.0.2 has been released!
                                                                    ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/' />
    <updated>2009-10-03T16:03:14-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/10/03/clip-version-1-0-2-has-been-released/</id>
    <content type='html'>
      <![CDATA[
                                                                          <p>You like command-line parsing, but you hate all of the bloat. Why
                                                                          should you have to create a Hash, then create a parser, fill the Hash
                                                                          out then throw the parser away (unless you want to print out a usage
                                                                          message) and deal with a Hash? Why, for Pete's sake, should the parser
                                                                          and the parsed values be handled by two different objects?</p>
                                                                          
                                                                          <p>Changes:</p>
                                                                          
                                                                          <h3>1.0.2 / 2009-10-02</h3>
                                                                          
                                                                          <ul>
                                                                          <li><p>Merged patches from Adam Salter:</p>
                                                                          
                                                                          <ul>
                                                                          <li>Added new "presence" method for options.</li>
                                                                          <li>Updated rspec usage to match the latest &amp; greatest syntax</li>
                                                                          <li>Make descriptions optional for flags and options</li>
                                                                          </ul>
                                                                          </li>
                                                                          <li><p><a href="http://clip.rubyforge.org">http://clip.rubyforge.org</a></p></li>
                                                                          </ul>
                                                                      ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                          The End of an Era
                                                                      ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/' />
    <updated>2009-10-02T21:55:55-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/10/02/the-end-of-an-era-2/</id>
    <content type='html'>
      <![CDATA[
                                                                            <p>Well, this is it kids; the end of my time at <a href="http://evri.com">Evri</a>. While I have cultivated a long-standing antipathy towards the Grateful Dead, I'll co-opt one of their song titles and simply mutter, "what a long strange trip it's been". I started out at Evri when it was still just a twinkle in somebody's eye. Since then I've seen it grow and mutate in ways I would have never imagined. I got to work on a lot of cool stuff and learn a bunch of new things. The best part, like any good job, was having the opportunity to work with some really great people.</p>
                                                                            
                                                                            <p>But now it's time for a change. My professional clock is set to about three years&mdash;when that bell rings it's time for me to move on. This was as true at Evri as it has been anywhere else, with one major difference: I made a career-change along the way.</p>
                                                                            
                                                                            <p>OK, I haven't given up software to become a sous-chef or to take troubled kids out into the woods to teach them discipline. But I think I have reached the end of my professional Java programming career. This is kind of a "Big Deal", because I've been doing it for a <em>decade</em>. I know, I know: never say never. It's entirely possible that I'll eat my words a year or two down the road, but for now, I can't help but feel like I'm closing a major chapter in my professional life.</p>
                                                                            
                                                                            <p>I've been with that language for a long time. Lately I've made a sport of complaining about it a lot, but honestly that's simply contempt bred from familiarity. There is a lot of good about the language and, despite my railings, the baby needn't be thrown out with the bath-water. What it comes down to is that I simply don't <em>enjoy</em> it anymore. It used to be fun to put those pieces together, but not any longer. So I'm trading in my Java hat for my two new loves: Ruby and Objective-C.</p>
                                                                            
                                                                            <p><img src="/images/2009/10/IMG_1047-150x150.JPG" class="left"/></p>
                                                                            
                                                                            <p>I may be stupid, but I'm not foolish enough to think that these languages will be the only remaining languages of my career. First of all, I'm not in the habit of defining my identity from the particular technologies I work with. Secondly, these are simply the environments I'm in love with now. I'm a dedicated family-man when it comes to people, but when it comes to programming languages, tools and environments I'm as bad as Liz Taylor. But jeez, why not embrace change? I don't do this for the paycheck. I do it because I love it. Why spend my time on things that aren't making me happy anymore?</p>
                                                                            
                                                                            <p>With that question burning a hole in my brain, it became clear that, for now, the twisting road that is my professional career is going to take a long detour through Ruby and Objective-C. I hope it gets some time with Erlang too&mdash;I've only dabbled with it a little bit, but found myself quite attracted right away.</p>
                                                                            
                                                                            <p>As I realized that my time was at an end at Evri, the question of "what next?" loomed large. Was there someone out there that wanted someone with the skills I wanted to cultivate? If so, were they doing something cool? Was I going to go "indie"? What would that look like? Questions, questions, questions. Fortunately I stumbled across a gig that is going to let me scratch most, if not all, of those itches.</p>
                                                                            
                                                                            <p>I'm taking October off to continue and complete the series of <a href="http://peepcode.com/products/iphone-view-controllers-part-i">iPhone</a> <a href="http://peepcode.com/products/iphone-view-controllers-part-ii">screencasts</a> I've been writing for <a href="http://peepcode.com">PeepCode</a>. In November I'll pick up my full-time gig and kick off the next phase of my professional life. You can't imagine how humbled and fortunate I feel to be able to do this.</p>
                                                                        ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                            iPhone Screencasts
                                                                        ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/' />
    <updated>2009-09-15T04:13:03-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/09/15/iphone-screencasts/</id>
    <content type='html'>
      <![CDATA[
                                                                              <p><a href="https://peepcode.com/products/iphone-view-controllers-part-i" target="_new"><img src="http://peepcode.com/system/uploads/2009/iphone-cover.png">
                                                                              </a></p>
                                                                              
                                                                              <p>I'm pleased to announce the release of the first in a series of <a href="http://peepcode.com">PeepCode screencasts for the iPhone SDK</a> I've been co-writing with Geoffrey Grosenbach. The first one (done in two parts) covers View Controller basics. We decided to start with View Controllers because they are at the core of all "productivity"-style applications. Once you have them down, you can start to put some meat on the bones of your iPhone apps.</p>
                                                                              
                                                                              <p>Once we've covered those, we'll work our way through the entire MVC Holy Trinity, one bit at a time. Along the way we hope to deep-dive on a few ancillary topics like Core Location, Game Kit as well as provisioning and unit-testing. We also hope to look at visual technologies like Core Graphics and Core Animation, as well model-related APIs like Core Data and web service-related libraries.</p>
                                                                              
                                                                              <p>The iPhone SDK is huge and there's a ton of material out there to cover. We're very excited to kick off what we hope will be a useful and successful instructional series for perspective iPhone developers out there. Let us know what you want to see.</p>
                                                                          ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                              EvriVerse 2.0
                                                                          ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/' />
    <updated>2009-08-19T16:27:18-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/08/19/evriverse-2-0/</id>
    <content type='html'>
      <![CDATA[
                                                                                <p><img src="/images/2009/08/photo-5.jpg" class="left"/></p>
                                                                                
                                                                                <p>I just wanted to make a quick announcement that the <a href="http://evriverse.evri.com">iPhone app</a> I've been building at <a href="http://evri.com">work</a> just released a major update today. It's in the App Store and it's free. Check it out.</p>
                                                                                
                                                                                <p>Working on this release was a <em>ton</em> of fun. We cleaned up a good bit of the mess from the earlier version and  added some cool new features. What was even more fun was <em>removing</em> functionality that either didn't work well or wasn't obvious to the user. My god, there is <em>nothing</em> I love as much as deleting code. I don't know why I don't look for more opportunities to do this. Not only is it personally and emotionally liberating, it's often the "right" thing to do.</p>
                                                                                
                                                                                <p>The features we pulled out really had no business being in there in the first place. Of course, we didn't know that until we released the first version, got feedback from folks and spent some time outside of the development process. Y'know, hindsight, 20/20, blah blah blah.</p>
                                                                                
                                                                                <p>I think it is exceedingly difficult to get perspective on your work while you're creating it. There's just too much personal investment in the activity, especially if you get any sort of "flow" going. Creative types <em>love</em> "flow" and hate giving it up for any reason, even if the work suffers as a result. I think that's fine, but that's why there's a separate process known as "editing". The trick, of course, is to balance satisfying your possibly-self-indulgent creative urges with creating something of value.</p>
                                                                                
                                                                                <p>Anyway, that's enough of my philosophical rambling. We also put together a little brochure site at <a href="http://evriverse.evri.com">http://evriverse.evri.com</a>, including a screencast with music composed by yours truly. That process was a whitepaper-grade case study in "stuff you can do with iLife". I grabbed all the footage using <a href="http://store.shinywhitebox.com/home/home.html">iShow U</a>, did all the music in Garage Band (on the bus using the computer keyboard no less) and glued it all together in iMovie. Super simple, super fun.</p>
                                                                                
                                                                                <p>All in all I'm pretty pleased with the result. It's free, so check it out and let me (or <a href="http://evri.com">Evri</a>) know what you think.</p>
                                                                            ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                                Cocoa's Ways of Talking
                                                                            ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/' />
    <updated>2009-06-25T01:53:32-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/06/25/cocoas-ways-of-talking/</id>
    <content type='html'>
      <![CDATA[
                                                                                  <p>Getting objects to talk to one another in Objective-C is a easy as passing a message from one to the other. These messages are typically passed through the message-invocation mechanism of using the square-braces to bind a message and arguments to a receiver. Most of the time this is a perfectly reasonable way to communicate. However there are times when you need objects to communicate <em>without having explicit knowledge of one another.</em></p>
                                                                                  
                                                                                  <p>In this post we'll look at three ways to allow your objects to communicate with each other in a highly-decoupled manner using the Cocoa frameworks. Cocoa provides three common ways of connecting objects for messaging: Notifications, Key-Value Observation and delegate pattern.</p>
                                                                                  
                                                                                  <h3>Notifications</h3>
                                                                                  
                                                                                  <p>Both Cocoa and Cocoa Touch provide a notifications framework built on two classes: <code>NSNotificationCenter</code> and <code>NSNotification</code>. The former contains a singleton instance, (via the <code>defaultCenter</code> method) with which observers register themselves and observables post notifications. The latter is the "envelope" for the notification which can contain an <code>NSDictionary</code> instance of customized data as its payload.</p>
                                                                                  
                                                                                  <p><img src="/images/2009/06/nsnotificationcenter.png" alt="NSNotificationCenter.png" /></p>
                                                                                  
                                                                                  <p>When an object registers for notifications, it specifies a notification to listen for (as a <code>NSString</code>) and, optionally, a target object. If the target is set to an object, only notifications posted by that object will be received. If the target object is set to <code>nil</code>, <em>any</em> object posting that notification will be sent to the receiver. Senders can optionally include a <code>NSDictionary</code> instance filled with domain-specific objects. You can use this as a way to further parameterize a notification, or eschew it altogether.</p>
                                                                                  
                                                                                  <p>Consider the example below:</p>
                                                                                  
                                                                                  <div class="highlight"><pre><span class="k">@implementation</span> <span class="nc">Foo</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">init</span> <span class="p">{</span>&#x000A;      <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">=</span> <span class="p">[</span><span class="n">super</span> <span class="n">init</span><span class="p">])</span> <span class="p">{</span>&#x000A;        <span class="p">[[</span><span class="n">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="p">]</span> <span class="nl">addObserver:</span><span class="n">self</span>&#x000A;                                                 <span class="nl">selector:</span><span class="k">@selector</span><span class="p">(</span><span class="nl">didReceiveNote:</span><span class="p">)</span>&#x000A;                                                     <span class="nl">name:</span><span class="s">@&quot;TheBigNotification&quot;</span>&#x000A;                                                   <span class="nl">object:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;      <span class="p">}</span>&#x000A;      <span class="k">return</span> <span class="n">self</span><span class="p">;</span>&#x000A;    <span class="p">}</span>&#x000A;    &#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">didReceiveNote:</span><span class="p">(</span><span class="n">NSNotification</span> <span class="o">*</span><span class="p">)</span><span class="n">notification</span> <span class="p">{</span>&#x000A;      <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Hey, I got a notification with user info: %@&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">notification</span> <span class="n">userInfo</span><span class="p">]);</span>&#x000A;    <span class="p">}</span>&#x000A;    <span class="k">@end</span>&#x000A;    &#x000A;    <span class="err">@</span><span class="n">implementation</span> <span class="n">Bar</span>&#x000A;    <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">doSomething</span> <span class="p">{</span>&#x000A;      <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;I&#39;m up to something!&quot;</span><span class="p">);</span>&#x000A;      <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">stuff</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="s">@&quot;foo&quot;</span><span class="p">,</span> <span class="s">@&quot;bar&quot;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span>&#x000A;      <span class="p">[[</span><span class="n">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="p">]</span> <span class="nl">postNotificationName:</span><span class="s">@&quot;TheBigNotification&quot;</span>&#x000A;                                                          <span class="nl">object:</span><span class="nb">nil</span>&#x000A;                                                        <span class="nl">userInfo:</span><span class="n">stuff</span><span class="p">];</span>&#x000A;    <span class="p">}</span>&#x000A;    <span class="k">@end</span>&#x000A;    </pre>
                                                                                  </div>
                                                                                  
                                                                                  
                                                                                  <p>Here the <code>Foo</code> class registers itself as a notification receiver for the notification named "TheBigNotification" on <em>any</em> object. The <code>Bar</code> class will post the same notification when the <code>doSomething</code> method is invoked.</p>
                                                                                  
                                                                                  <p>We could have been much more specific about which object to observe, but I think this violates one of the key features of notifications which is that the sender and receiver are decoupled. To me if the receiver is going to go to the trouble of listening for notifications from a specific object, you'd be better off declaring a custom protocol and using the delegate pattern (explained below).</p>
                                                                                  
                                                                                  <p>While at the 2009 WWDC, I had a chance to pick the brains of some Apple engineers and one of them told me that notifications are really intended for one-to-many broadcasts. I think that's a great rule of thumb, because the code can really feel like overkill for single object-to-object messages. However, I'd add one more clause to that rule which is that notifications work for one-to-one messages when you would otherwise have to pass instances around of delegates just to connect objects.</p>
                                                                                  
                                                                                  <p>As an example, consider an iPhone application with a stack of view controllers in a <code>UINavigationController</code> instance. If you have a view controller several steps removed from another view controller (i.e. one is a further up the stack in a tab bar controller) and it needs to call some method back to the view controller lower down in the stack, each intermediate object would need a reference to the delegate class just to pass it down the line. This seems like the worst kind of encapsulation breakage since you're forcing a bunch of otherwise-unrelated classes to have knowledge of a class they don't even use.</p>
                                                                                  
                                                                                  <p>Maybe it's my long track-record with Java, but I pay attention to the classes I import and I like to keep that list as short as possible. The more classes know about each other, the more difficult it is to modify them.</p>
                                                                                  
                                                                                  <p>There's one final thing worth knowing about the <code>NSNotificationCenter</code>, and that is how it works with threads. When one object posts a notification, that call blocks while the notification is delivered to <em>all</em> targets. This means that you want your notification-handling code in the receiving object to be as quick as possible. If you can live with deferred notifications and want to avoid the synchronous nature of notification delivery, you can use the <code>NSNotificationQueue</code> instead.</p>
                                                                                  
                                                                                  <h3>Key-Value Observation</h3>
                                                                                  
                                                                                  <p>When I first read about, and used Key-Value Observation (KVO) it seemed like magic. You simply point one object at another and say "I'd like to know when this attribute changes" and Cocoa handles all of the notifications and threading automatically. Genius!</p>
                                                                                  
                                                                                  <p>KVO also allows you to use a special syntax when specifying the attributes you want to observe so that you can register with an object and traverse its object graph. Let's look at the classic customer/orders/line items example. If you want to know when changes are made to any line items in an order you would observe changes in the order like so:</p>
                                                                                  
                                                                                  <div class="highlight"><pre><span class="n">Order</span> <span class="o">*</span><span class="n">order</span> <span class="o">=</span> <span class="p">[</span><span class="n">self</span> <span class="n">anyOrder</span><span class="p">];</span>&#x000A;    <span class="p">[</span><span class="n">order</span> <span class="nl">addObserver:</span><span class="n">self</span>&#x000A;            <span class="nl">forKeyPath:</span><span class="s">@&quot;lineItems&quot;</span>&#x000A;               <span class="nl">options:</span><span class="n">NSKeyValueObservingOptionNew</span> <span class="o">|</span> <span class="n">NSKeyValueObservingOptionOld</span>&#x000A;               <span class="nl">context:</span><span class="nb">nil</span><span class="p">];</span>&#x000A;    </pre>
                                                                                  </div>
                                                                                  
                                                                                  
                                                                                  <p>Whenever you register for KVO, you <em>must</em> implement the method <code>- observeValueForKeyPath:ofObject:change:context:</code>. Unlike notifications, you don't get to specify a selector. This means that if you're object is observing several other objects, you will have to inspect the object given in the callback method and dispatch appropriately.</p>
                                                                                  
                                                                                  <p>Key paths have a ton of flexibility including the ability to traverse deep object graphs and observe aggregate functions on a collection (e.g. observe the max date of all of a customer's orders). Check out the <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">Key-Value Programming Guide</a> for details, which is an indispensable reference.</p>
                                                                                  
                                                                                  <p>KVO works like notifications in that the thread that invokes the change will block until all observers have been notified and their callback methods have been invoked. Unlike notifications, there is no built-in asynchronous KVO-triggering mechanism unless you explicitly mutate properties in another thread using something like the <code>detachNewThreadSelector:toTarget:withObject:</code> class method of <code>NSThread</code>.</p>
                                                                                  
                                                                                  <p>For classes to be key-value <em>observable</em> they must be, what the documentation calls, "key-value compliant". This generally means that each observable property exposes certain methods for accessing and mutating them. Again, <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">the KVO guide</a> is your go-to reference.</p>
                                                                                  
                                                                                  <p>KVO is structurally similar to notifications, but is really intended for fine-grained messaging, generally around your model classes. Notifications are intended for broader application-level events. Both mechanisms give you a way to decouple classes that would otherwise need more intimate knowledge of one another.</p>
                                                                                  
                                                                                  <p>Consider the simple case of managing a tabular view of line items in an order. When a user adds a line item, removes a line item or updates the quantity of a line item we want a field showing the total price to be updated. Without KVO we would need to add extra logic in our event-handing for the table view to also update the total field. With KVO our event-handling logic can simply focus on updating the underlying model. The total field will simply observe the total cost of the order and be updated appropriately. Now if we want to remove the total field or perhaps add another view of total information, we don't have to touch the original event-handing code.</p>
                                                                                  
                                                                                  <h3>Delegates</h3>
                                                                                  
                                                                                  <p>If you've spent any time with the Cocoa docs you'll run across The Delegate Pattern. This thing is like the quark&mdash;it is the fundamental building block of the Cocoa APIs. Conceptually, it's really pretty simple. A delegate is simply an object that provides custom behavior for another object, often by implementing a specific protocol.</p>
                                                                                  
                                                                                  <p>Let's return to our running example. A table view of line items in an order has to handle a lot of things such as rendering each cell, handling scrolling, managing user-generated events and so on. These features are common enough that they are simply part of the table view class itself. What is specific to your application is the <em>data</em> that goes in those cells and <em>the actions</em> to be taken for user-generated events. Cocoa solves this by providing protocols for delegating that behavior to custom classes. In the case of providing data, a data-oriented delegate would be queried by the table view for the total number of rows, appropriate object to put in each row, the column headers, etc. In the case of event-handling, the table view will forward events to the event-handling delegate.</p>
                                                                                  
                                                                                  <p>Notifications use the <code>NSNotificationCenter</code> (or by proxy, the <code>NSNotificationQueue</code>) as an intermediary between message-senders and message-receivers. KVO uses the observed object as the intermediary. In the delegate model there is no intermediate object, but you still have relatively decoupled code because the object that invokes methods on the delegate has no knowledge of what <em>class</em> of object it's dealing with. Put another way, you could remove all of the classes in your project that implement a particular delegate protocol, and the class that <em>uses</em> the delegate would still compile correctly.</p>
                                                                                  
                                                                                  <p>The delegate pattern isn't so much about decoupling which objects are communicating with each other, as much as decoupling the classes of those objects. This doesn't make it any less powerful than the other two methods. In a lot of cases a simple delegate model is much more straightforward and preferable the alternatives.</p>
                                                                                  
                                                                                  <p>The delegate pattern is Cocoa's version of dependency injection. The object receiving the injected dependency has no idea of the type (and by extension, the implementation) of the object it is receiving, only what it's capabilities are via a contract specified as a protocol. This is basic polymorphism where the interface and the implementation are separated to reduce coupling.</p>
                                                                                  
                                                                                  <p>Delegating is a popular alternative to sub-classing. It is a <em>preferred</em> alternative because it's less likely to break encapsulation. If customization is done through subclassing it can be difficult to know which methods to override and implement, and easy to break the parent class. This is why Java provides all sorts of safety features like marking methods <code>abstract</code> and <code>final</code>. However that is simply more of a headache to deal with and using polymorphism would be a much better design.</p>
                                                                                  
                                                                                  <p>So there you have it, three ways to keep your code flexible and loosely-coupled!</p>
                                                                                  
                                                                                  <h3>Resources</h3>
                                                                                  
                                                                                  <ul>
                                                                                  <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html">Apple's Notification Programming Topics</a></li>
                                                                                  <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html">Apple's Key-Value Coding Programming Guide</a></li>
                                                                                  <li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html">Apple's Cocoa Fundamentals</a></li>
                                                                                  <li><a href="http://www.mikeash.com/?page=pyblog/key-value-observing-done-right.html">Mike Ash's Well-Reasoned Critique of KVO Design</a></li>
                                                                                  </ul>
                                                                              ]]>
    </content>
  </entry>
  <entry>
    <title>
      <![CDATA[
                                                                                  The iPhone and Web APIs
                                                                              ]]>
    </title>
    <link href='http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/' />
    <updated>2009-05-27T03:57:39-07:00</updated>
    <id>http://alexvollmer.com/posts/2009/05/27/the-iphone-and-web-apis/</id>
    <content type='html'>
      <![CDATA[
                                                                                    <h1>The iPhone Ecosystem</h1>
                                                                                    
                                                                                    <p>We live in a very interesting time for application development. The distinctions between desktop, browser and mobile applications are blurring more and more every day. "Ubiquitous platform" applications, like <a href="http://evernote.com">Evernote</a>, are where the future is because it reduces the major hurdle of access for users. As time goes on users are going to expect applications to be available in a bunch of different ways that all need to work together.</p>
                                                                                    
                                                                                    <p>The common way to do this is base the application on shared-state accessed via an HTTP-based API. This makes it relatively easy to create apps for various devices as well as offer up a public API for others to use. An interesting side-effect of this is that the API, the shared-state and data behind it become the differentiator between products. The end-user client software is simply the packaging, turning the stand-alone application market into something more akin to the "razors and razor-blades model".</p>
                                                                                    
                                                                                    <p>Okay, none of this should be earth-shattering news to anyone. You should be prepared to write more apps that are integrated with one (or possibly more) "backend services". These services will, as likely as not, be connected over HTTP. As an iPhone developer you should know how to do this in your sleep.</p>
                                                                                    
                                                                                    <p>The <a href="http://www.evri.com">Evri</a> API is absolutely crucial to the EvriVerse phone application. Without it, the app does <em>nothing</em> of interest on its own. Our iPhone application is merely one kind of presentation of our web APIs. I don't think that's unique. What good would Tweetie be without Twitter?</p>
                                                                                    
                                                                                    <h1>Dealing with Web APIs</h1>
                                                                                    
                                                                                    <p>An unfortunate fact of integrating with web APIs is that they are, relatively speaking, slow. We don't want the user to get frustrated and give up on our app because they have their flow continually disrupted by waiting for data.</p>
                                                                                    
                                                                                    <p>There are some things you can do to mitigate the latency costs, if you control the API such as using some sensible caching parameters. However, especially if you don't control the web API, the bulk of what you should focus on is <em>concurrency</em> within your application. The biggest arrow in your quiver is figuring out how to turn unnecessarily serial operations into parallel ones. Now keep in mind that the iPhone doesn't support true multi-core concurrency. What I'm talking about is taking advantage of the I/O wait times that are inherently part of working with a high-latency I/O source (the web).</p>
                                                                                    
                                                                                    <p>Coming from a Java background, using threads seemed like a pretty natural approach and after reading the docs on the <code>NSThread</code>class I felt pretty confident I knew how to make it work. However, I was surprised by how quickly the code complicated. There is a lot to like about Objective-C, but I sorely miss Ruby's blocks and even Java's inner-classes. In Objective-C you connect methods together dynamically by handing objects selectors. The problem with this is that it's difficult to tell the high-level methods from the low-level callback methods just by looking at your class definition. Yes, you can use special comments and the like, but if you've worked in a language that has <em>structural</em> support for this differentiation, moving to a language without it feels like losing an arm.</p>
                                                                                    
                                                                                    <p>So instead of managing your own threads, let Cocoa Touch do the work for you. The <code>NSURLConnection</code> class is inherently asynchronous&mdash;you can fire a request and immediately move one with your life. Now you just need a little structure for handling the response and getting it back into your views.</p>
                                                                                    
                                                                                    <h1>The EvriApi</h1>
                                                                                    
                                                                                    <p>We tried to push as much of the mechanics of URL-handling into a separate code-base we call <a href="http://github.com/evri/EvriApi">EvriApi</a>. A good bit of the design was inspired by Matt Gemmell's <a href="http://mattgemmell.com/2008/02/22/mgtwitterengine-twitter-from-cocoa">MGTwitterEngine</a>, so I can't claim that I came up with the whole idea myself.</p>
                                                                                    
                                                                                    <p>We wanted the API to be as simple to work with as possible. Each API call has the same structure:
                                                                                    *  Each API method takes zero-or-more domain-specific parameters, a selector and a target object.
                                                                                    *  Each API method returns a unique request identifier
                                                                                    *  The target object will have the given selector called when the request completes, and will be given an instance of the <code>EvriAPIResponse</code> class.
                                                                                    *  If the response is successful (check <code>[response success]</code>), the payload of the request is retrieved as a domain-object
                                                                                    *  If the response is unsuccessful, check the error message on the response
                                                                                    *  Requests can be cancelled by handing the request identifier back to the API
                                                                                    *  Attempts to cancel already-completed requests do nothing</p>
                                                                                    
                                                                                    <p>The <code>NSURLConnection</code> class makes asynchronous requests by default, and uses the familiar delegate model for handling the response. When a client invokes an API method, it returns immediately with a unique identifier (as a <code>NSString</code> instance) and the request is initiated on another thread which is handled automatically by <code>NSURLConnection</code>. The client is responsible for keeping track of that and using it to cancel any outstanding requests.</p>
                                                                                    
                                                                                    <p>When the request completes, the body of the response is parsed using the <code>NSXMLParser</code> class. The parser is given one of our specialized XML handlers as a delegate. These handlers deal with the XML event-stream and produce a model object or collection of model objects. The framework then packages this up into an <code>EvriAPIResponse</code> instance and invokes the selector given in the original request on the target given in the original request.</p>
                                                                                    
                                                                                    <h1>Wiring it Up</h1>
                                                                                    
                                                                                    <p>The EvriVerse app is primarily a "productivity" style application. In <a href="http://developer.apple.com/iPhone/library/documentation/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html">Interface Guidelines</a>-parlance this means that we use a lot of hierarchical navigation. In general we have no more than one or two API calls associated with a particular view controller.</p>
                                                                                    
                                                                                    <p>The common pattern for handling a user-initiated action that requires an API call is:</p>
                                                                                    
                                                                                    <ol>
                                                                                    <li>A new view-controller is instantiated and displayed, typically with an activity indicator visible</li>
                                                                                    <li>User-interaction is disabled on the new view controller</li>
                                                                                    <li>The new view controller is displayed (usually by pushing it on the navigation controller stack).</li>
                                                                                    <li>A request is submitted to the <code>EvriApi</code>, setting the new view controller as the target and some special method as the target selector.</li>
                                                                                    <li>The request ID from the <code>EvriApi</code> is given to the newly-created view-controller</li>
                                                                                    <li>When the API request finishes, the handler method on the new view-controller executes, handling both success and failure cases. It also re-enabled user interaction on the view.</li>
                                                                                    <li>If the user navigates back before the request has completed, any outstanding requests are cancelled. This is usually handled in the <code>viewWillDisapper:(BOOL)animated</code> method of the view controller.</li>
                                                                                    </ol>
                                                                                    
                                                                                    
                                                                                    <p>Stepping back, the actors and interactions look something like this:</p>
                                                                                    
                                                                                    <p><img src="/images/2009/05/evri-api.png" alt="evri-api.png" /></p>
                                                                                    
                                                                                    <p>In code (snippets) it might look something like this:</p>
                                                                                    
                                                                                    <div class="highlight"><pre>    <span class="c1">// our parent view controller</span>&#x000A;        <span class="k">@implementation</span> <span class="nc">ParentViewController</span>&#x000A;        <span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">didSelectEntity</span> <span class="p">{</span>&#x000A;          <span class="n">ChildViewController</span> <span class="o">*</span><span class="n">cvc</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">ChildViewController</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>&#x000A;        &#x000A;          <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">navigationController</span> <span class="nl">pushController:</span><span class="n">cvc</span> <span class="nl">animated:</span><span class="n">NO</span><span class="p">];</span>&#x000A;        &#x000A;          <span class="n">NSString</span> <span class="o">*</span><span class="n">requestId</span> <span class="o">=</span> <span class="p">[</span><span class="n">EvriApi</span> <span class="nl">fetchEntityByURI:</span><span class="n">entity</span><span class="p">.</span><span class="n">uri</span>&#x000A;                                          <span class="nl">performSelector:</span><span class="err">@</span><span class="p">(</span><span class="nl">didReceiveEntityResponse:</span><span class="p">)</span>&#x000A;                                                 <span class="nl">onTarget:</span><span class="n">cvc</span><span class="p">];</span>&#x000A;        <span class="p">}</span>&#x000A;        <span class="k">@end</span>&#x000A;    &#x000A;    &#x000A;    &#x000A;        <span class="err">@</span><span class="n">interface</span> <span class="n">ChildViewController</span> <span class="o">:</span> <span class="n">UITableViewController</span> <span class="p">{</span>&#x000A;          <span class="n">NSString</span> <span class="o">*</span><span class="n">requestId</span><span class="p">;</span>&#x000A;        <span class="p">}</span>&#x000A;        &#x000A;        <span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="
