<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>John Barnette</title>
 <link href="http://www.jbarnette.com/atom.xml" rel="self"/>
 <link href="http://www.jbarnette.com/"/>
 <updated>2012-10-01T13:18:58-07:00</updated>
 <id>http://www.jbarnette.com/</id>

 <author>
   <name>John Barnette</name>
   <email>john@jbarnette.com</email>
 </author>

 
 <entry>
   <title>Isolate on Heroku</title>
   <link href="http://www.jbarnette.com/2010/06/26/isolate-on-heroku.html"/>
   <updated>2010-06-26T00:00:00-07:00</updated>
   <id>http://www.jbarnette.com/2010/06/26/isolate-on-heroku</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Jamie Macey wrote a &lt;a href='http://github.com/jamie/isolate-heroku'&gt;gem&lt;/a&gt; for this, and we improved the logic a bit. Use it.&lt;/p&gt;

&lt;p&gt;Quite a few people have asked about using &lt;a href='http://github.com/jbarnette/isolate'&gt;Isolate&lt;/a&gt; on Heroku. There&amp;#8217;s no built-in support for Isolate in Heroku&amp;#8217;s current deployment tools, but it&amp;#8217;s pretty easy to hack together using Heroku&amp;#8217;s support for a &lt;code&gt;.gems&lt;/code&gt; manifest file.&lt;/p&gt;

&lt;h2 id='assumptions'&gt;Assumptions&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You&amp;#8217;re using some sort of &lt;code&gt;rake release&lt;/code&gt; task for deployment. See &amp;#8220;Alternatives&amp;#8221; at the end of this post for, uh, an alternative.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;You&amp;#8217;re using Isolate with its &lt;code&gt;:system&lt;/code&gt; option set to &lt;code&gt;true&lt;/code&gt;. If you&amp;#8217;re using Isolate 2, this is the default. &lt;code&gt;:system =&amp;gt; true&lt;/code&gt; allows isolated projects to use gems that are already installed on the system, which is necessary for Heroku support.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;I&amp;#8217;m testing this with a simple isolated Rails 2.3.8 app, but the process is basically the same for any Rails version (or other framework). See the examples in Isolate&amp;#8217;s &lt;code&gt;README&lt;/code&gt; for details.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='dot_gems'&gt;Dot Gems&lt;/h2&gt;

&lt;p&gt;Heroku&amp;#8217;s &lt;code&gt;.gems&lt;/code&gt; manifest is a simple text file containing one gem dependency per line, in a format that&amp;#8217;s very similar to a &lt;code&gt;gem&lt;/code&gt; command line. Heroku will read this file every time you release/push reinstall all your gem dependencies if it&amp;#8217;s changed.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re going to generate &lt;code&gt;.gems&lt;/code&gt; from our Isolate file. Here&amp;#8217;s my &lt;code&gt;lib/tasks/isolate.rake&lt;/code&gt; file:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;desc&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Generate a .gems manifest.&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:dotgems&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='sx'&gt;%w(Isolate lib/tasks/isolate.rake)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;open&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;.gems&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;wb&amp;quot;&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;f&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;entries&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Isolate&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;sandbox&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;entries&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;sort_by&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;e&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;e&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;puts&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;isolate --version &amp;#39;= &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='no'&gt;Isolate&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;VERSION&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;&amp;quot;&lt;/span&gt;

    &lt;span class='n'&gt;entries&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&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;entry&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
      &lt;span class='k'&gt;next&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='n'&gt;entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;matches?&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;production&amp;quot;&lt;/span&gt;

      &lt;span class='n'&gt;gems&lt;/span&gt;  &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
      &lt;span class='n'&gt;gems&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;--version &amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;requirement&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;&amp;quot;&lt;/span&gt;

      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:source&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
        &lt;span class='n'&gt;gems&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;--source &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:source&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;puts&lt;/span&gt; &lt;span class='n'&gt;gems&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&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 class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='nb'&gt;abort&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Commit .gems, it changed.&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='sr'&gt;/\.gems/&lt;/span&gt; &lt;span class='o'&gt;=~&lt;/span&gt; &lt;span class='sb'&gt;`git status`&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This task looks at all your isolated gem entries, picks the ones that are valid for production, and writes each of them to the &lt;code&gt;.gems&lt;/code&gt; file. It also adds Isolate itself as a dependency. If &lt;code&gt;.gems&lt;/code&gt; has changed, the task aborts and reminds you to commit the changes.&lt;/p&gt;

&lt;h2 id='releasing'&gt;Releasing&lt;/h2&gt;

&lt;p&gt;My &lt;code&gt;rake release&lt;/code&gt; task does a fair amount of stuff before it pushes to Heroku, like creating a release email and running some sanity checks. To make sure my gem dependencies are always up-to-date, I just make sure the &lt;code&gt;release&lt;/code&gt; task depends on &lt;code&gt;dotgems&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:release&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:dotgems&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Done. Any time I run &lt;code&gt;rake release&lt;/code&gt;, &lt;code&gt;.gems&lt;/code&gt; will either be up-to-date or prompt me to commit the changes before continuing.&lt;/p&gt;

&lt;h2 id='alternatives'&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;This works Well Enough for me at the moment, but it could certainly be smoother. If you deploy using &lt;code&gt;git push&lt;/code&gt; instead of wrapping it in a Rake tasks, you could use a Git pre-commit hook to regenerate &lt;code&gt;.gems&lt;/code&gt; if necessary.&lt;/p&gt;

&lt;p&gt;Isolate 2 has added some &lt;a href='http://github.com/jbarnette/isolate/blob/master/lib/isolate/events.rb'&gt;lifecycle event hooks&lt;/a&gt;, so it&amp;#8217;d also be pretty easy to autogenerate &lt;code&gt;.gems&lt;/code&gt; every time Isolate runs.&lt;/p&gt;

&lt;p&gt;Of course, the best possible solution would be for Heroku to support Isolate natively, but I wouldn&amp;#8217;t hold your breath for that. :-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Deploying to Heroku</title>
   <link href="http://www.jbarnette.com/2009/11/10/deploying-to-heroku.html"/>
   <updated>2009-11-10T00:00:00-08:00</updated>
   <id>http://www.jbarnette.com/2009/11/10/deploying-to-heroku</id>
   <content type="html">&lt;p&gt;Deploying to Heroku with &lt;code&gt;git push&lt;/code&gt; is awesome. I&amp;#8217;m running a couple of different environments, though, and there&amp;#8217;s extra stuff that I want to do when I deploy. Rake to the rescue!&lt;/p&gt;

&lt;h2 id='some_assumptions'&gt;Some Assumptions&lt;/h2&gt;

&lt;p&gt;Okay, here&amp;#8217;s how I roll: &lt;code&gt;origin&lt;/code&gt; is GitHub. &lt;code&gt;origin/master&lt;/code&gt; is the production branch, &lt;em&gt;not&lt;/em&gt; the head of development. &lt;code&gt;origin/next&lt;/code&gt; is, well, what&amp;#8217;s next (you probably call it &amp;#8220;staging&amp;#8221;). There are local tracking branches for each of these, natch.&lt;/p&gt;

&lt;p&gt;New features happen in topic branches, and they&amp;#8217;re merged into &lt;code&gt;next&lt;/code&gt; when they&amp;#8217;re ready. Emergencies and bug fixes are similar, but they also get merged into &lt;code&gt;master&lt;/code&gt; and deployed before &lt;code&gt;next&lt;/code&gt; is fully baked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;master&lt;/code&gt; is only ever updated by bug/emergency branch merges and periodic merges of &lt;code&gt;next&lt;/code&gt;. If &lt;code&gt;git merge next&lt;/code&gt; isn&amp;#8217;t a fast-forward, something&amp;#8217;s probably wrong.&lt;/p&gt;

&lt;p&gt;There are (at the moment) two Heroku environments, &lt;code&gt;myapp-next&lt;/code&gt; and &lt;code&gt;myapp-master&lt;/code&gt;. There&amp;#8217;s a Git remote for each environment:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git remote
heroku-next
origin
heroku-master&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Got it? Good.&lt;/p&gt;

&lt;h2 id='deploying'&gt;Deploying&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ rake deploy&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Super&lt;/em&gt; complicated. In my setup, this task&amp;#8230;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complains if I&amp;#8217;m trying to deploy from a branch that doesn&amp;#8217;t match an deployment env (deploys can only happen from &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt;),&lt;/li&gt;

&lt;li&gt;sets the &lt;code&gt;TO&lt;/code&gt; environment variable for Hoptoad,&lt;/li&gt;

&lt;li&gt;shows a list of all the changes since the last deploy, and how long it&amp;#8217;s been,&lt;/li&gt;

&lt;li&gt;pushes the current branch to the matching remote, e.g., &lt;code&gt;git push
heroku-next next:master&lt;/code&gt;,&lt;/li&gt;

&lt;li&gt;tells Hoptoad about the deploy, and&lt;/li&gt;

&lt;li&gt;sends a fancy email w/changes to the deployment mailing list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='the_first_time'&gt;The First Time&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ rake deploy:newb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This task installs the &lt;code&gt;heroku&lt;/code&gt; and &lt;code&gt;taps&lt;/code&gt; gems if they&amp;#8217;re not available, creates and fetches the Heroku remotes for each environment, and makes sure you have local tracking branches for the &lt;code&gt;origin/bleh&lt;/code&gt; equivalents of each remote.&lt;/p&gt;

&lt;h2 id='what_changed'&gt;What changed?&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ rake deploy:pending&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This task shows a list of commits that have happened since the last deploy. It&amp;#8217;s a pretty thin wrapper around &lt;code&gt;git log&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id='i_hate_conclusions'&gt;I Hate Conclusions&lt;/h2&gt;

&lt;p&gt;There are a few other lifecycle hooks for attaching stuff that needs to happen before or after the deploy, but that&amp;#8217;s pretty much it. A lightly edited version of my &lt;code&gt;lib/tasks/deploy.rake&lt;/code&gt; is available in &lt;a href='http://gist.github.com/231216'&gt;this Gist&lt;/a&gt;. Add to it, correct it, abuse it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Boring Things First</title>
   <link href="http://www.jbarnette.com/2009/09/07/boring-things-first.html"/>
   <updated>2009-09-07T00:00:00-07:00</updated>
   <id>http://www.jbarnette.com/2009/09/07/boring-things-first</id>
   <content type="html">&lt;p&gt;&lt;em&gt;This is a draft.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yeah, yeah. You&amp;#8217;re agile. You &lt;em&gt;always&lt;/em&gt; test first, you work in tight iterations, you have YAGNI tattooed on your forehead. Good for you. Guess what? You&amp;#8217;re building on sand. Do this stuff first:&lt;/p&gt;

&lt;h2 id='tests_and_autotest_with_coverage'&gt;Tests (and Autotest) With Coverage&lt;/h2&gt;

&lt;p&gt;Make sure your testing infrastructure works. Write a single sanity test, make it pass and fail, and make sure that your test scripts/tasks, autotest setup, and coverage tools are working correctly.&lt;/p&gt;

&lt;h2 id='deployinstallupdate_an_empty_app'&gt;Deploy/Install/Update an Empty App&lt;/h2&gt;

&lt;p&gt;Before you write a damn thing, make sure you can distribute. If you&amp;#8217;re working on a Rails app, get your &lt;a href='http://rubyhitsquad.com/Vlad_the_Deployer.html'&gt;Vlad&lt;/a&gt; or &lt;a href='http://www.capify.org/index.php/Capistrano'&gt;Capistrano&lt;/a&gt; setup tuned and perfect. Do a bunch of blank deploys.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re writing a desktop app, write your installer and make sure it&amp;#8217;s working. Don&amp;#8217;t wait &amp;#8216;til the last minute! The moment you write a line of code, it&amp;#8217;ll be easier to have someone test it if the installer&amp;#8217;s functional.&lt;/p&gt;

&lt;p&gt;Even better, start by integrating an update system like &lt;a href='http://sparkle.andymatuschak.org'&gt;Sparkle&lt;/a&gt;. You may be distributing the empty shell of an app, but now you can automatically update your testers every time you push new changes. And you&amp;#8217;re testing your post-release update infrastructure at the same time! Win!&lt;/p&gt;

&lt;h2 id='error_notification'&gt;Error Notification&lt;/h2&gt;

&lt;p&gt;Some of your code is shit. Even in the unlikely event that all your Codes Are Perfect, someone&amp;#8217;s code that you &lt;em&gt;depend&lt;/em&gt; on is shit. Integrate error reporting at the very beginning, before any users have a chance to make errors. For Rails apps, I use &lt;a href='http://www.hoptoadapp.com'&gt;Hoptoad&lt;/a&gt;. There are a billion other alternatives, and rolling your own is easy too.&lt;/p&gt;

&lt;h2 id='fundamental_docs'&gt;Fundamental Docs&lt;/h2&gt;

&lt;p&gt;You&amp;#8217;re probably not going to be the only person who works on this project. How does the next person in the door get up and running? If the answer is much more complicated than &amp;#8220;check out the code and read the README,&amp;#8221; you suck.&lt;/p&gt;

&lt;p&gt;Start documenting at the very beginning. What should someone run to get started in a fresh checkout? (I like &lt;code&gt;rake newb&lt;/code&gt;) How does deployment work? Where&amp;#8217;s the deployment server? How was it configured? How do I stand up another one from scratch? What external services (issue tracking, error reporting) does this app use?&lt;/p&gt;

&lt;p&gt;Make sure your &lt;em&gt;initial&lt;/em&gt; set of docs answers these questions, and make it clear that keeping them up-to-date is as important as keeping the tests passing.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>On Rake</title>
   <link href="http://www.jbarnette.com/2009/08/27/on-rake.html"/>
   <updated>2009-08-27T00:00:00-07:00</updated>
   <id>http://www.jbarnette.com/2009/08/27/on-rake</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been reading a lot of Rakefiles lately, and it&amp;#8217;s obvious that the folks writing them think of Rake as An Engine For Encapsulating Tasks. That&amp;#8217;s fine, but it&amp;#8217;s only part of what Rake can do.&lt;/p&gt;

&lt;h2 id='i_do_declare'&gt;I Do Declare&lt;/h2&gt;

&lt;p&gt;Rake is all about &lt;em&gt;resolving dependencies&lt;/em&gt;. It&amp;#8217;s about being declarative, not imperative. Especially when dealing with files and directories, this can make a huge difference. Here&amp;#8217;s an example of a imperative task:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;desc&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Make sure your database.yml is in place&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:wheres_your_database_yml&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;exists?&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database.yml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Where&amp;#39;s your database.yml, dude?&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;exist?&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database.yml.example&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(elided)... so I&amp;#39;ll make a copy of it for you.&amp;quot;&lt;/span&gt;

      &lt;span class='n'&gt;cp&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database.yml.example&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
        &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database.yml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

        &lt;span class='nb'&gt;abort&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(elided)...rerun the last command.&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='nb'&gt;abort&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(elided)...There&amp;#39;s no config/database.yml.example...&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;(This is from &lt;a href='http://github.com/technicalpickles/wheres-your-database-yml-dude'&gt;technicalpickles&amp;#8217; dude-wheres-your-database-yml&lt;/a&gt;, a nice little Rails plugin for automatically installing a &lt;code&gt;database.yml&lt;/code&gt; file the first time a new contributor runs Rake. I&amp;#8217;ve shortened a few of the messages, but that&amp;#8217;s it.)&lt;/p&gt;

&lt;p&gt;This says, &amp;#8220;Hey, if there&amp;#8217;s not a &lt;code&gt;config/database.yml&lt;/code&gt; file, create it by copying &lt;code&gt;config/database.yml.example&lt;/code&gt;. If THAT doesn&amp;#8217;t exist, complain.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s how to write this in a more declarative way:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;file&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;config/database.yml&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;config/database.yml.example&amp;quot;&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;t&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;sh&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;cp &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;prerequisites&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&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='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;(This doesn&amp;#8217;t abort or talk to the user, but you get the idea.)&lt;/p&gt;

&lt;p&gt;This says essentially the same thing. &lt;code&gt;file&lt;/code&gt; declarations in Rake behave just like tasks &amp;#8211; they can have prerequisites, be dependencies, and be invoked via &lt;code&gt;rake&lt;/code&gt; &amp;#8211; but they only run if the target doesn&amp;#8217;t exist or the prerequisites are newer than the target.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s also a shortcut for creating directories:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;directory&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;

&lt;span class='c1'&gt;# ...is the same as:&lt;/span&gt;
&lt;span class='n'&gt;file&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;mkdir&lt;/span&gt; &lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s also possible to declare a transformation for a &lt;em&gt;set&lt;/em&gt; of files, not just a single file. Let&amp;#8217;s say that you have a directory of Markdown files, and you want to be able to transform any of &amp;#8216;em into HTML. Easy:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;rule&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;.html&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;.markdown&amp;quot;&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;t&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;sh&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;markdown &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;source&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &amp;gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='c1'&gt;# in your shell&lt;/span&gt;
&lt;span class='err'&gt;$&lt;/span&gt; &lt;span class='n'&gt;rake&lt;/span&gt; &lt;span class='n'&gt;foo&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Yay! Again, this will only run when the dependencies are unresolved, that is, if the target is missing or the source is newer.&lt;/p&gt;

&lt;h2 id='picking_nits'&gt;Picking Nits&lt;/h2&gt;

&lt;p&gt;A grab-bag of other bad usage I&amp;#8217;ve seen recently:&lt;/p&gt;

&lt;h3 id='prerequisites'&gt;Prerequisites&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:mystuff&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# ...&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:something&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:mystuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This isn&amp;#8217;t necessary. Unless you want to be able to use your &lt;code&gt;mystuff&lt;/code&gt; task independently, just define &lt;code&gt;something&lt;/code&gt; again:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:something&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# my stuff...&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;#8220;Redefining&amp;#8221; an existing task in Rake &lt;em&gt;appends&lt;/em&gt; the new actions (and prerequisites) to the original. Don&amp;#8217;t add new tasks unless you actually need them.&lt;/p&gt;

&lt;h3 id='explicit_invocation'&gt;Explicit Invocation&lt;/h3&gt;

&lt;p&gt;Sometimes it&amp;#8217;s necessary to run Rake tasks imperatively. That&amp;#8217;s fine. Run them with &lt;code&gt;invoke&lt;/code&gt;, not with &lt;code&gt;execute&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:mine&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# some setup stuff&lt;/span&gt;
  &lt;span class='no'&gt;Rake&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;theirstuff&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;invoke&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;invoke&lt;/code&gt; uses the same rules as normal Rake execution: If the task has run already, it won&amp;#8217;t run again. &lt;code&gt;execute&lt;/code&gt; runs the task no matter what. Make sure you know which one you want.&lt;/p&gt;

&lt;h2 id='fin'&gt;Fin&lt;/h2&gt;

&lt;p&gt;For a more detailed explanation of &lt;code&gt;directory&lt;/code&gt;, &lt;code&gt;file&lt;/code&gt;, and &lt;code&gt;rule&lt;/code&gt;, take a look at &lt;a href='http://docs.rubyrake.org/user_guide/chapter03.html'&gt;the Rake documentation&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Environment Setup</title>
   <link href="http://www.jbarnette.com/2009/07/24/dev-environment-setup.html"/>
   <updated>2009-07-24T00:00:00-07:00</updated>
   <id>http://www.jbarnette.com/2009/07/24/dev-environment-setup</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I&amp;#8217;m rereading this in the first quarter of 2011 and it&amp;#8217;s pretty obsolete. I&amp;#8217;ll update it at some point.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve had scattered notes on setting up a new development computer from scratch in Backpack for years now. Hopefully collecting them here will make it more likely that they&amp;#8217;ll stay up-to-date. This is &lt;em&gt;my&lt;/em&gt; environment, probably not what I&amp;#8217;d suggest for you.&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t necessarily install all of these all the time (MySQL), but I&amp;#8217;d still rather have all the instructions in one place.&lt;/p&gt;

&lt;p&gt;These notes assume Mac OS X Leopard, with the developer tools installed.&lt;/p&gt;

&lt;h2 id='fundamental_stuff'&gt;Fundamental Stuff&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://agilewebsolutions.com/products/1Password'&gt;1Password&lt;/a&gt;. It knows all.&lt;/li&gt;

&lt;li&gt;&lt;a href='https://www.getdropbox.com'&gt;Dropbox&lt;/a&gt;. Sync folders transparently.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.gnu.org/software/emacs'&gt;Emacs&lt;/a&gt;. I&amp;#8217;m building &lt;a href='http://github.com/jbarnette/ports'&gt;Emacs 23 via MacPorts&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.levien.com/type/myfonts/inconsolata.html'&gt;Inconsolata&lt;/a&gt;. My favorite programming font.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.obdev.at/products/launchbar/index.html'&gt;LaunchBar&lt;/a&gt;. Useless without it.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.macports.org'&gt;MacPorts&lt;/a&gt;. I use this to manage as much dev stuff as I can.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://culturedcode.com/things'&gt;Things&lt;/a&gt;. What am I supposed to be doing right now?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='important_stuff'&gt;Important Stuff&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://adium.im'&gt;Adium&lt;/a&gt;. I like talking on the digital internets.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://getfirefox.com'&gt;FireFox&lt;/a&gt;. I use Safari for daily browsing, but FF for lots of dev.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://growl.info'&gt;Growl&lt;/a&gt;. I turn off most notifications, but it&amp;#8217;s still good to have.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.indev.ca/MailActOn.html'&gt;Mail Act-On&lt;/a&gt;. Effortless filing in Mail.app.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.loganrockmore.com/MailUnreadMenu'&gt;Mail Unread Menu&lt;/a&gt;. Since I hide the dock and mute everything.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.parallels.com'&gt;Parallels&lt;/a&gt;. Only for testing stuff on Windows.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.shimoapp.com'&gt;Shimo&lt;/a&gt;. VPNs are dumb, but Shimo is pretty.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.panic.com/transmit'&gt;Transmit&lt;/a&gt;. FTP, SFTP, S3.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.atebits.com/tweetie-mac'&gt;Tweetie&lt;/a&gt;. WHAT ARE YOU DOING?!&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.xmarks.com'&gt;Xmarks&lt;/a&gt;. Cross-browser, cross-machine bookmark syncing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='nice_stuff'&gt;Nice Stuff&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://www.objectpark.org/FuzzyClock.html'&gt;FuzzyClock&lt;/a&gt;. Normal clocks are boring.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://wiki.github.com/Caged/gitnub'&gt;GitNub&lt;/a&gt;. Good for quick repo history scans.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://skitch.com'&gt;Skitch&lt;/a&gt;. Screenshots + sharing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='profile_emacs_configuration_etc'&gt;Profile, Emacs Configuration, etc.&lt;/h2&gt;

&lt;p&gt;I keep most of my dotfiles in a &lt;a href='http://github.com/jbarnette/dotfiles'&gt;Git repository&lt;/a&gt; and symlink them. I do the same thing with Dropbox for 1Password and Things.&lt;/p&gt;

&lt;h2 id='rubygems'&gt;RubyGems&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ sudo gem update --system&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='git'&gt;Git&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ sudo port install git-core +svn +doc
$ git config --global user.name John Barnette
$ git config --global user.email jbarnette@gmail.com&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='mysql'&gt;MySQL&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ sudo port install mysql5-server
$ sudo mysql_install_db5 --user=mysql
$ sudo port load mysql5-server&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add &lt;code&gt;/opt/local/lib/mysql5/bin&lt;/code&gt; to your path, and this should work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mysql -uroot&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='mysql_ruby_bindings'&gt;MySQL Ruby Bindings&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;sudo gem install mysql --                                    \
  --with-mysql-include=/opt/local/include/mysql5             \
  --with-mysql-lib=/opt/local/lib/mysql5                     \
  --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Versioning HTTP APIs</title>
   <link href="http://www.jbarnette.com/2009/04/07/http-apis.html"/>
   <updated>2009-04-07T00:00:00-07:00</updated>
   <id>http://www.jbarnette.com/2009/04/07/http-apis</id>
   <content type="html">&lt;p&gt;There&amp;#8217;s a lot of hot air circulating online re versioning HTTP APIs. I ignore most of it: It&amp;#8217;s RESTy folks without real load or customers, wanking about purity.&lt;/p&gt;

&lt;p&gt;I actually agree with some of the purist noise from a theoretical perspective, but in practice the implementations are annoying enough that they&amp;#8217;re simply not worth the effort.&lt;/p&gt;

&lt;p&gt;These suggestions apply to &lt;em&gt;external&lt;/em&gt; APIs: If you control all the endpoints, or if you&amp;#8217;re running a service where folks are more accepting of rapid change, you don&amp;#8217;t need to worry nearly as much.&lt;/p&gt;

&lt;p&gt;These also apply only to systems where there are lots of clients and a &lt;em&gt;single&lt;/em&gt; service endpoint. The landscape changes a bit if clients are hitting multiple, independent installations of your service.&lt;/p&gt;

&lt;p&gt;My rules of thumb for versioning an HTTP API:&lt;/p&gt;

&lt;h2 id='do_your_best_to_never_ever_break_compatibility'&gt;Do Your Best To Never, Ever, Break Compatibility&lt;/h2&gt;

&lt;p&gt;You don&amp;#8217;t need new versions if you don&amp;#8217;t break client compatibility! Don&amp;#8217;t make casual changes to the API. Remember your consumers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don&amp;#8217;t change resource URLs without a damn good reason.&lt;/li&gt;

&lt;li&gt;Don&amp;#8217;t let attribute/parameter positions matter.&lt;/li&gt;

&lt;li&gt;Accept and ignore unknown attributes/parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you follow these guidelines, there&amp;#8217;s no reason to break major API compatibility when you add new resources, parameters, or attributes.&lt;/p&gt;

&lt;h2 id='admit_that_youre_going_to_break_compatibility'&gt;Admit That You&amp;#8217;re Going to Break Compatibility&lt;/h2&gt;

&lt;p&gt;Nobody&amp;#8217;s perfect. It&amp;#8217;s gonna happen. Acknowledge it from the beginning, and design your URL scheme accordingly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://example.com/api/v1/widgets.json
http://example.com/api/v2/widgets.json&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Many RESTy folks object to this sort of namespace segmentation, because a resource should only have one identifier. That makes a lot of sense, but the implementation difficulties outweigh the benefits. It&amp;#8217;s a lot easier to route completely separate namespaces than it is to use content negotiation or any of the other &amp;#8220;more proper&amp;#8221; solutions.&lt;/p&gt;

&lt;h2 id='pick_sunsets_and_stick_to_them'&gt;Pick Sunsets and Stick To Them&lt;/h2&gt;

&lt;p&gt;How many API versions are you going to support? For how long? Be firm. I haven&amp;#8217;t generally seen a need to support more than two versions of an API simultaneously.&lt;/p&gt;

&lt;p&gt;Be helpful when you kill an API version. Have any requests to the old namespace return good error codes and messages (or permanent redirects to the new API).&lt;/p&gt;

&lt;p&gt;Be aggressive about communicating with your API consumers. Don&amp;#8217;t let them get caught by surprise when an API version goes away.&lt;/p&gt;

&lt;h2 id='write_documentation_as_you_go'&gt;Write Documentation as You Go&lt;/h2&gt;

&lt;p&gt;Most APIs start as an internal tool, and then get exposed to the world later. Most internal tools are very lightly documented. Don&amp;#8217;t do that! If it&amp;#8217;s an interface, &lt;em&gt;even if it&amp;#8217;s currently only used internally&lt;/em&gt;, document it as if it&amp;#8217;s intended for a wider audience. If you document incrementally, the burden is very low.&lt;/p&gt;

&lt;h2 id='write_really_damn_good_integration_tests'&gt;Write Really Damn Good Integration Tests&lt;/h2&gt;

&lt;p&gt;Keep your coverage high. Don&amp;#8217;t ever change tests, except to fix a test bug. You can &lt;em&gt;add&lt;/em&gt; to them, but if you&amp;#8217;re changing them you&amp;#8217;ve probably broken compatibility. When you have to break compatibility, &lt;em&gt;copy&lt;/em&gt; the current tests, document the difference in the test and the documentation, and alter them for the new version.&lt;/p&gt;

&lt;h2 id='ship_a_service_client'&gt;Ship a Service Client&lt;/h2&gt;

&lt;p&gt;Along with good service documentation, try to ship at least one client implementation of your API. If it&amp;#8217;s good, clean, well-tested, and well-documented, folks will use it as a guide when they port to their preferred environment.&lt;/p&gt;

&lt;p&gt;Design your API via working tests and it&amp;#8217;ll be more usable in the long run. If it&amp;#8217;s possible, have different people implement the server and the client.&lt;/p&gt;

&lt;h2 id='separate_api_from_ui'&gt;Separate API from UI&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re developing in a framework like Rails, avoid the temptation to mix your API and your UI controllers. Work hard to keep them separated. If there&amp;#8217;s enough logic in your UI controllers that it&amp;#8217;s hard to break out the API bits, your controllers are too fat. Refactor.&lt;/p&gt;

&lt;h2 id='a_quick_rails_example'&gt;A Quick (Rails) Example&lt;/h2&gt;

&lt;p&gt;Here&amp;#8217;s how I might implement a (very) small API. We&amp;#8217;ll start with a single resource &amp;#8211; a widget &amp;#8211; and build from there.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Api::V1::WidgetsController
controllers/api/v1/widgets_controller.rb

# Api::V1::WidgetsControllerTest
test/functional/api/v1/widgets_controller_test.rb

# Api::V1::WidgetsTest
test/integration/api/v1/widgets_test.rb&lt;/code&gt;&lt;/pre&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# in routes.rb&lt;/span&gt;
&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;namespace&lt;/span&gt; &lt;span class='ss'&gt;:api&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;api&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;api&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;namespace&lt;/span&gt; &lt;span class='ss'&gt;:v1&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;v1&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;v1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;resources&lt;/span&gt; &lt;span class='ss'&gt;:widgets&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='adding_an_attribute_to_the_widget_model'&gt;Adding an Attribute to the Widget Model&lt;/h3&gt;

&lt;p&gt;No new version is necessary: just add it. Don&amp;#8217;t forget to change the docs! Remember to clearly document that clients, like the server, should ignore unknown attributes.&lt;/p&gt;

&lt;h3 id='adding_a_new_resource'&gt;Adding a New Resource&lt;/h3&gt;

&lt;p&gt;No new version is necessary: just add it. If the clients don&amp;#8217;t know about a resource, they don&amp;#8217;t need to care. See the next section if you&amp;#8217;re adding a relationship to an existing resource: The same restrictions apply.&lt;/p&gt;

&lt;h3 id='renaming_an_attribute_on_the_widget_model'&gt;Renaming an Attribute on the Widget Model&lt;/h3&gt;

&lt;p&gt;Okay, so this is a breaking change. Time for v2!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cp -r app/controllers/api/v1 app/controllers/api/v2
$ cp -r test/functional/api/v1 test/functional/api/v2
$ cp -r test/integration/api/v1 test/integration/api/v2
$ cp -r doc/api/v1 doc/api/v2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Use the method of your choice to change all references under the new paths from &amp;#8220;V1&amp;#8221; to &amp;#8220;V2&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Don&amp;#8217;t forget to copy your routes to a new v2 namespace. Once you&amp;#8217;ve done all this for the first time, write a Rake task to do it for you. For extra points, write a task that removes an older API version and make the generation task complain if you&amp;#8217;re trying to support too many version simultaneously.&lt;/p&gt;

&lt;p&gt;Add your breaking features, change the new v2 tests, update the docs and your client reference implementation, and get on with your life.&lt;/p&gt;

&lt;p&gt;When the new version goes live, it&amp;#8217;s time to start communicating with your consumers about when the old version is going away.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Focusing Autotest</title>
   <link href="http://www.jbarnette.com/2009/01/23/focusing-autotest.html"/>
   <updated>2009-01-23T00:00:00-08:00</updated>
   <id>http://www.jbarnette.com/2009/01/23/focusing-autotest</id>
   <content type="html">&lt;p&gt;Looking at &lt;a href='http://github.com/spicycode/micronaut'&gt;micronaut&lt;/a&gt; made me realize that I often want to iterate very quickly on a single test, rather than having Autotest re-run every test in the file each time I save. After a quick chat with &lt;a href='http://blog.zenspider.com'&gt;Ryan&lt;/a&gt; &amp;#8211; whose suggestion was &lt;em&gt;way&lt;/em&gt; simpler than what I was considering &amp;#8211; here&amp;#8217;s what popped out:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Test&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Unit&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;TestCase&lt;/span&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;focus&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;focused&lt;/span&gt;
    &lt;span class='n'&gt;focused&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;collect!&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_s&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='nb'&gt;instance_methods&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
      &lt;span class='n'&gt;collect&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_s&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
      &lt;span class='nb'&gt;select&lt;/span&gt;  &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;m&lt;/span&gt; &lt;span class='o'&gt;=~&lt;/span&gt; &lt;span class='sr'&gt;/^test/&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
      &lt;span class='n'&gt;reject&lt;/span&gt;  &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;focused&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;include?&lt;/span&gt; &lt;span class='n'&gt;m&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
      &lt;span class='n'&gt;each&lt;/span&gt;    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;undef_method&lt;/span&gt; &lt;span class='n'&gt;m&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;With this snippet in my test helper file, I can easily focus on just one test:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;MyTest&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Test&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Unit&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;TestCase&lt;/span&gt;
  &lt;span class='c1'&gt;# lots of tests&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;test_thingy&lt;/span&gt;
    &lt;span class='c1'&gt;# ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='c1'&gt;# lots more tests&lt;/span&gt;

  &lt;span class='n'&gt;focus&lt;/span&gt; &lt;span class='ss'&gt;:test_thingy&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;#8230;and remove the focus when I&amp;#8217;m ready to zoom out. Awesome. Sprinkle on some editor support and it&amp;#8217;ll be &lt;em&gt;epic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(2009-03-27: This is available in the latest ZenTest.)&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Parsing Ruby is Hard</title>
   <link href="http://www.jbarnette.com/2009/01/22/parsing-ruby-is-hard.html"/>
   <updated>2009-01-22T00:00:00-08:00</updated>
   <id>http://www.jbarnette.com/2009/01/22/parsing-ruby-is-hard</id>
   <content type="html">&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='s2'&gt;&amp;quot;Parsing &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Ruby &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;is &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt; &lt;span class='sx'&gt;%(hard)&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; &amp;quot;Parsing Ruby is hard.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Note to Self</title>
   <link href="http://www.jbarnette.com/2009/01/21/note-to-self.html"/>
   <updated>2009-01-21T00:00:00-08:00</updated>
   <id>http://www.jbarnette.com/2009/01/21/note-to-self</id>
   <content type="html">&lt;h2 id='be_confident'&gt;Be Confident&lt;/h2&gt;

&lt;p&gt;Tests build confidence. Write &amp;#8216;em. They&amp;#8217;ll save your ass, and they&amp;#8217;ll let you take a chainsaw to your code without being afraid of unintended consequences.&lt;/p&gt;

&lt;h2 id='be_lazy'&gt;Be Lazy&lt;/h2&gt;

&lt;p&gt;Write tools. If it&amp;#8217;s happened more than twice, don&amp;#8217;t ever do it by hand again.&lt;/p&gt;

&lt;h2 id='be_asynchronous'&gt;Be Asynchronous&lt;/h2&gt;

&lt;p&gt;If it can be done outside the request/response cycle, consider queuing it. Mailers, uploads, audit trails, anything with an external system dependency or a lot of IO.&lt;/p&gt;

&lt;h2 id='be_stateful'&gt;Be Stateful&lt;/h2&gt;

&lt;p&gt;If there&amp;#8217;s a lifecycle, model it as a real state machine. Beware ad hoc flags.&lt;/p&gt;

&lt;h2 id='be_clear'&gt;Be Clear&lt;/h2&gt;

&lt;p&gt;You&amp;#8217;ll write it once, but you&amp;#8217;ll read it a lot. Code accordingly. Sometimes simplicity takes a bit longer, but it&amp;#8217;ll pay off.&lt;/p&gt;

&lt;h2 id='be_consistent'&gt;Be Consistent&lt;/h2&gt;

&lt;p&gt;Inconsistent file names, task names, and coding styles hurt productivity.&lt;/p&gt;

&lt;h2 id='be_timely_but_not_too_timely'&gt;Be Timely (but not too timely)&lt;/h2&gt;

&lt;p&gt;Keep frameworks, plugins, libraries, and tools up-to-date, but think twice before using a production app to play with the bleeding edge.&lt;/p&gt;

&lt;h2 id='be_certain'&gt;Be Certain&lt;/h2&gt;

&lt;p&gt;Don&amp;#8217;t speculate, get data. Act on what you know, not what you suspect. Is that code really faster? Do users really want that feature?&lt;/p&gt;

&lt;h2 id='be_persistent'&gt;Be Persistent&lt;/h2&gt;

&lt;p&gt;Find the root cause. Keep asking &lt;strong&gt;why&lt;/strong&gt;, even when you&amp;#8217;re tired and under the gun. The guesswork patch you write today will be a nightmare tomorrow.&lt;/p&gt;

&lt;h2 id='be_wrong'&gt;Be Wrong&lt;/h2&gt;

&lt;p&gt;If it&amp;#8217;s not working, change it, no matter how long it took to write. Don&amp;#8217;t throw good money after bad. Admit mistakes early and often.&lt;/p&gt;</content>
 </entry>
 
</feed>
