<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[Fickle Bits]]></title>
  
  <link href="http://benscheirman.com/" />
  <updated>2012-07-14T08:29:48-05:00</updated>
  <id>http://benscheirman.com/</id>
  <author>
    <name><![CDATA[Ben Scheirman]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/flux88" /><feedburner:info uri="flux88" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[Houston Code Camp - Call for Speakers]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/e9OVlDJ5jHk/" />
    <updated>2012-07-14T08:03:00-05:00</updated>
    <id>http://benscheirman.com/2012/07/houston-code-camp-call-for-speakers</id>
    <content type="html">&lt;p&gt;&lt;a href="http://houstoncodecamp.com"&gt;Houston Code Camp 2012&lt;/a&gt; is happening on August 25th
at the Microsoft offices in Houston, TX.&lt;/p&gt;

&lt;p&gt;This is going to be a great event!  Last year we had sessions on Ruby, C#, JavaScript, iOS, and lots more.  It&amp;#8217;s definitely a polyglot event
where there is something for everyone.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re looking for speakers, so if you&amp;#8217;re interested in speaking, please
&lt;a href="http://houstoncodecamp.com/session_suggestions/new"&gt;submit a topic&lt;/a&gt;. I hope you&amp;#8217;ll consider being a part of it.&lt;/p&gt;

&lt;p&gt;Registration is not yet open, but keep a look out on &lt;a href="http://twitter.com/houstoncodecamp"&gt;twitter&lt;/a&gt; or this blog for more details.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=e9OVlDJ5jHk:pfNsczCvcNQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=e9OVlDJ5jHk:pfNsczCvcNQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=e9OVlDJ5jHk:pfNsczCvcNQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=e9OVlDJ5jHk:pfNsczCvcNQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2012/07/houston-code-camp-call-for-speakers/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Serving Assets from S3 on Heroku]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/cQLpquSKlTo/" />
    <updated>2012-07-07T11:17:00-05:00</updated>
    <id>http://benscheirman.com/2012/07/serving-assets-from-s3-on-heroku</id>
    <content type="html">&lt;p&gt;Recently I changed &lt;a href="http://nsscreencast.com"&gt;NSScreencast&lt;/a&gt; to use a &lt;a href="http://en.wikipedia.org/wiki/Content_delivery_network"&gt;CDN&lt;/a&gt;
to serve up assets from a different, faster server.&lt;/p&gt;

&lt;h2&gt;Why use a CDN?&lt;/h2&gt;

&lt;p&gt;Using a CDN has numerous benefits.  First, and foremost, this alleviates a bunch of secondary requests that
would normally hit your webserver.  Loading the home page of NSScreencast loads more than a dozen images, stylesheets, and
javascript files.  When deploying to Heroku this can be especially problematic as each asset request will occupy one of your
dynos for a short time.  In the spirit of maximizing your free dyno on Heroku, not sending these requests to your app is definitely
a big win.&lt;/p&gt;

&lt;p&gt;In addition, most browsers have a setting that limits the number of connections (usually 2) that it will open
in parallel to a given domain.  By using a CDN, you can increase the number of parallel requests
because these assets are not served up by your application&amp;#8217;s domain.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s also a common practice to use dns to &amp;#8220;alter&amp;#8221; the domain so that you can maximize this parallelization.&lt;/p&gt;

&lt;h2&gt;Using the asset sync gem&lt;/h2&gt;

&lt;p&gt;Following the instructions on &lt;a href="https://devcenter.heroku.com/articles/cdn-asset-host-rails31"&gt;Heroku&amp;#8217;s Devcenter article&lt;/a&gt; I
decided to use the &lt;code&gt;asset_sync&lt;/code&gt; gem.  This gem will upload your compiled assets to your preferred CDN (any file storage server that
&lt;a href="https://github.com/fog/fog/"&gt;fog&lt;/a&gt; supports).  In my case, I wanted to use S3.&lt;/p&gt;

&lt;p&gt;The first step is adding this gem to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:assets&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# other asset gems&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;asset_sync&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It&amp;#8217;s important to put this in your asset group, as your running app doesn&amp;#8217;t need to load this into memory.&lt;/p&gt;

&lt;p&gt;Then you need to configure the gem.  I found Heroku&amp;#8217;s instructions to be lacking here, as I had to dig into
the &lt;a href="https://github.com/rumblelabs/asset_sync"&gt;&lt;code&gt;asset_sync&lt;/code&gt; github page&lt;/a&gt; to make this work.&lt;/p&gt;

&lt;p&gt;Add a file called &lt;code&gt;config/initializers/asset_sync.rb&lt;/code&gt; to your app:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Since this gem is only loaded with the assets group, we have to check to &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# see if it&amp;#39;s defined before configuring it.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;AssetSync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="no"&gt;AssetSync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fog_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;AWS&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_ACCESS_KEY_ID&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_SECRET_ACCESS_KEY&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fog_directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FOG_DIRECTORY&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c1"&gt;# Fail silently.  Useful for environments such as Heroku&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fail_silently&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;That last config line is important.  When you deploy to Heroku, your app&amp;#8217;s assets will get precompiled.  But because Heroku
doesn&amp;#8217;t initialize your app on precompile, none of your settings will be available.  Instead we&amp;#8217;ll have to run the precompile again,
manually, to get AssetSync to kick in.&lt;/p&gt;

&lt;h2&gt;Setting up the configuration with Heroku San&lt;/h2&gt;

&lt;p&gt;Since I like to have multiple environments, I use &lt;a href="https://github.com/fastestforward/heroku_san"&gt;&lt;code&gt;heroku_san&lt;/code&gt;&lt;/a&gt; to manage them, including
the environment variables.&lt;/p&gt;

&lt;p&gt;Inside of &lt;code&gt;config/heroku.yml&lt;/code&gt;, set up the following for each environment:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;FOG_PROVIDER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;AWS&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;FOG_DIRECTORY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nsscreencast-assets&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;your access key&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Configuring Your Rails app to use S3 as an Asset Host&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;config/production.rb&lt;/code&gt; (and &lt;code&gt;staging.rb&lt;/code&gt; if you have one), make sure to add the
following line to allow Rails to generate the appropriate links for your assets:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asset_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;scheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssl?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FOG_DIRECTORY&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.s3.amazonaws.com&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This will allow your app to serve up the URLs using SSL if the request is coming via SSL.  Doing
this can avoid warnings in the browser that your app contains secure and unsecure content.&lt;/p&gt;

&lt;h2&gt;Testing it all out&lt;/h2&gt;

&lt;p&gt;If all of this is configured correctly, you can test it out by doing a push&amp;#8230;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You&amp;#8217;ll see the asset precompile going on in the logs, and likely an error related to AssetSync.  This is fine (and
in fact, this tripped me up at first).  Once
the deploy has completed, you&amp;#8217;ll have to run this command to upload your assets:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="ss"&gt;:precompile&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;yourapp&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Doing this, you should see something like the following output:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Precompiling&lt;/span&gt; &lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Uploading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Uploading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Uploading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Uploading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Set up Heroku San to do this on every deploy&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;d likely forget to run this command every once in a while, so I set up Heroku San to run this command
after every deploy.&lt;/p&gt;

&lt;p&gt;To do this, add a new rake task in your app (&lt;code&gt;lib/tasks/deploy.rake&lt;/code&gt;):&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:after_deploy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="no"&gt;HerokuSan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each_app&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;---&amp;gt; Precompiling asssets &amp;amp; uploading to the CDN&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;heroku run rake assets:precompile --app &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now when you run your deploy via &lt;code&gt;rake production deploy&lt;/code&gt; this will happen automatically.&lt;/p&gt;

&lt;h2&gt;So what&amp;#8217;s the net result?&lt;/h2&gt;

&lt;p&gt;Doing this alleviated nearly 30 secondary requests to my application for each page load.  That alone is pretty huge.  Also, S3 is
much faster at serving these assets than nginx is (at least via a Heroku app on 1 dyno).&lt;/p&gt;

&lt;p&gt;I tested this before and after by clearing the cache and doing a fresh page load.  Using the Chrome Inspector, I looked at the time to load the page and all assets.
Here are my findings:&lt;/p&gt;

&lt;table style="margin: 25px;"&gt;
  &lt;tr&gt;
    &lt;td style="border: solid 1px #ddd; padding: 3px 7px;"&gt;
      &lt;strong&gt;Before&lt;/strong&gt; (&lt;em&gt;serving assets with no CDN&lt;/em&gt;)
    &lt;/td&gt;
    &lt;td style="border: solid 1px #ddd; padding: 3px 7px;"&gt;3.27 seconds&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td style="border: solid 1px #ddd; padding: 3px 7px;"&gt;&lt;strong&gt;After&lt;/strong&gt;
    (&lt;em&gt;using S3 as a CDN&lt;/em&gt;)
    &lt;/td&gt;
    &lt;td style="border: solid 1px #ddd; padding: 3px 7px;"&gt;1.07 seconds&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;That&amp;#8217;s a huge gain for a minor change in your application &amp;amp; deployment process.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=cQLpquSKlTo:iWgGbArtdyQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=cQLpquSKlTo:iWgGbArtdyQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=cQLpquSKlTo:iWgGbArtdyQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=cQLpquSKlTo:iWgGbArtdyQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2012/07/serving-assets-from-s3-on-heroku/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Hello, NSScreencast]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/3Fbob8oVwh0/" />
    <updated>2012-02-10T06:27:00-06:00</updated>
    <id>http://benscheirman.com/2012/02/hello</id>
    <content type="html">&lt;p&gt;&lt;a href="http://nsscreencast.com"&gt;NSScreencast&lt;/a&gt; is now live. The first 2 videos have been posted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nsscreencast.com/episodes/1-objective-c-basics"&gt;Objective-C Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nsscreencast.com/episodes/2-diagnosing-memory-problems"&gt;Diagnosing Memory Problems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Now that the site has launched, I can share more details with you about it.&lt;/p&gt;

&lt;h3&gt;A new video each week&lt;/h3&gt;

&lt;p&gt;Each week, a new video will be posted covering a single, focused topic related to iOS development.&lt;/p&gt;

&lt;h3&gt;Don&amp;#8217;t waste the listener&amp;#8217;s time&lt;/h3&gt;

&lt;p&gt;Each video will be short and to the point. It boils down to this: a 20 minute video is an easy thing to watch.  A 60-minute video is a serious time commitment.&lt;/p&gt;

&lt;h3&gt;Some Free, Some Paid&lt;/h3&gt;

&lt;p&gt;Eventually, NSScreencast will be a subscription service.  I&amp;#8217;ll announce details once they are nailed down, but for now, enjoy the videos!
If you&amp;#8217;d like to be notified when an episode is released, you can &lt;a href="http://feeds.feedburner.com/NSScreencast"&gt;subscribe to the RSS feed&lt;/a&gt;,
or follow &lt;a href="http://twitter.com/nsscreencast"&gt;@nsscreencast&lt;/a&gt; on twitter.  (&lt;em&gt;Subscribing in iTunes is coming soon&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;If you have any video topic suggestions, feel free to share them at the &lt;a href="http://nsscreencast.uservoice.com"&gt;User Voice Forum&lt;/a&gt;.
Seriously, I&amp;#8217;d love to hear your feedback!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=3Fbob8oVwh0:WOidBiZox3c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=3Fbob8oVwh0:WOidBiZox3c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=3Fbob8oVwh0:WOidBiZox3c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=3Fbob8oVwh0:WOidBiZox3c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2012/02/hello/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[NSScreencasts, Coming Soon]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/ni1eAlVJOSw/" />
    <updated>2012-01-19T22:47:00-06:00</updated>
    <id>http://benscheirman.com/2012/01/nsscreencasts</id>
    <content type="html">&lt;h2&gt;Bite-Sized Learning&lt;/h2&gt;

&lt;p&gt;Video training is becoming a very common way to learn these days.  With &lt;a href="http://tekpub.com"&gt;Tekpub&lt;/a&gt;, &lt;a href="http://peepcode.com/"&gt;Peepcode&lt;/a&gt;, &lt;a href="http://pluralsight.com"&gt;Pluralsight&lt;/a&gt;,
&lt;a href="http://codeschool.com"&gt;Code School&lt;/a&gt;, and many others, there are usually great productions to teach you any development topic that you&amp;#8217;d want to learn about.&lt;/p&gt;

&lt;p&gt;All of these services are great, however I&amp;#8217;m becoming a fan of the smaller, more focused screencasts.  &lt;a href="http://railscasts.com"&gt;Railscasts&lt;/a&gt;, for instance, has
been &lt;em&gt;instrumental&lt;/em&gt; to my Rails learning development.  &lt;a href="http://destroyallsoftware.com/"&gt;Destroy all Software&lt;/a&gt; teaches me new things every week.&lt;/p&gt;

&lt;p&gt;Smaller videos like this are easier to digest, and are more focused on a single topic.  Like the &lt;a href="http://en.wikipedia.org/wiki/Boiling_frog"&gt;boiled frog&lt;/a&gt;
you eventually realize how far you&amp;#8217;ve come on a topic, simply by watching regular videos.&lt;/p&gt;

&lt;p&gt;iOS Development is an ever-changing landscape, with so many topic areas to cover, that a single training class or screencast series just
can&amp;#8217;t teach you all of it.  Instead of trying to cover everything in depth (increasing the length of videos). I find it valuable to
have smaller, focused tutorials that teach you one thing, and do it quickly and effectively.&lt;/p&gt;

&lt;h2&gt;Introducing NSScreencast&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://nsscreencast.com"&gt;NSScreencast&lt;/a&gt; will be launching soon and will feature regular bite-sized videos
focused on a single topic related to Objective-C and building iOS applications.&lt;/p&gt;

&lt;p&gt;NSScreencast &lt;em&gt;will&lt;/em&gt; include free videos. Down the road, a nominal paid subsribtion will unlock access to more content.&lt;/p&gt;

&lt;p&gt;I still have lots to do before I release the first video, but if you like the idea, please sign up on
the site to be notified when it launches. Thanks!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ni1eAlVJOSw:VzMEeKJkOvQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ni1eAlVJOSw:VzMEeKJkOvQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ni1eAlVJOSw:VzMEeKJkOvQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=ni1eAlVJOSw:VzMEeKJkOvQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2012/01/nsscreencasts/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Careful With Block-Based Notification Handlers]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/17G4hUzhVFw/" />
    <updated>2012-01-11T16:27:00-06:00</updated>
    <id>http://benscheirman.com/2012/01/careful-with-block-based-notification-handlers</id>
    <content type="html">&lt;p&gt;In general, I prefer using block-based APIs over those that accept selectors.&lt;/p&gt;

&lt;p&gt;The block based APIs are generally easier to read &amp;amp; follow, and don&amp;#8217;t clutter up your class with methods that are
out of context with the code that might potentially invoke them.&lt;/p&gt;

&lt;h2&gt;An Example&lt;/h2&gt;

&lt;p&gt;One good example is view animations.  Here we&amp;#8217;re fading out a view and removing it from the hierarchy once
the view has been completely faded out.  It&amp;#8217;s concise, easy to read, and you don&amp;#8217;t need to go anywhere else in the
class to get a complete picture of how this works.&lt;/p&gt;

&lt;p&gt;Also, since you can have multiple animations going on, having a block-based completion handler means
you don&amp;#8217;t have to distinguish between what the animations were in some generic completion method.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="nl"&gt;animateWithDuration:&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="nl"&gt;animations:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;someView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nl"&gt;completion:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;someView&lt;/span&gt; &lt;span class="n"&gt;removeFromSuperView&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Contrast this with the non-block version:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;fadeOutView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="n"&gt;beginAnimations&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="nl"&gt;setAnimationDuration:&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="nl"&gt;setAnimationDelegate:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="nl"&gt;setAnimationDidStopSelector:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;animationDidStop:finished:context:&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;someView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="n"&gt;commitAnimations&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;animationDidStop:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;animationID&lt;/span&gt; &lt;span class="nf"&gt;finished:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSNumber&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;finished&lt;/span&gt; &lt;span class="nf"&gt;context:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;someView&lt;/span&gt; &lt;span class="n"&gt;removeFromSuperView&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Block-Based Notification Handlers&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NSNotificationCenter&lt;/code&gt; also got some block love when iOS SDK 4.0 came around.  The old form looked like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setupNotifications&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSNotificationCenter&lt;/span&gt; &lt;span class="n"&gt;defaultCenter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;addObserver:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                           &lt;span class="nl"&gt;selector:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;onWhizBang:&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                               &lt;span class="nl"&gt;name:&lt;/span&gt;&lt;span class="n"&gt;MyWhizBangnotification&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                             &lt;span class="nl"&gt;object:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;onWhizBang:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSNotification&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;notification&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;// reload the table to show the new whiz bangs&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tableView&lt;/span&gt; &lt;span class="n"&gt;reloadData&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;dealloc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSNotificationCenter&lt;/span&gt; &lt;span class="n"&gt;defaultCenter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;removeObserver:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;dealloc&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This isn&amp;#8217;t a lot of code (and it is easy to remember, unlike the previous UIView animation block code), however
the action and the notification handler are separated from each other.&lt;/p&gt;

&lt;p&gt;The block-based API looks like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setupNotifications&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSNotificationCenter&lt;/span&gt; &lt;span class="n"&gt;defaultCenter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nl"&gt;addObserverForNotificationName:&lt;/span&gt;&lt;span class="n"&gt;MyWhizBangNotification&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                              &lt;span class="nl"&gt;object:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                               &lt;span class="nl"&gt;queue:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSOperationQueue&lt;/span&gt; &lt;span class="n"&gt;mainQueue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                               &lt;span class="nl"&gt;block:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSNotification&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                 &lt;span class="c1"&gt;//reload the table to show the new whiz bangs&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tableView&lt;/span&gt; &lt;span class="n"&gt;reloadData&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                               &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;dealloc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSNotificationCenter&lt;/span&gt; &lt;span class="n"&gt;defaultCenter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;removeObserver:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;dealloc&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Aside from some funky indentation, this is preferable in some cases, especially when the action to
be completed is as simple as reloading the table.&lt;/p&gt;

&lt;p&gt;But there&amp;#8217;s a bug.  Can you spot it?&lt;/p&gt;

&lt;h2&gt;Blocks Are Closures&lt;/h2&gt;

&lt;p&gt;There&amp;#8217;s a subtle bug here that you might not notice at first.  I didn&amp;#8217;t realize this until it was littered all
over my code base.&lt;/p&gt;

&lt;p&gt;Blocks are &lt;a href="http://simple.wikipedia.org/wiki/Closure_(computer_science)"&gt;closures&lt;/a&gt;, and they will capture any values declared outside the scope of the block (and retained) so that
they can be used when the block executes.  This includes variables declared in the enclosing method or any ivars
that you reference from inside the block.&lt;/p&gt;

&lt;p&gt;Here, we used &lt;code&gt;self.tableView&lt;/code&gt;.  &lt;code&gt;self&lt;/code&gt; gets retained by the block, which is also retained by self.  We have a &lt;em&gt;retain-cycle&lt;/em&gt;
which is generally a bad thing.  It&amp;#8217;s especially bad here, because we don&amp;#8217;t clear out the block until &lt;code&gt;dealloc&lt;/code&gt;,
but &lt;em&gt;dealloc won&amp;#8217;t ever be called because the block is retaining the instance&lt;/em&gt;!&lt;/p&gt;

&lt;h2&gt;Weak Pointers Save the Day&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;ve read up on blocks, you&amp;#8217;ve probably seen the &lt;code&gt;__block&lt;/code&gt; keyword.  This specifier tells blocks not to retain the pointer.
So all we need is a new pointer, like so:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;__block&lt;/span&gt; &lt;span class="n"&gt;MyViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// use weakSelf in the blocks, instead of self&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This sort of code drives me nuts.  It won&amp;#8217;t be apparent to the next developer why it&amp;#8217;s there, and it&amp;#8217;s
pretty ugly.&lt;/p&gt;

&lt;h2&gt;Retain Cycles are Elsewhere, Too&lt;/h2&gt;

&lt;p&gt;You might also run into this if you have a parent-child view controller relationship, or perhaps a
an parent-&gt;object-&gt;delegate chain, where the parent &lt;em&gt;is&lt;/em&gt; the delegate.  This is why you typically mark
your delegate property signatures with &lt;code&gt;assign&lt;/code&gt; instead of &lt;code&gt;retain&lt;/code&gt; semantics.&lt;/p&gt;

&lt;p&gt;Not all retain-cycles are terrible though.  If you have a way of breaking the cycle, then you just need
to weigh how long these objects will remain active for to decide if you need to fix it.&lt;/p&gt;

&lt;p&gt;Hopefully this will save you a few headaches down the line.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=17G4hUzhVFw:voGtSjkEgcE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=17G4hUzhVFw:voGtSjkEgcE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=17G4hUzhVFw:voGtSjkEgcE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=17G4hUzhVFw:voGtSjkEgcE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2012/01/careful-with-block-based-notification-handlers/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Formatting JSON From Terminal]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/4MRBjPFJCu4/" />
    <updated>2011-12-12T15:08:00-06:00</updated>
    <id>http://benscheirman.com/2011/12/formatting-json-from-terminal</id>
    <content type="html">&lt;p&gt;I work with JSON APIs a lot. On a current API I work on, there is an OAuth-esque request
signing process that is required to make sure that others cannot forge requests simply
by changing parameters arround.&lt;/p&gt;

&lt;p&gt;A typical request might look like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;HTTP 1.1
&lt;/span&gt;&lt;span class='line'&gt;GET /foo/bars.json
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;Headers:
&lt;/span&gt;&lt;span class='line'&gt;    Accept-Encoding = gzip;
&lt;/span&gt;&lt;span class='line'&gt;    Accept = application/json
&lt;/span&gt;&lt;span class='line'&gt;    Authorization = "cHOLIOb7bAeqFEmsz3io%2Bxg4sQA%3D";
&lt;/span&gt;&lt;span class='line'&gt;    Account-Id = 201;
&lt;/span&gt;&lt;span class='line'&gt;    User-Agent = "...";&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The &lt;code&gt;Authorization&lt;/code&gt; header is generated by concatenating the HTTP Method, URL, any parameters, and then signed with a key.&lt;/p&gt;

&lt;p&gt;Because of this security, it is very difficult to create adhoc requests just to try them out. So instead, we have our iPhone app
&lt;code&gt;NSLog&lt;/code&gt; the proper curl command for us.  Now it&amp;#8217;s as simple as copy &amp;amp; paste from the Xcode Console, which gives me a
less-than-readable output of the JSON.&lt;/p&gt;

&lt;p&gt;Usually for this I just pipe the command into &lt;code&gt;pbcopy&lt;/code&gt; to get it on my clipboard, then I visit &lt;a href="http://jsonlint.com"&gt;JSON Lint&lt;/a&gt; to
make it easy to read.&lt;/p&gt;

&lt;h2&gt;Doin&amp;#8217; it all from Terminal&lt;/h2&gt;

&lt;p&gt;I looked at ways of doing this all from the Terminal, and came across this python command:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;python -mjson.tool&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It takes input from stdin and outputs it formatted nicely.  Sweet!  Now all that&amp;#8217;s needed is to make this a bit more easy to remember,
so I made a script to do this for me called &lt;code&gt;format_json&lt;/code&gt; and put it in my path.&lt;/p&gt;

&lt;p&gt;Now, any time I want to see the JSON output of an API, I can simply type:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl some.server.com/api/devices.json?key&lt;span class="o"&gt;=&lt;/span&gt;124512312 -H Authorization:&lt;span class="s2"&gt;&amp;quot;124151231231123123&amp;quot;&lt;/span&gt; |
&lt;/span&gt;&lt;span class='line'&gt;    format_json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And here is the output:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="s2"&gt;&amp;quot;devices&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;device_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;40f4fc8a5818608dbb9a6c981179222b6f&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;device_type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;iPhone&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Ben&amp;#39;s iPhone&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;push_enabled&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="s2"&gt;&amp;quot;push_token&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a3a36......480c25fdf&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Very handy, indeed.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4MRBjPFJCu4:spmiwtycZbo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4MRBjPFJCu4:spmiwtycZbo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4MRBjPFJCu4:spmiwtycZbo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=4MRBjPFJCu4:spmiwtycZbo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/12/formatting-json-from-terminal/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Houston Tech Fest 2011 Recap]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/a3lHCGUL4Js/" />
    <updated>2011-10-17T10:27:00-05:00</updated>
    <id>http://benscheirman.com/2011/10/houston-tech-fest-2011-recap</id>
    <content type="html">&lt;p&gt;Houston Tech Fest 2011 came and went, and yet again was a great success.
I believe it was the biggest one ever, with over 1,300 registrants.&lt;/p&gt;

&lt;p&gt;I gave three talks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://speakerrate.com/talks/8761-rails-intrigue"&gt;Rails Intrigue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://speakerrate.com/talks/8744-introducing-a-new-feature-to-a-rails-app-from-beginning-to-end"&gt;Introducing a new feature to a Rails app using Cucumber&lt;/a&gt; (with Claudio Lasalla)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://speakerrate.com/talks/8760-wrangle-your-source-like-a-boss-with-git"&gt;Wrangle your source like a boss with git&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You can find the slides &amp;amp; code used in the presentations &lt;a href="http://github.com/subdigital/houston-tech-fest-2011"&gt;here on github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you attended any of these sessions, I&amp;#8217;d really appreciate if you
rate them using the links above.&lt;/p&gt;

&lt;p&gt;See you next year, Houston Tech Fest!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=a3lHCGUL4Js:MyHaAw_cISI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=a3lHCGUL4Js:MyHaAw_cISI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=a3lHCGUL4Js:MyHaAw_cISI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=a3lHCGUL4Js:MyHaAw_cISI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/10/houston-tech-fest-2011-recap/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Appsites Is Now AppKickstand]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/ll_mZA1Hp0U/" />
    <updated>2011-10-13T21:50:00-05:00</updated>
    <id>http://benscheirman.com/2011/10/appsites-is-now-appkickstand</id>
    <content type="html">&lt;p&gt;A few weeks ago I launched Appsites, a free way to quickly host an
attractive splash page for iPhone applications.&lt;/p&gt;

&lt;p&gt;Instead of competing with another site with the same name for traffic
when we could be sharing it, I decided a new name was in order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I now present to you:  &lt;a href="http://appkickstand.com"&gt;AppKickstand&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://appkickstand.com"&gt;&lt;img src="http://benscheirman.com/images/appkickstand.png"
alt="AppKickstand" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For an example of what it looks like with real apps, check out
&lt;a href="http://appkickstand.com/giggletouch"&gt;Giggle Touch&lt;/a&gt; or
&lt;a href="http://appkickstand.com/tallythings"&gt;Tally Things&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have an iPhone app, what are you waiting for?  It&amp;#8217;s &lt;strong&gt;FREE&lt;/strong&gt;!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ll_mZA1Hp0U:WNdZYzfjz74:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ll_mZA1Hp0U:WNdZYzfjz74:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ll_mZA1Hp0U:WNdZYzfjz74:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=ll_mZA1Hp0U:WNdZYzfjz74:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/10/appsites-is-now-appkickstand/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Sharing Vim Configuration Between Machines]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/hZiO4eMTdd8/" />
    <updated>2011-10-06T09:29:00-05:00</updated>
    <id>http://benscheirman.com/2011/10/sharing-vim-configuration-between-machines</id>
    <content type="html">&lt;p&gt;I do most of my development on my MacBook Pro, however I have a nice 27&amp;#8221;
iMac at home, and it is refreshing to use it for development when I can.
It&amp;#8217;s fast and has a huge screen.  The only downside is all my custom
development configurations are on my MacBook Pro!&lt;/p&gt;

&lt;p&gt;There are a number of options you can use to share settings between
machines, but I&amp;#8217;m a fan of using &lt;a href="http://dropbox.com"&gt;Dropbox&lt;/a&gt; (&lt;a href="http://db.tt/sYjPEQl"&gt;referral link&lt;/a&gt;). Any change I make, on either machine, will get automatically
synchronized for me.&lt;/p&gt;

&lt;p&gt;Since my Vim configurations were already present on my MacBook Pro, the
first step was to copy them over to a Dropbox folder:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;mkdir ~/Dropbox/vim
&lt;/span&gt;&lt;span class='line'&gt;cp -R ~/.vim ~/Dropbox/vim
&lt;/span&gt;&lt;span class='line'&gt;cp ~/.vimrc ~/Dropbox/vim
&lt;/span&gt;&lt;span class='line'&gt;cp ~/.vimrc.local ~/Dropbox/vim
&lt;/span&gt;&lt;span class='line'&gt;cp ~/.gvimrc ~/Dropbox/vim&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The next step was to come up with an installer script that would symlink
these files on a new machine.  I made sure to move existing vim files to
a temporary filename so that I wouldn&amp;#8217;t lose anything accidentally.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;set -o errexit
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;function confirm()
&lt;/span&gt;&lt;span class='line'&gt;{
&lt;/span&gt;&lt;span class='line'&gt;    echo -n "$@ "
&lt;/span&gt;&lt;span class='line'&gt;    read -e answer
&lt;/span&gt;&lt;span class='line'&gt;    for response in y Y yes YES Yes Sure sure SURE OK ok Ok
&lt;/span&gt;&lt;span class='line'&gt;    do
&lt;/span&gt;&lt;span class='line'&gt;        if [ "_$answer" == "_$response" ]
&lt;/span&gt;&lt;span class='line'&gt;        then
&lt;/span&gt;&lt;span class='line'&gt;            return 0
&lt;/span&gt;&lt;span class='line'&gt;        fi
&lt;/span&gt;&lt;span class='line'&gt;    done
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    # Any answer other than the list above is considerred a "no" answer
&lt;/span&gt;&lt;span class='line'&gt;    return 1
&lt;/span&gt;&lt;span class='line'&gt;}
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;function link_file() 
&lt;/span&gt;&lt;span class='line'&gt;{
&lt;/span&gt;&lt;span class='line'&gt;  echo "symlinking $1"
&lt;/span&gt;&lt;span class='line'&gt;  ln -s "$PWD/$1" "$HOME/$1"
&lt;/span&gt;&lt;span class='line'&gt;}
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;echo "This will remove any existing vim configuration files and simlink them with the files here."
&lt;/span&gt;&lt;span class='line'&gt;confirm "Are you sure?"
&lt;/span&gt;&lt;span class='line'&gt;if [ $? -eq 0 ]
&lt;/span&gt;&lt;span class='line'&gt;then
&lt;/span&gt;&lt;span class='line'&gt;  for file in ~/.vimrc ~/.vimrc.local ~/.gvimrc
&lt;/span&gt;&lt;span class='line'&gt;  do
&lt;/span&gt;&lt;span class='line'&gt;    if [[ -f $file ]]; then
&lt;/span&gt;&lt;span class='line'&gt;      echo "Moving $file to $file.bak"
&lt;/span&gt;&lt;span class='line'&gt;      mv $file $file.bak
&lt;/span&gt;&lt;span class='line'&gt;    fi
&lt;/span&gt;&lt;span class='line'&gt;  done
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  for dir in ~/.vim
&lt;/span&gt;&lt;span class='line'&gt;  do
&lt;/span&gt;&lt;span class='line'&gt;    if [[ -d $dir ]]; then
&lt;/span&gt;&lt;span class='line'&gt;      echo "Moving $dir directory to $dir.bak"
&lt;/span&gt;&lt;span class='line'&gt;      mv $dir $dir.bak
&lt;/span&gt;&lt;span class='line'&gt;    fi
&lt;/span&gt;&lt;span class='line'&gt;  done
&lt;/span&gt;&lt;span class='line'&gt;fi
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;echo "symlinking"
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;for file in .vim .vimrc .vimrc.local .gvimrc
&lt;/span&gt;&lt;span class='line'&gt;do
&lt;/span&gt;&lt;span class='line'&gt;  link_file $file
&lt;/span&gt;&lt;span class='line'&gt;done
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;echo "Done.  Check that it works.  If so, you can remove the .bak files, if any"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Make sure the script is executable by running:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;chmod +x setup.sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then run this script on any new machine that you want to use Vim on. It will symlink these files from your Dropbox folder to your home
folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.vim/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.vimrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.vimrc.local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.gvimrc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;After it&amp;#8217;s done, check that it is working.  Remove any .bak files that
you don&amp;#8217;t need anymore.&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s it. You have an automatic Vim configuration synching system
between machines.  It works great for your shell configuration as well!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=hZiO4eMTdd8:b1JFtEcpScg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=hZiO4eMTdd8:b1JFtEcpScg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=hZiO4eMTdd8:b1JFtEcpScg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=hZiO4eMTdd8:b1JFtEcpScg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/10/sharing-vim-configuration-between-machines/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Making a UIButton Flip Over]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/bTZQAAH2W0Y/" />
    <updated>2011-10-04T08:44:00-05:00</updated>
    <id>http://benscheirman.com/2011/10/making-a-uibutton-flip-over</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;ve used the iPod app on the iPhone, you&amp;#8217;ve probably seen an
interesting trick when switching from album art to the track listing:
the button in the top right corner flips over synchronized with the flip
animation of the main view.&lt;/p&gt;

&lt;p&gt;I wanted to achieve a similar effect for the iPhone app that I&amp;#8217;m
building, Deli Radio (&lt;a href="http://itunes.com/apps/deliradio"&gt;app store link&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;ve ever struggled with the flip transitions before, you probably
know how finicky it can be to get it all working. The best way to set it
up is to have a parent view contain both views that you want to swap,
and set the animation transition type on &lt;em&gt;that&lt;/em&gt; view.&lt;/p&gt;

&lt;p&gt;For a button (either in the navigation bar or elsewhere) we&amp;#8217;d need to
introduce a parent view to achieve this effect.  This is how I achieved
the effect.&lt;/p&gt;

&lt;p&gt;&lt;img class="right" src="http://benscheirman.com/images/btn-info-border@2x.png"&gt;
&lt;img class="right" src="http://benscheirman.com/images/btn-images@2x.png"&gt;&lt;/p&gt;

&lt;p&gt;First, I had two images I wanted to use for my &lt;code&gt;UIBarButtonItem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wanted this to be easily reusable (since I need to do this in more
than one place in this application), so I created a category method on
&lt;code&gt;UIButton&lt;/code&gt;.&lt;/p&gt;

&lt;div&gt;&lt;script src='https://gist.github.com/1261810.js?file=UIButtonCHButtonFlip.h'&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;@interface UIButton (CHFlipButton)

+ (UIView *)flipButtonWithFirstImage:(UIImage *)firstImage 
                         secondImage:(UIImage *)secondImage
                     firstTransition:(UIViewAnimationTransition)firstTransition
                    secondTransition:(UIViewAnimationTransition)secondTransition
                      animationCurve:(UIViewAnimationCurve)curve
                            duration:(NSTimeInterval)duration
                              target:(id)target
                            selector:(SEL)selector;


@end
&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;It may look strange that a &lt;code&gt;UIButton&lt;/code&gt; class method returns a &lt;code&gt;UIView&lt;/code&gt;
instance, but we need to have a container view to base the animations
off of.&lt;/p&gt;

&lt;p&gt;Here is the implementation:&lt;/p&gt;

&lt;div&gt;&lt;script src='https://gist.github.com/1261810.js?file=UIButtonCHButtonFlip.m'&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;#import &amp;lt;objc/runtime.h&amp;gt;

#import &amp;quot;UIButton+CHFlipButton.h&amp;quot;

// keys used for assigning associated objects
static char UIButtonFlipBlockKey;
static char UIButtonFlipAltButtonKey;
static char UIButtonFlipTransitionKey;
static char UIButtonFlipContainerViewKey;

typedef void (^UIButtonFlipActionBlock)(id sender);

@implementation UIButton (CHFlipButton)

// associate the block with the button instance, then set the default button handler

- (void)chFlipButton_handleControlEvent:(UIControlEvents)event withBlock:(UIButtonFlipActionBlock)block {
    objc_setAssociatedObject(self, &amp;amp;UIButtonFlipBlockKey, block, OBJC_ASSOCIATION_COPY);
    [self addTarget:self action:@selector(chFlipButton_callFlipBlock:) forControlEvents:UIControlEventTouchUpInside];
}

// the default button handler just calls the block

- (void)chFlipButton_callFlipBlock:(id)sender {
    UIButtonFlipActionBlock block = objc_getAssociatedObject(self, &amp;amp;UIButtonFlipBlockKey);
    if (block) {
        block(sender);
    }
}

+ (UIView *)flipButtonWithFirstImage:(UIImage *)firstImage 
                         secondImage:(UIImage *)secondImage
                     firstTransition:(UIViewAnimationTransition)firstTransition
                    secondTransition:(UIViewAnimationTransition)secondTransition
                      animationCurve:(UIViewAnimationCurve)curve
                            duration:(NSTimeInterval)duration
                              target:(id)target
                            selector:(SEL)selector {
    
    UIButtonFlipActionBlock flipButtonAction = ^(id sender) { /* shown further down */ };
    
    //create the first button
    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    [button1 setBackgroundImage:firstImage forState:UIControlStateNormal];
    [button1 chFlipButton_handleControlEvent:UIControlEventTouchUpInside withBlock:flipButtonAction];
    [button1 setFrame:CGRectMake(0, 0, firstImage.size.width, firstImage.size.height)];

    //create the 2nd button
    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
    [button2 setBackgroundImage:secondImage forState:UIControlStateNormal];
    [button2 chFlipButton_handleControlEvent:UIControlEventTouchUpInside withBlock:flipButtonAction];
    [button2 setFrame:CGRectMake(0, 0, secondImage.size.width, secondImage.size.height)];    
 
    //create a container to hold them
    UIView *container = [[[UIView alloc] initWithFrame:button1.bounds] autorelease];
    [container addSubview:button1];
    
    //record state so we can access it later (in the block)
    objc_setAssociatedObject(button1, &amp;amp;UIButtonFlipAltButtonKey, button2, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(button1, &amp;amp;UIButtonFlipTransitionKey, [NSNumber numberWithInt:firstTransition], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(button1, &amp;amp;UIButtonFlipContainerViewKey, container, OBJC_ASSOCIATION_ASSIGN);
    
    objc_setAssociatedObject(button2, &amp;amp;UIButtonFlipAltButtonKey, button1, OBJC_ASSOCIATION_ASSIGN);
    objc_setAssociatedObject(button2, &amp;amp;UIButtonFlipTransitionKey, [NSNumber numberWithInt:secondTransition], OBJC_ASSOCIATION_ASSIGN);  //button1 is in charge of the retains initially
    objc_setAssociatedObject(button2, &amp;amp;UIButtonFlipContainerViewKey, container, OBJC_ASSOCIATION_ASSIGN);
    
    //returns the container, because this is what needs to be added to your view
    return container;
}

@end
&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;I am using a little-known technique of setting associated objects
using &lt;code&gt;objc_setAssociatedObject(...)&lt;/code&gt;.  This uses the runtime to attach
state to an existing class without needing to subclass.&lt;/p&gt;

&lt;p&gt;Now that you understand how it is all setup, the block body will now
make sense:&lt;/p&gt;

&lt;div&gt;&lt;script src='https://gist.github.com/1261810.js?file=UIButtonCHButtonFlipBlock.m'&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;/* Here is that block definition from above */

    UIButtonFlipActionBlock flipButtonAction = ^(id sender) {

        //get the alternate button &amp;amp; container
        UIButton *otherButton = (UIButton *)objc_getAssociatedObject(sender, &amp;amp;UIButtonFlipAltButtonKey);
        UIView *container = (UIView *)objc_getAssociatedObject(sender, &amp;amp;UIButtonFlipContainerViewKey);
        
        //figure out our transition
        NSNumber *transitionNumber = (NSNumber *)objc_getAssociatedObject(sender, &amp;amp;UIButtonFlipTransitionKey);
        UIViewAnimationTransition transition = (UIViewAnimationTransition)[transitionNumber intValue];
                
        [UIView animateWithDuration:duration animations:^ {
            
            [UIView setAnimationTransition:transition forView:container cache:YES];
            [UIView setAnimationCurve:curve];
            
            //the view has the last retain count on the sender button, so we need to retain it first
            objc_setAssociatedObject(otherButton, &amp;amp;UIButtonFlipAltButtonKey, sender, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            
            [sender removeFromSuperview];
            [container addSubview:otherButton];
            
            //sender no longer needs to retain the other button, because the view now is...
            objc_setAssociatedObject(sender, &amp;amp;UIButtonFlipAltButtonKey, otherButton, OBJC_ASSOCIATION_ASSIGN);
            
        }];
        
        //call the original button handler
        [target performSelector:selector withObject:self];
    };
&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;Usage is really easy.  I just created a bar button item with a custom
view, and was done.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;UIImage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;firstImage&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIImage&lt;/span&gt; &lt;span class="nl"&gt;imageNamed:&lt;/span&gt;&lt;span class="s"&gt;@&amp;quot;btn-info.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;UIImage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;secondImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIImage&lt;/span&gt; &lt;span class="nl"&gt;imageNamed:&lt;/span&gt;&lt;span class="s"&gt;@&amp;quot;btn-images.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIButton&lt;/span&gt; &lt;span class="nl"&gt;flipButtonWithFirstImage:&lt;/span&gt;&lt;span class="n"&gt;firstImage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                              &lt;span class="nl"&gt;secondImage:&lt;/span&gt;&lt;span class="n"&gt;secondImage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                          &lt;span class="nl"&gt;firstTransition:&lt;/span&gt;&lt;span class="n"&gt;UIViewAnimationTransitionFlipFromRight&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                         &lt;span class="nl"&gt;secondTransition:&lt;/span&gt;&lt;span class="n"&gt;UIViewAnimationTransitionFlipFromLeft&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                           &lt;span class="nl"&gt;animationCurve:&lt;/span&gt;&lt;span class="n"&gt;UIViewAnimationCurveEaseInOut&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                                 &lt;span class="nl"&gt;duration:&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                                   &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                                                 &lt;span class="nl"&gt;selector:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flipContent&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navigationItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rightBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nl"&gt;initWithCustomView:&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The effect can be seen below.&lt;/p&gt;

&lt;p&gt;&lt;video width='389' height='336' preload='none' controls poster=' https://flux88.s3.amazonaws.com/videos/button_flip1.jpeg'&gt;&lt;source src='https://flux88.s3.amazonaws.com/videos/button_flip.m4v' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'/&gt;&lt;/video&gt;&lt;/p&gt;

&lt;p&gt;Note that the flip effect on the main view is achieved separately, but
the 2 strategies share identical values for the animation, so the flip
transition types match, as well as the duration &amp;amp; animation curve.&lt;/p&gt;

&lt;p&gt;The code for this can be seen in the &lt;a href="https://github.com/chaione/chaioneui"&gt;ChaiOneUI project on Github&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=bTZQAAH2W0Y:7dgalyWfmVw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=bTZQAAH2W0Y:7dgalyWfmVw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=bTZQAAH2W0Y:7dgalyWfmVw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=bTZQAAH2W0Y:7dgalyWfmVw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/10/making-a-uibutton-flip-over/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Creating a Glow Effect for UILabel and UIButton]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/ksLi2yG9hdQ/" />
    <updated>2011-09-27T19:57:00-05:00</updated>
    <id>http://benscheirman.com/2011/09/creating-a-glow-effect-for-uilabel-and-uibutton</id>
    <content type="html">&lt;p&gt;One recent iPhone design mockup called for a glowing effect for a
&lt;code&gt;UIButton&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This can be accomplished with images, however I needed a series of
buttons to have the same glow effect, and it can easily be accomplished
with Core Graphics.&lt;/p&gt;

&lt;p&gt;The first step is to include the Core Graphics headers:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;#import &amp;lt;QuartzCore/QuartzCore.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Next, the effect is achieved by using a shadow with no offset (meaning
the shadow will be directly underneath the text, not shifted down or to
the right).  The layer is then given a shadow radius &amp;amp; opacity to allow
the shadow to bleed outward.  Unsetting &lt;code&gt;masksToBounds&lt;/code&gt; will allow the
glow to be drawn even outside of the label&amp;#8217;s frame. Finally the shadow color is set to either the
foreground color or something a bit lighter.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentTitleColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shadowColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="n"&gt;CGColor&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shadowRadius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;4.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shadowOpacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;.9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shadowOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CGSizeZero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;masksToBounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This effect works on plain &lt;code&gt;UILabel&lt;/code&gt; or the &lt;code&gt;titleLabel&lt;/code&gt; property of a
&lt;code&gt;UIButton&lt;/code&gt;.  You can see the results of the effect here:&lt;/p&gt;

&lt;p&gt;&lt;img class="image" src="http://benscheirman.com/images/uibutton-gloweffect.png"&gt;&lt;/p&gt;

&lt;p&gt;Don&amp;#8217;t go overboard with this.  It&amp;#8217;s a subtle effect, but looks great
when used effectively.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ksLi2yG9hdQ:gIHkBWuZbiQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ksLi2yG9hdQ:gIHkBWuZbiQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=ksLi2yG9hdQ:gIHkBWuZbiQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=ksLi2yG9hdQ:gIHkBWuZbiQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/09/creating-a-glow-effect-for-uilabel-and-uibutton/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Introducing App Sites]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/6_jlDwIb2Lo/" />
    <updated>2011-09-20T08:46:00-05:00</updated>
    <id>http://benscheirman.com/2011/09/introducing-appsites</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve not been that great about marketing Giggle Touch.  It&amp;#8217;s a cool app,
kids like it, but most people don&amp;#8217;t know about it.&lt;/p&gt;

&lt;p&gt;The biggest reason was probably that I never set up a proper website for
it.  Doing a search would only yield a blog post that said it was
&amp;#8220;coming soon.&amp;#8221;&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s all changed now.  I&amp;#8217;d like to introduce &lt;em&gt;App Sites&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://appsites.heroku.com"&gt;App Sites&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;img class="right" src="http://benscheirman.com/images/yourapphere.png"&gt;&lt;/p&gt;

&lt;p&gt;The premise is simple: &lt;em&gt;standup a website for an iPhone
app in minutes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Check it out here:
&lt;a href="http://appsites.heroku.com"&gt;http://appsites.heroku.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can see the site in action by visiting the
&lt;a href="http://appsites.heroku.com/giggletouch"&gt;Giggle Touch&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s free (for now) and gives you the ability to add features, a
description, a link back to the app, and a screenshot.&lt;/p&gt;

&lt;p&gt;Planned upcoming features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom domains&lt;/li&gt;
&lt;li&gt;Multiple screenshots&lt;/li&gt;
&lt;li&gt;Videos&lt;/li&gt;
&lt;li&gt;Coming soon (if the app hasn&amp;#8217;t launched yet)&lt;/li&gt;
&lt;li&gt;More analytics&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you have an iPhone app, I encourage you to create a page.  Let me
know what you think!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=6_jlDwIb2Lo:80g2iNmSOao:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=6_jlDwIb2Lo:80g2iNmSOao:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=6_jlDwIb2Lo:80g2iNmSOao:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=6_jlDwIb2Lo:80g2iNmSOao:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/09/introducing-appsites/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Firebug-Style Visual Debugging for iOS]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/XbvUcjDhy78/" />
    <updated>2011-09-16T10:56:00-05:00</updated>
    <id>http://benscheirman.com/2011/09/firebug-style-debugging-for-ios</id>
    <content type="html">&lt;p&gt;Using a crazy helpful library called &lt;a href="https://github.com/domesticcatsoftware/DCIntrospect"&gt;DC Introspect&lt;/a&gt; you&amp;#8217;re able to easily take an app running in the Simulator:&lt;/p&gt;

&lt;p&gt;&lt;img class="image" src="http://benscheirman.com/images/simulator-before-introspection.png"&gt;&lt;/p&gt;

&lt;p&gt;And get visual frame debugging information like this:&lt;/p&gt;

&lt;p&gt;&lt;img class="image" src="http://benscheirman.com/images/simulator-after-introspection.png"&gt;&lt;/p&gt;

&lt;p&gt;You can also click &amp;amp; drag your mouse to get pixel information,
surrounding frames, print out detailed frame information in the console,
and even move frames around all while the app is running.&lt;/p&gt;

&lt;p&gt;Using it is incredibly simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have &lt;code&gt;DEBUG&lt;/code&gt; defined in your Preprocessor Macros:&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;img class="image" src="http://benscheirman.com/images/debug-preprocessor-macro.png"&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Download the code from https://github.com/domesticcatsoftware/DCIntrospect and drag the DCIntrospect/DCIntrospect folder into your project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your Application Delegate class, make the following changes:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;    #import &amp;quot;DCIntrospect.h&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// in applicationDidFinishLaunching:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="n"&gt;makeKeyAndVisible&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;#ifdef TARGET_IPHONE_SIMULATOR&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;DCIntrospect&lt;/span&gt; &lt;span class="n"&gt;sharedIntrospector&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Once that is done, the library will be loaded and you can use it.  When
the simulator launches, just press Spacebar to activate the tool.&lt;/p&gt;

&lt;p&gt;Here are some keyboard shortcuts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;o&lt;/code&gt; - Outline all views&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; - Prints out a help view&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; - Flash on &lt;code&gt;drawRect:&lt;/code&gt; calls&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c&lt;/code&gt; - Toggle showing coordinates&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4 6 8 2&lt;/code&gt; - Nudge the selected view left, right, up, down&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; - Recenter view where it was originally&lt;/li&gt;
&lt;li&gt;&lt;code&gt;9 7 3 1&lt;/code&gt; - Modify Width &amp;amp; Height of selected view&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You can also click &amp;amp; drag with the mouse to get detailed information
about frames &amp;amp; mouse position.&lt;/p&gt;

&lt;p&gt;I am amazed at how awesome this library is. I&amp;#8217;ll be using it in my
default toolbox from now on.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=XbvUcjDhy78:46vupEZI7sI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=XbvUcjDhy78:46vupEZI7sI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=XbvUcjDhy78:46vupEZI7sI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=XbvUcjDhy78:46vupEZI7sI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/09/firebug-style-debugging-for-ios/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Vim - Could Not Invoke JSLint]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/WVQUkEr0W94/" />
    <updated>2011-08-26T08:59:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/vim—could-not-invoke-jslint</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;re running MacVim with Janus and have upgraded to Lion, you may
have noticed a little error when you open JavaScript files:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Error detected while processing function 87_JSLint:
Line 33:
could not invoke JSLint!&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It seems many are having &lt;a href="https://github.com/hallettj/jslint.vim/issues/13"&gt;this issue&lt;/a&gt;.  There are 2 things to check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have Node in your path.  Confirm this by typing &lt;code&gt;which
node&lt;/code&gt; and make sure it resolves a binary somewhere on your system.&lt;/li&gt;
&lt;li&gt;Open up your &lt;code&gt;~/.vimrc.local&lt;/code&gt; and add this command:&lt;/li&gt;
&lt;/ol&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='vim'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;&amp;quot; Use Node.js for JavaScript interpretation&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;let&lt;/span&gt; $JS_CMD&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;node&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Kudos to &lt;a href="http://github.com/eventualbuddha"&gt;eventualbuddha&lt;/a&gt; for
figuring this out.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=WVQUkEr0W94:Lx_2pnqHXgQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=WVQUkEr0W94:Lx_2pnqHXgQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=WVQUkEr0W94:Lx_2pnqHXgQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=WVQUkEr0W94:Lx_2pnqHXgQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/vim---could-not-invoke-jslint/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Is Rails Exempt?]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/4SEGH9h5Wy8/" />
    <updated>2011-08-26T07:58:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/is-rails-exempt-from-software-principles</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;ve been following the Ruby community recently, you&amp;#8217;d notice that
there&amp;#8217;s are people calling our Rails (and Rails developers) for treating
Rails as if it is somehow &lt;em&gt;exempt&lt;/em&gt; from long-standing software
principles.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://osherove.com/"&gt;Roy Osherove&lt;/a&gt;, a fairly well-known .NET developer and author of The &lt;a href="http://artofunittesting.com/"&gt;Art of Unit Testing&lt;/a&gt;, ventured into Ruby-land
recently and commented on twitter about how Rails&amp;#8217;s
definition of unit &amp;amp; integration is quite different from his.&lt;/p&gt;

&lt;p&gt;&lt;img class="tweet" src="http://benscheirman.com/images/rails-unit-integration-tweet.png"&gt;&lt;/p&gt;

&lt;p&gt;I have to agree with Roy. Those in the TDD camp in .NET understood the
difference and were (from my experience) fairly cognizent of isolating
concerns and not mixing the 2 concepts. Some even go as far as to
isolate integration tests into their own assembly, providing a physical
separation further guaranteeing that a unit test project won&amp;#8217;t touch
web services or the database.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s easy to assume from the outside that the Rails is just testing
nirvana and that &lt;em&gt;everyone&lt;/em&gt; does it and it&amp;#8217;s so easy.  Unfortunately it&amp;#8217;s
just not the truth.  Rails (and Ruby) make testing really easy but that
means it&amp;#8217;s even easier to do the wrong thing as well.&lt;/p&gt;

&lt;h2&gt;Legacy Rails Apps&lt;/h2&gt;

&lt;p&gt;Now that Rails is (gasp) over 7 years old you&amp;#8217;re starting to see some
real legacy Rails applications out in the wild.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/avdi"&gt;Avdi Grimm&lt;/a&gt; has a &lt;a href="http://avdi.org/devblog/2011/08/22/your-code-is-my-hell/"&gt;good post&lt;/a&gt; on the topic of how many of the Rails apps he comes to work on are in poor shape, technically.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Here are a few examples, just to give you an idea of what I’m talking about:&lt;/p&gt;

&lt;p&gt;“Design Patterns are a Java thing. In Ruby you just write code.”&lt;/p&gt;

&lt;p&gt;“The warnings Ruby produces are dumb; just disable them.”&lt;/p&gt;

&lt;p&gt;“Sure they aren’t technically Unit Tests, but isolating objects turned out to be kind of hard and besides nobody else is doing it.”&lt;/p&gt;

&lt;p&gt;“Stuff like the Law of Demeter isn’t really as important in Ruby code”&lt;/p&gt;

&lt;p&gt;“That’s only a problem in large projects” (implying that this project will never become large).&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I&amp;#8217;ve certainly been guilty of some of this. Rails makes it easy to do
things that can turn out to be problematic. As with anything, you have
to be disciplined to notice the warning signs and act accordingly.&lt;/p&gt;

&lt;p&gt;When testing is painful, you&amp;#8217;re likely making mistakes. Some common
pain-points that I&amp;#8217;ve experienced are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No tests - the app is hard to test because the design is poor. Classes
are too tightly coupled and don&amp;#8217;t have clear delineation of
responsibilities.&lt;/li&gt;
&lt;li&gt;Tests break for unrelated reasons - the tests are covering too much
behavior, so when a single behavior changes, many tests break.&lt;/li&gt;
&lt;li&gt;Tests break when implementation changes - the tests are probably
utilizing too much mocking &amp;amp; stubbing. The tests are coupled heavily
to a particular implementation.&lt;/li&gt;
&lt;li&gt;Unclear what the problem is when a test breaks - Tests are probably
too coarse-grained and may contain too many assertions per test.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;These are just a sampling of what I&amp;#8217;ve personally observed.&lt;/p&gt;

&lt;p&gt;So why do many Rails developers ignore these concepts?&lt;/p&gt;

&lt;h2&gt;Pragmatism at work&lt;/h2&gt;

&lt;p&gt;Many rails tutorials (and the default Rails template) treats model tests
as &lt;em&gt;unit&lt;/em&gt; tests. Since Rails models are by default based on Active
Record, they have data access baked into their core.  Doing proper unit
testing means you&amp;#8217;re testing a logical unit.  If your test involves a
model operation that requires a database round-trip, that&amp;#8217;s technically
an &lt;em&gt;integration&lt;/em&gt; test.  But does it really matter?&lt;/p&gt;

&lt;p&gt;Most Rails developers will tell you no. Consider this spec:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;should be initially unpublished&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is a unit test. It tests a single piece of functionality and will
fail for just one reason.&lt;/p&gt;

&lt;p&gt;Now, here&amp;#8217;s another example:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;should fetch published articles&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# ?&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# post.rb&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;published&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;published_at &amp;lt;= ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;How should you implement this spec?&lt;/p&gt;

&lt;p&gt;If you were trying to avoid hitting the database you might intercept the
&lt;code&gt;where&lt;/code&gt; call and assert the parameters passed to it. But surely this
isn&amp;#8217;t the only way you could implement this method giving the same
behavior.  You might use &lt;code&gt;scopes&lt;/code&gt; or another &lt;code&gt;where&lt;/code&gt; call might actually
be added later that doesn&amp;#8217;t affect the outcome of this method in any way
that this test is concerned about.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;should fetch published articles&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:article&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;future_post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;:article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:published_at&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_now&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="n"&gt;future_post&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This test hits the database (numerous times, in fact) but it&amp;#8217;s testing
&lt;em&gt;exactly&lt;/em&gt; the behavior we need.  We aren&amp;#8217;t testing implementation, we&amp;#8217;re
testing that the behavior works as intended.  If we somehow muck with
the query, breaking it, this test will fail.  If we change the
implementation to use some other query means (scopes or whatever) this
test will still pass.&lt;/p&gt;

&lt;p&gt;Is it so bad that the test hits the database?&lt;/p&gt;

&lt;p&gt;There are drawbacks of course:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The test requires a database, thus you have to migrate&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;database_cleaner&lt;/code&gt; gem will have to be present to clean out the
database before each run&lt;/li&gt;
&lt;li&gt;These database statements make the test suite a LOT slower, so large
test suites will eventually suffer.&lt;/li&gt;
&lt;li&gt;The tests could fail if the database isn&amp;#8217;t present (or migrated), or
if the query is incorrect.  But this isn&amp;#8217;t likely to happen since
we&amp;#8217;re using a tested framework (ActiveRecord).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Ultimately this isn&amp;#8217;t really a unit test at all.  It&amp;#8217;s an integration
test.  So is &lt;code&gt;spec/models/post_spec.rb&lt;/code&gt; the wrong place for this stuff?&lt;/p&gt;

&lt;p&gt;The question eventually comes down to this: &lt;em&gt;What is more valuable?  A
fast, isolated test suite?  Or a test suite that breaks for the right
reasons?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Don&amp;#8217;t throw out good practices just because it&amp;#8217;s Ruby&lt;/h2&gt;

&lt;p&gt;I think it&amp;#8217;s important to be cognizant of software paradigms and use
them where they make sense. It&amp;#8217;s also important to recognize when
practices are being ignored because &amp;#8220;celebrities&amp;#8221; aren&amp;#8217;t touting them.&lt;/p&gt;

&lt;p&gt;It is still valuable, however, to keep a fresh eye on old assumptions. Don&amp;#8217;t
always take things as gospel just because that&amp;#8217;s the way they have
always been. One
of the things I love about the Ruby community is how willing people are
to rock the boat &amp;amp; try something new.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4SEGH9h5Wy8:ScNTEKRShVw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4SEGH9h5Wy8:ScNTEKRShVw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=4SEGH9h5Wy8:ScNTEKRShVw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=4SEGH9h5Wy8:ScNTEKRShVw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/is-rails-exempt-from-software-principles/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[When viewWillAppear: Isn't Called]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/2dgikX9qpZc/" />
    <updated>2011-08-24T10:11:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/when-viewwillappear-isnt-called</id>
    <content type="html">&lt;p&gt;The &lt;code&gt;UIViewController&lt;/code&gt; lifecycle is pretty simple.  &lt;code&gt;viewDidLoad&lt;/code&gt; is
called when the view is loaded (usually from a XIB) and when the view
controller&amp;#8217;s view is about to be displayed &lt;code&gt;viewWillAppear:&lt;/code&gt; gets called
(and &lt;code&gt;viewWillDisappear:&lt;/code&gt; when it goes away).&lt;/p&gt;

&lt;p&gt;The problem is, when you have a non-standard view hierarchy (like my
current app) these methods don&amp;#8217;t get called. The Apple docs have this to
say about the problem:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In my application I have a persistent bar at the bottom of the screen,
so my &lt;code&gt;UINavigationController&lt;/code&gt; only owns a portion of the screen.  Thus, my
&lt;code&gt;RootViewController&lt;/code&gt; (which owns these 2 portions) is always &lt;em&gt;active&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class="screenshot" src="http://benscheirman.com/images/non-standard-nav-frame.png"&gt;&lt;/p&gt;

&lt;p&gt;I recently came upon a requirement that needed to leverage
&lt;code&gt;viewWillAppear:&lt;/code&gt; and &lt;code&gt;viewWillDisappear:&lt;/code&gt; in order to decorate the
bottom bar with some additional information. Since this is a view
controller a few layers deep in the hierarchy, the methods weren&amp;#8217;t being
called.&lt;/p&gt;

&lt;p&gt;Luckly, there is a fix to this. The navigation controller can notify
its &lt;code&gt;delegate&lt;/code&gt; when it changes view controllers.&lt;/p&gt;

&lt;p&gt;Start off in the view controller that is the root of the navigation
controller hierarchy.  Make it conform to the
&lt;code&gt;UINavigationControllerDelegate&lt;/code&gt; protocol.  We&amp;#8217;ll also need an ivar to
store the last view controller that &lt;em&gt;appeared&lt;/em&gt; so that we can notify
when it &lt;em&gt;disappears&lt;/em&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;MyRootViewController&lt;/span&gt; : &lt;span class="nc"&gt;UIViewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UINavigationControllerDelegate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_lastViewController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// methods&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In the implementation, in do the following:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;MyRootViewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c1"&gt;// other stuff&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;viewDidLoad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navigationController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nl"&gt;navigationController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINavigationController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;navigationController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nl"&gt;willShowViewController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;viewController&lt;/span&gt; &lt;span class="nl"&gt;animated:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;animated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_lastViewController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_lastViewController&lt;/span&gt; &lt;span class="nl"&gt;viewWillDisappear:&lt;/span&gt;&lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;viewController&lt;/span&gt; &lt;span class="nl"&gt;viewWillAppear:&lt;/span&gt;&lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="n"&gt;_lastViewController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you need support for &lt;code&gt;viewDidAppear&lt;/code&gt; and &lt;code&gt;viewDidDisappear&lt;/code&gt; then
you&amp;#8217;d have to implement this method as well:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objc'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;navigationController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINavigationController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;navigationController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;       &lt;span class="nf"&gt;didShowViewController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;viewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                    &lt;span class="nf"&gt;animated:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;After doing this, your view controllers should start receiving the
&lt;code&gt;viewWillAppear:&lt;/code&gt; and &lt;code&gt;viewWillDisappear:&lt;/code&gt; methods successfully.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2dgikX9qpZc:2e125d86f88:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2dgikX9qpZc:2e125d86f88:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2dgikX9qpZc:2e125d86f88:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=2dgikX9qpZc:2e125d86f88:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/when-viewwillappear-isnt-called/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Moving My Blog]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/gn_MsGDoqQM/" />
    <updated>2011-08-21T00:00:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/moving-my-blog</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve decided to transition over to a new blog.&lt;/p&gt;


&lt;p&gt;The reasons? Mostly because I&amp;#8217;m questioning more &amp;amp; more the need to have a dynamic blog that I need to maintain. Static HTML blog generators are very interesting and I thought I&amp;#8217;d give one a try.&lt;/p&gt;


&lt;p&gt;I&amp;#8217;ll leave this one around for historical reasons. It gets a decent amount of traffic and has content going back to 2004.&lt;br /&gt;&lt;/p&gt;


&lt;p&gt;So without further ado I present my new blog, &lt;a href="http://benscheirman.com"&gt;Fickle Bits&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;


&lt;p&gt;(Note to RSS readers, your feeds will not auto-update. Subscribe to the new blog here: &lt;a href="http://feeds.feedburner.com/ficklebits" target="_blank"&gt;Subscribe&lt;/a&gt; )&lt;br /&gt;&lt;/p&gt;

&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=gn_MsGDoqQM:AU6ZL1_Oz0U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=gn_MsGDoqQM:AU6ZL1_Oz0U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=gn_MsGDoqQM:AU6ZL1_Oz0U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=gn_MsGDoqQM:AU6ZL1_Oz0U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/moving-my-blog/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[My Vim Journey]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/7tAg0_wbnDE/" />
    <updated>2011-08-17T23:53:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/my-vim-journey</id>
    <content type="html">&lt;p&gt;For my Rails work, I&amp;#8217;ve largely leaned on &lt;a href="http://macromates.org"&gt;TextMate&lt;/a&gt;.  It&amp;#8217;s used by many Rubyists, looks sexy,
and is easily extended.&lt;/p&gt;

&lt;p&gt;I still use TextMate frequently, but I&amp;#8217;ve been ramping up on my Vim
skills and I&amp;#8217;ve recently come to a point where I think I&amp;#8217;m pretty
productive in it.&lt;/p&gt;

&lt;p&gt;My initial frustrations with Vim were that it was too configurable.
Talk to any Vim power-user and you&amp;#8217;ll find a completely different set of
plugins &amp;amp; keyboard shortcuts.  If you snag a friend&amp;#8217;s set of Vim
configuration files (like I did) you might find yourself frustrated that
there&amp;#8217;s too much to learn and it&amp;#8217;s difficult to know where various
behaviors are coming from.&lt;/p&gt;

&lt;p&gt;In this post, I&amp;#8217;ll attempt to demonstrate a very sane Vim setup that
newcomers can use to get started and not be too overwhelmed.&lt;/p&gt;

&lt;h2&gt;Why Vim?&lt;/h2&gt;

&lt;p&gt;Before I get started with the basics of Vim, why would you use it in the
first place?&lt;/p&gt;

&lt;p&gt;For me it boils down to this:  &lt;em&gt;I love staying on the keyboard&lt;/em&gt;.
Vim may not make you faster (&lt;em&gt;in fact initially you&amp;#8217;ll be a lot slower&lt;/em&gt;) but it can fit your workflow better.&lt;/p&gt;

&lt;p&gt;Another big differentiator of Vim is &lt;em&gt;Command Mode&lt;/em&gt;.  The notion
here is that you spend more time wrangling text rather than creating it
from scratch.  That&amp;#8217;s certainly true of my code.&lt;/p&gt;

&lt;p&gt;It is important, however, that in the larger software ecosystem,
&lt;em&gt;typing is not the bottleneck&lt;/em&gt;.  Don&amp;#8217;t expect Vim to make you build
the right software faster.&lt;/p&gt;

&lt;p&gt;Vim enables a keyboard-optimized workflow that &lt;em&gt;may&lt;/em&gt; make you faster.
YMMV.  If you&amp;#8217;re fast with TextMate or Emacs or don&amp;#8217;t want to spend the
time to learn something new, then Vim may very well not be for you.&lt;/p&gt;

&lt;p&gt;Lastly, Vim is ubiquitous.  It&amp;#8217;s on every platform and
you can carry your configuration (or a very large set of it) everywhere.
People frequently put their vim configurations on Github for themselves
and others to utilize.&lt;/p&gt;

&lt;h2&gt;Getting MacVim&lt;/h2&gt;

&lt;p&gt;Almost all Unix-based systems (like Mac) include a terminal version of
Vim.  The version included on OS X isn&amp;#8217;t compiled with Ruby support, so
some plugins won&amp;#8217;t work.  In addition, it doesn&amp;#8217;t have OS-level
integration like Copy &amp;amp; Paste in the same buffer.&lt;/p&gt;

&lt;p&gt;Most Vim users I know use MacVim, which comes pre-compiled with Ruby
support, has tabs, and more.&lt;/p&gt;

&lt;p&gt;If you have &lt;a href="http://mxcl.github.com/homebrew/"&gt;homebrew&lt;/a&gt; installed, just
type:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;brew install  macvim&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you&amp;#8217;d rather grab a pre-built binary, then head on over &lt;a href="https://github.com/b4winckler/macvim"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll also want to make sure that the &lt;code&gt;mvim&lt;/code&gt; binary is in your path.&lt;/p&gt;

&lt;h2&gt;Basic Vim Navigation&lt;/h2&gt;

&lt;p&gt;I won&amp;#8217;t cover everything you can do in Vim here, but here&amp;#8217;s just enough
to get you started:&lt;/p&gt;

&lt;p&gt;In Command Mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;h&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;l&lt;/code&gt; to move the cursor around.  It will feel weird, but you start to appreciate not
lifting your hand off of the home row to reach for the arrow keys.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;G&lt;/code&gt; to go to the end of a document, &lt;code&gt;gg&lt;/code&gt; to go to the top of
the document.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;i&lt;/code&gt; to go to insert mode at the current position&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;I&lt;/code&gt; to insert at the beginning of the line&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;a&lt;/code&gt; to &amp;#8220;append&amp;#8221; content after the cursor&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;A&lt;/code&gt; to &amp;#8220;append&amp;#8221; content at the end of a line&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;cw&lt;/code&gt; (&amp;#8220;change word&amp;#8221;) to replace the current word and go into insert mode&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;dta&lt;/code&gt; to (&amp;#8220;delete &amp;#8216;til the letter a&amp;#8221;) in a line&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In Insert Mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;esc&lt;/code&gt; to go back to command mode.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Command Mode, you can type commands by prefixing them with &lt;code&gt;:&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To write the changes to the current buffer (save) type &lt;code&gt;:w&lt;/code&gt; and hit
&lt;code&gt;enter&lt;/code&gt;.  Often times you&amp;#8217;ll write &amp;amp; quit in one command, with &lt;code&gt;:wq&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Feel free to use the mouse &amp;amp; arrow-keys while you&amp;#8217;re getting used to everything.  It
will feel weird.&lt;/p&gt;

&lt;p&gt;For more Vim-fu, definitely check out this &lt;a href="http://peepcode.com/products/smash-into-vim-i"&gt;PeepCode
screencast&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Installing a Base Set of Plugins with Janus&lt;/h2&gt;

&lt;p&gt;The real power of Vim is in the plugins, and fortunately Yehuda Katz &amp;amp;
Carl Lerche have put together an opinionated and useful set of plugins
that are pre-configured and work well together.  Take a look at the plugins it includes
&lt;a href="https://github.com/carlhuda/janus"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Getting Janus installed is easy.  If you are super trust-worthy and
don&amp;#8217;t mind running a script blindly (I don&amp;#8217;t recommend it) you can
simply run:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;curl https://raw.github.com/carlhuda/janus/master/bootstrap.sh -o - | sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;More explicit instructions for the paranoid can be found on &lt;a href="http://github.com/carlhuda/janus"&gt;the github
page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have Janus installed, your Vim will be on steroids. Don&amp;#8217;t worry
though, I&amp;#8217;ll try to cover the most important things you&amp;#8217;ll be using.&lt;/p&gt;

&lt;h2&gt;Getting a Decent Theme installed&lt;/h2&gt;

&lt;p&gt;MacVim installs a hundred nasty looking themes, but a few of them are
worth taking a look at.  Here are some that I like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;molokai&lt;/li&gt;
&lt;li&gt;railscasts&lt;/li&gt;
&lt;li&gt;vividchalk&lt;/li&gt;
&lt;li&gt;vibrantink&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you want to install other themes (like this nice &lt;a href="http://www.vim.org/scripts/script.php?script_id=2855"&gt;github&lt;/a&gt; one) then you
simply download it &amp;amp; copy the &lt;code&gt;theme.vim&lt;/code&gt; (or whatever the theme is
called) to &lt;code&gt;~/.vim/colors&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To switch between the themes that are installed, you can use the menu,
or you can type &lt;code&gt;:colorscheme &amp;lt;scheme&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To set defaults for your installation, you&amp;#8217;d normally add commands to
&lt;code&gt;~/.vimrc&lt;/code&gt; however Janus has taken that file over.  It instead reads
your settings from &lt;code&gt;~/.vimrc.local&lt;/code&gt;.  In order to provide settings for
graphical Vim installations (like MacVim) there&amp;#8217;s also a &lt;code&gt;~/.gvimrc&lt;/code&gt;
file.&lt;/p&gt;

&lt;p&gt;Open up that file (&lt;code&gt;:edit ~/.gvimrc&lt;/code&gt;) and add the following commands:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='vim'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;colorscheme&lt;/span&gt; github
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;guifont&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;Menlo:h14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Feel free to tweak this to contain your favorite color scheme &amp;amp; font.
In order to see these changes you have to &amp;#8220;source&amp;#8221; the file:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='vim'&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;:&lt;/span&gt;source %
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(&lt;code&gt;%&lt;/code&gt; here means &amp;#8220;current file&amp;#8221;)&lt;/p&gt;

&lt;p&gt;You should see the changes take effect immediately.&lt;/p&gt;

&lt;h2&gt;Opening MacVim with a &amp;#8220;Project&amp;#8221;&lt;/h2&gt;

&lt;p&gt;One common thing in TextMate is to &lt;code&gt;cd&lt;/code&gt; into a project and then type
&lt;code&gt;mate .&lt;/code&gt; which will open TextMate&amp;#8217;s project drawer with all of the files
in that directory loaded up.&lt;/p&gt;

&lt;p&gt;In MacVim, you can do the same.  Navigate to a folder with some content
(like a Rails app) and type: &lt;code&gt;mvim .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see something resembling a file navigator.  You can navigate
these with the same movement commands from above.&lt;/p&gt;

&lt;p&gt;Once you&amp;#8217;ve chosen a file, press &lt;code&gt;enter&lt;/code&gt; to open it in the buffer.&lt;/p&gt;

&lt;p&gt;&lt;span class='pullquote-right' data-pullquote='The leader key is a special, configurable key used to create quick shortcut combinations.'&gt;
Janus comes with NERDTree, which has similar behavior to TextMate&amp;#8217;s
Project Drawer.  Open up the NERDTree pane by typing &lt;code&gt;&amp;lt;leader&amp;gt;-n&lt;/code&gt; or &lt;code&gt;\n&lt;/code&gt;. By default the leader key is set to backslash.
The leader key is a special, configurable key used to create quick shortcut combinations.
&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The NERDTree window can be collapsed by typing &lt;code&gt;&amp;lt;leader&amp;gt;-n&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;You might want to instead find the file by searching for it by name.
For that, the aptly-named Command-T plugin can be hepful.&lt;/p&gt;

&lt;p&gt;Command-T can be activated (by default) with &lt;code&gt;&amp;lt;leader&amp;gt;-t&lt;/code&gt;.  Start typing
and it will auto complete the results.&lt;/p&gt;

&lt;h2&gt;Scared Yet?&lt;/h2&gt;

&lt;p&gt;Writing this reminds me of how hard it was to get started.  I can only
offer some encouragement that with practice, Vim does start to feel like
 you can leverage your fast typing skills to really.&lt;/p&gt;

&lt;p&gt;Practice only a couple of commands at a time.  Really learn what they
are doing and then move one to the next command.  Print out a cheet
sheet.  Pair with someone else who uses Vim.&lt;/p&gt;

&lt;p&gt;I hope you found this intro useful. I&amp;#8217;ll cover some more Vim tricks as time goes on.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=7tAg0_wbnDE:8Upm6yVg434:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=7tAg0_wbnDE:8Upm6yVg434:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=7tAg0_wbnDE:8Upm6yVg434:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=7tAg0_wbnDE:8Upm6yVg434:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/my-vim-journey/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[A Fresh Start?]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/lvQmVcRJfNU/" />
    <updated>2011-08-17T23:37:00-05:00</updated>
    <id>http://benscheirman.com/2011/08/a-fresh-start</id>
    <content type="html">&lt;p&gt;So I&amp;#8217;ve been thinking of ditching the traditional blog for a while now.  My &lt;a href="http://flux88.com"&gt;current blog&lt;/a&gt; is powered by WordPress, which
is powerful enough, however it always seems like a hassle to maintain.
There are also no fantastic blog editors for the Mac (still).&lt;/p&gt;

&lt;p&gt;This time I&amp;#8217;m going in a completely new direction.  This blog is powered
by &lt;a href="http://octopress.org"&gt;Octopress&lt;/a&gt; (which uses
&lt;a href="https://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt; as the engine.  I&amp;#8217;m not
going to import old posts and I&amp;#8217;m not going to worry about integrating a lot
of features. Just epic content, that&amp;#8217;s it!&lt;/p&gt;

&lt;p&gt;Posts are composed in Markdown (I&amp;#8217;m using vim to write this), static HTML is generated and the blog is then deployed to a git repository.&lt;/p&gt;

&lt;p&gt;Will it make me blog more? I hope so, but only time will tell!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=lvQmVcRJfNU:SkncA139E2U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=lvQmVcRJfNU:SkncA139E2U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=lvQmVcRJfNU:SkncA139E2U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=lvQmVcRJfNU:SkncA139E2U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/08/a-fresh-start/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Houston Code Camp Registration is Now Open]]></title>
    <link href="http://feedproxy.google.com/~r/flux88/~3/2DPd3Cbrhqs/" />
    <updated>2011-06-17T00:00:00-05:00</updated>
    <id>http://benscheirman.com/2011/06/houston-code-camp-registration-is-now-open</id>
    <content type="html">&lt;h2&gt;Houston Code Camp 2011&lt;/h2&gt;


&lt;h3&gt;August 20th, 2011&lt;/h3&gt;


&lt;p&gt;&lt;img src="http://benscheirman.com/images/logo__.jpg" style="float:right; margin: 25px;"   /&gt;&lt;/p&gt;

&lt;p&gt;Houston Code Camp is a free day of sessions relating to software development. The event is free to attend, but registration is required.&lt;/p&gt;


&lt;p&gt;A Code Camp follows these rules:&lt;/p&gt;


&lt;ul&gt;
  &lt;li&gt;They are a organized by developers and for developers to come and learn from their peers. Topics are always based on community interest and never determined by anyone other than the community.&lt;/li&gt;

  &lt;li&gt;Code Camps are always FREE for attendees&lt;/li&gt;

  &lt;li&gt;The success of the Code Camp is determined by the community. All content that is delivered is original and voted for by you! Make sure your vote counts, and vote for the sessions you&amp;#8217;d like to see at our &lt;a href="http://houstoncodecamp.uservoice.com/forums/116507-speaker-submissions" target="_blank"&gt;speaker submission site&lt;/a&gt;.&lt;/li&gt;

  &lt;li&gt;No Fluff - Code Camps are about Code, not slides. You won&amp;#8217;t find any marketing heavy powerpoint decks here&lt;/li&gt;

  &lt;li&gt;All are welcome to attend and speak and do so without expectation of payment. Learn more about speaking on our &lt;a href="http://houstoncodecamp.uservoice.com/forums/116507-speaker-submissions" target="_blank"&gt;speaking&lt;/a&gt; page.&lt;/li&gt;

  &lt;li&gt;The beauty of the Code Camp is that they always occur on weekends.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The schedule is still being formed. Take a look at the list of submissions &lt;a href="http://houstoncodecamp.uservoice.com/forums/116507-speaker-submissions" target="_blank"&gt;here&lt;/a&gt;. You can still get your session proposal in if you&amp;#8217;re interested in speaking!&lt;/p&gt;


&lt;p&gt;Space is limited, so make sure and snag your ticket today. It&amp;#8217;s FREE!.&lt;/p&gt;




&lt;p&gt;What are you waiting for? &lt;strong&gt;&lt;a href="http://houstoncodecamp.com/registration" target="_blank"&gt;Go register&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;

&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2DPd3Cbrhqs:-3VREFwtf6I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2DPd3Cbrhqs:-3VREFwtf6I:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/flux88?a=2DPd3Cbrhqs:-3VREFwtf6I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/flux88?i=2DPd3Cbrhqs:-3VREFwtf6I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
  <feedburner:origLink>http://benscheirman.com/2011/06/houston-code-camp-registration-is-now-open/</feedburner:origLink></entry>
  
</feed>
