<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Mechanical Robot Fish]]></title>
  <link href="http://www.mechanicalrobotfish.com/atom.xml" rel="self"/>
  <link href="http://www.mechanicalrobotfish.com/"/>
  <updated>2012-01-20T23:28:11-05:00</updated>
  <id>http://www.mechanicalrobotfish.com/</id>
  <author>
    <name><![CDATA[Michael F. Booth]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Minimum Viable Blog Post]]></title>
    <link href="http://www.mechanicalrobotfish.com/blog/2011/11/23/minimum-viable-blog-post/"/>
    <updated>2011-11-23T23:03:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/blog/2011/11/23/minimum-viable-blog-post</id>
    <content type="html"><![CDATA[<p>I&#8217;m off to the <a href="http://businessofsoftware.org/">Business of Software conference</a> in Boston, which
the organizers have been kind enough to bring to my home city <em>even
though they appear to live in another country altogether.</em></p>

<p>In the meantime, as always, you can
<a href="https://twitter.com/#!/mechanical_fish">follow @mechanical_fish on Twitter</a> or even
<a href="https://news.ycombinator.com/threads?id=mechanical_fish">the mechanical_fish comment stream on Hacker News</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unit testing hints that you might have missed the first time]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/135-unit-testing-hints-you-might-have-missed-first-time"/>
    <updated>2009-07-13T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/unit-testing-hints-that-you-might-have-missed-the-first-time</id>
    <content type="html"><![CDATA[<p>After spending all too many hours toiling away on Drupal 5 sites
without the benefit of unit testing, I&#8217;m finally getting to spend some
quality time with Drupal 6&#8217;s
<a href="http://drupal.org/simpletest">SimpleTest</a> module. Things have
certainly gotten a lot better in the Drupal testing world over the
last year or two.</p>

<p>As I work to develop my testing chops it&#8217;s hard to avoid pining for
Ruby, where the community has been obsessed with testing for years,
where lots of experiments have been tried, and where the language
syntax actually works with you to make test code more elegant. Even
something basic, like asserting the presence of an exception in PHP:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="nv">$threw</span> <span class="o">=</span> <span class="k">FALSE</span><span class="p">;</span>
</span><span class='line'><span class="k">try</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">something_broken</span><span class="p">();</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">catch</span> <span class="p">(</span><span class="nx">MyKindOfException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="nv">$threw</span> <span class="o">=</span> <span class="k">TRUE</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertTrue</span><span class="p">(</span><span class="nv">$threw</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>&#8230;becomes so much nicer in Ruby test/unit (which is hardly the last
word in Ruby testing utilities):</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">assert_raise</span> <span class="no">MyKindOfError</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">something_broken</span><span class="p">()</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>But, though we can&#8217;t hope to mimic the elegance of Ruby&#8217;s block syntax
in PHP, we can at least try to take advantage of the Ruby community&#8217;s
hard-won experience with testing methodologies and design
patterns. One of my favorite Ruby bloggers was
<a href="http://blog.jayfields.com">Jay Fields</a> &#8211; he&#8217;s been working more in
Java lately, but his old Rails links live on:</p>

<ul>
<li><p>First, the disclaimer: Even the &#8220;industry experts&#8221; on testing are
<a href="http://blog.jayfields.com/2009/02/thoughts-on-developer-testing.html">still trying to figure it out</a>,
and
<a href="http://blog.jayfields.com/2008/06/developer-testing-and-importance-of.html">there is no silver bullet</a>:
the right kind of testing to do depends on what you&#8217;re trying to
write.</p></li>
<li><p>Having said that:
<a href="http://blog.jayfields.com/2007/06/testing-inline-setup.html">Setup and teardown methods make your tests less readable and maintainable</a>,
and the guy who designed the NUnit library
<a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">wishes he hadn&#8217;t supported them at all</a>.</p></li>
<li><p>The Rails community has experimented with many ways of
representing the data that your tests will operate on. Rails 1.0
provided
<a href="http://ar.rubyonrails.org/classes/Fixtures.html">fixtures</a>; after
much trial and error, the consensus seems to be that
<a href="http://www.daikini.com/past/2007/6/10/rails_fixtures/">they suck</a>
and that you will eventually figure that out. The folks I follow
have dabbled with
<a href="http://www.c2.com/cgi/wiki?ObjectMother">Object Mothers</a> before
settling (for the moment) on the
<a href="http://nat.truemesh.com/archives/000714.html">Test Data Builders</a>
pattern; the fairly popular
<a href="http://giantrobots.thoughtbot.com/2008/6/6/waiting-for-a-factory-girl">Factory Girl</a>
library appears to be a Rails implementation of the Test Data
Builder concept.</p></li>
<li><p>In production software, duplicated code is generally considered
harmful. In test code,
<a href="http://blog.jayfields.com/2008/05/testing-duplicate-code-in-your-tests.html">duplicated code is often your friend</a>. It
is more important for a test routine to be easily understood in
isolation than for it to avoid duplicating other test
routines. Test code is not production code: The tests run in
isolation, are generally read in isolation, and benefit from being
written in isolation.</p></li>
<li><p>While we&#8217;re on the subject of isolation:
<a href="http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html">write one assertion per test</a>. I
like this idea, but &#8211; alas! &#8211; it is an even more radical idea in
Drupal than it is in Rails or Java, because SimpleTest is (a)
wicked slow at the moment and (b) linearly dependent on the number
of test methods. (Or such is my impression &#8211; insert a caveat
about the importance of formal benchmarking here.) I believe
SimpleTest does a lot of tedious DB setup and teardown for every
test method, and it doesn&#8217;t have
<a href="http://clarkware.com/cgi/blosxom/2005/10/24">transactional tests</a>. One
of us needs to be chained to a desk next to
<a href="http://drupal.org/user/214218">boombatower</a> and forced to
<a href="http://drupal.org/node/323477">implement some speed boosts</a>.</p></li>
</ul>


<p>But, even if we are compelled to compromise in practice, we can still
hold the ideal in our hearts: one assertion per test is great,
multiple assertions per test is a compromise, and tests which
interdepend on each other in a complicated way are&#8230; not good.</p>

<ul>
<li><p>Here&#8217;s one I need to think about:
<a href="http://blog.jayfields.com/2008/05/testing-value-of-test-names.html">writing tests without names</a>. Not
that we will be doing this in PHP soon; even in Ruby it
<a href="http://expectations.rubyforge.org/svn/trunk/test/failures_test.rb">looks a little weird</a>. But
if zero names might be right, then <em>two</em> names is almost certainly
one too many. I&#8217;ve been thinking about the Drupal SimpleTest
convention of equipping every assertion with a gloriously
descriptive, HTML-formatted comment:</p>

<pre><code>$this-&gt;assertTrue($bool, t('The bool should be true'));
</code></pre>

<p>and noticing that the presence of the comment makes the test
method&#8217;s name entirely redundant. Maybe I&#8217;ll experiment with using
tiny, inconspicuous method names.</p></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The other half of the word "Wikipedia"]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/134-other-half-word-wikipedia"/>
    <updated>2009-05-06T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/the-other-half-of-the-word-wikipedia</id>
    <content type="html"><![CDATA[<p>In
<a href="">Tom Geller&#8217;s recent grumble about the official Drupal Handbooks on Drupal.org</a>,
he notes a problem (the tree of docs is huge and is difficult to
reorganize or prune) but &#8211; like most of the rest of us &#8211; he isn&#8217;t
quite certain how to solve it. So he offers a prayer to the gods of
WIkipedia, as so many have done before:</p>

<blockquote><p>Converting Drupal.org&#8217;s documentation into a wiki(-like) format might help &#8220;crowdsource&#8221; the task.</p></blockquote>

<p>Funny thing about this recommendation, which all of us have been
tempted to issue at one time or another: The docs <em>are</em> in a
&#8220;wiki-like format&#8221;. Any registered user on
<a href="http://drupal.org">Drupal.org</a> can edit a page. All of its revisions
are accessible. You can show diffs between revisions.</p>

<p>And yet the problem is not solved. The Drupal docs are still nowhere
near as good as a wiki. Or &#8211; important distinction &#8211; they are
nowhere near as good as Wikipedia, which is what most people think of
when they think of <em>a wiki</em>.</p>

<h2>You can&#8217;t spell Wikipedia without &#8220;Pedia&#8221;</h2>

<p>But <strong>Wikipedia is not the typical wiki</strong>. (My impression is that the
<em>average</em> wiki on the Internet kind of sucks &#8211; the Rails wiki, for
example, was
<a href="http://weblog.rubyonrails.org/2009/2/10/the-state-of-the-wiki">legendarily disorganized and out of date</a>
until recently.)</p>

<p>Wikipedia&#8217;s secret is that it isn&#8217;t just a wiki. <strong>It&#8217;s an
<em>encyclopedia</em>, an old and familiar genre with well-understood
semantics.</strong> When you see a Wikipedia link to a term like
&#8221;<a href="http://en.wikipedia.org/wiki/Bluegrass_music">bluegrass music</a>&#8221;, you
see more than just a link: You <em>already know what is on the other
end</em>.</p>

<ul>
<li><p>The topic of the article is more-or-less completely defined by the
title of the link.</p></li>
<li><p>The entry will be written for a general audience and will not
contain excessive detail or be too long.</p></li>
<li><p>The entry may relate to other entries, but is designed to stand
alone. No prerequisites will be assumed.</p></li>
</ul>


<p><strong>It is this implicit context that makes Wikipedia so usable.</strong> That&#8217;s
  why you can read a Wikipedia page filled with
  <a href="http://en.wikipedia.org/wiki/Bluegrass_music">hundreds of internal Wikipedia links</a>
  and not get lost. You know what each of those links are. And that&#8217;s
  why each <em>external</em> link gets special formatting on Wikipedia: It&#8217;s
  a warning. &#8220;This is not like the other links; you don&#8217;t know what&#8217;s
  out there. Prepare to be rickrolled.&#8221;</p>

<h2>The encyclopedia is flat</h2>

<p>One of Wikipedia&#8217;s other friendly features is that <strong>the Wikipedia
architecture is a big flat list</strong>. True, there are &#8220;superarticles&#8221;,
like
<a href="http://en.wikipedia.org/wiki/Cake_(disambiguation">disambiguation pages</a>). And
there are pages with subtopics. But there are very few special
structures for creating such pages, and no real provision at all for
creating trees with formally defined &#8220;parent&#8221; pages and &#8220;child&#8221;
pages. So, nobody does that.</p>

<p>This is <em>great</em> because <strong>it frees people from worrying about
organization</strong>. You can start a new Wikipedia article by searching for
the intended title and clicking &#8220;create the article&#8221;. No need to worry
about where it fits in some grand Wikipedia schema. No need to figure
out how to edit the <em>Music</em> category to indicate that <em>progressive
bluegrass</em> is a kind of <em>bluegrass</em>. No need to figure out what kind
of music
<a href="http://en.wikipedia.org/wiki/Béla_Fleck_and_the_Flecktones">the Flecktones</a>
play. (Is &#8220;blu-bop&#8221; a real word? It is now!)</p>

<p>There is also no danger of accidentally creating <em>two</em> entries for the
term &#8220;bluegrass music&#8221;.</p>

<p>A Wikipedia editor only needs to edit the content. <strong>A Drupal handbook
editor must not only edit the content but also arrange it in a
structure.</strong> That&#8217;s a whole new level of difficulty and intimidation.</p>

<h2>What does this mean for Drupal?</h2>

<p><strong>It would actually be really nice to have a Drupal Encyclopedia</strong> &#8211;
a collection of pages, designed to be read independently, which each
cover a single topic in encyclopedia fashion for a general audience.</p>

<p><strong>But, as a general-purpose organizational scheme for the Handbooks,
the encyclopedia model doesn&#8217;t work.</strong> Sometimes the Handbooks need to
contain pages with obsessively detailed instructions. Sometimes we
need explanations of complex topics that go on for more than one page
and need to be read in order. Often it&#8217;s impossible to capture a
page&#8217;s entire context in its title, so we need to organize pages into
topical sections and subsections and chapters and books.</p>

<p>In other words, <strong>Wikipedia&#8217;s design is not a silver bullet</strong>. We&#8217;re
not trying to write an encyclopedia. We&#8217;re trying to write something
different, and more complicated. No wonder it&#8217;s so much harder to get
right.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[In praise of ancient paper technology]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/133-praise-ancient-paper-technology"/>
    <updated>2009-05-05T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/in-praise-of-ancient-paper-technology</id>
    <content type="html"><![CDATA[<p>I&#8217;m gearing up to comment on Tom Geller&#8217;s recent <a href="http://tomgeller.com/content/problem-drupal-documentation">grumbles about the Drupal free documentation</a>, but first I feel that I should point out the obvious: Drupal has some great <em>paid</em> documentation. Some highlights that I know about:</p>

<ul>
<li><p>People who want to know what all the fuss is about can pick up The Lullabots&#8217; <a href="http://www.usingdrupal.com/">Using Drupal</a>, which I&#8217;m using as light bedtime reading.</p></li>
<li><p>Hard-core coders who contemplate deploying Drupal should definitely read <a href="http://www.drupalbook.com/">Pro Drupal Development</a>, a truly indispensable guide to Drupal&#8217;s innards.</p></li>
<li><p>Javascript is a Drupal component, too. An increasingly important one, in fact. Which gives me an excuse to plug one of my favorite software books ever: Crockford&#8217;s <a href="">Javascript: The Good Parts</a>. A blessedly <em>short</em> but dense book. Just the sort of thing that Tom Geller might like, I suspect.</p></li>
</ul>


<p>The open-source revolution has proceeded so swiftly that some people seem to have forgotten that <em>all</em> documentation used to come in big paper books that cost money. Yet that technology is still surprisingly useful! And it really isn&#8217;t that <em>much</em> money, compared to the medical expense of continually banging your head on your desk.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A Very Subtle Git-CVSImport Bug, and Its Workaround]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/132-very-subtle-git-cvsimport-bug-and-its-workaround"/>
    <updated>2009-04-13T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/a-very-subtle-git-cvsimport-bug-and-its-workaround</id>
    <content type="html"><![CDATA[<p>I&#8217;ve been trying to follow
<a href="http://mikkel.hoegh.org/blog/2008/a_git_mirror_for_drupal_cvs?page=2">Mikkel Hoegh&#8217;s handy instructions</a>
to mirror some of the Drupal CVS repositories onto github, so that git
users like myself can make better use of our favorite tool. But I hit
a snag last month when I found a bug in my Drupal git mirror. A commit
from last December had failed to go through, breaking all the Drupal 7
commits since then.</p>

<p>I&#8217;ve spent some time off and on trying to figure out what went wrong,
since a mirror with occasional errors and omissions isn&#8217;t very
useful. Just today I found
<a href="http://stackoverflow.com/questions/702980/why-is-git-cvsimport-missing-one-major-patchset">a very handy post on Stack Overflow</a>
that appears to have solved my problem.</p>

<p>I had tried using Mikkel&#8217;s command to mirror a CVS repository with git:</p>

<pre><code>git-cvsimport -v -d:pserver:anonymous@cvs.drupal.org:/cvs/drupal -o upstream drupal
</code></pre>

<p>Which (oddly) seems to work for him &#8211; his own
<a href="http://github.com/mikl/drupal/tree/master">Drupal mirror on github</a>
works just fine. It didn&#8217;t work for me, though. Neither did this:</p>

<pre><code>git cvsimport -p x -v -k -o cvshead -s _ -d :pserver:anonymous@cvs.drupal.org:/cvs/drupal -C drupal drupal
</code></pre>

<p>But it turns out that the <code>-p x</code> flag, which means &#8220;pass the -x flag
through to cvsps&#8221;, isn&#8217;t correct. You have to say <code>-p -x</code>, like this:</p>

<pre><code>git cvsimport -p -x -v -k -o cvshead -s _ -d :pserver:anonymous@cvs.drupal.org:/cvs/drupal -C drupal drupal
</code></pre>

<p>One tiny dash makes the difference. My new mirror appears to be
correct. I&#8217;m glad someone else found this workaround, since I would
probably have never found it myself.</p>

<p>Having said that, I&#8217;m actually going to take down my own Drupal mirror
on github and recommend that everyone use
<a href="http://github.com/mikl/drupal/tree/master">Mikkel&#8217;s instead</a>. It&#8217;s
correct and, so long as he is maintaining it, it makes no sense to
waste resources maintaining it twice. What I&#8217;m going to do is put up
some mirrors of common Drupal modules to go along with it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Getting Git Together with Drupal]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/130-getting-git-together-drupal"/>
    <updated>2009-03-09T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/getting-git-together-with-drupal</id>
    <content type="html"><![CDATA[<p><strong>UPDATE:</strong> <em>This system was an experiment and I no longer use it. I feel
it&#8217;s too complicated to be worth the effort.</em></p>

<p>Any programming project &#8211; including Drupal projects &#8211; should use a
version control system. My favorite such system is
<a href="http://git-scm.com/">git</a>. If you haven&#8217;t tried it I recommend that
you learn all about it at the tutorial section of
<a href="https://github.com/guides">github</a>, or from Peepcode&#8217;s
<a href="http://peepcode.com/products/git">git screencast</a>.</p>

<p>Assuming that you understand the basics of git, let&#8217;s apply it to a
Drupal project. The simplest strategy is to create a single git
repository that holds everything in your project. You download Drupal
core and modules (using FTP, the
<a href="http://drupal.org/project/update_advanced">Update Status</a> module, or
<a href="http://drupal.org/project/drush">drush</a>) and you check them into git
as you install them. Your custom changes get checked into the same git
repository.</p>

<p>Here&#8217;s a couple of hints:</p>

<h3>Use branches to separate your code from contrib</h3>

<p>You want to make it easy to distinguish changes that you make from
those made by others. Creating branches is a good way to accomplish
this. When you first set up your project, create:</p>

<ul>
<li><p>A branch called <code>core</code>. You should check the Drupal core code into this branch.</p></li>
<li><p>A branch called <code>modules</code>, based on <code>core</code>. When you install a third
party module, you should do so in this branch. (Actually, it would
be ideal to create a separate branch for each module, but that&#8217;s a
bit of work to manage so I&#8217;ll hold off on recommending that. I&#8217;d
hate to scare you away on the first day.)</p></li>
<li><p>Branches for your site&#8217;s code, based on <code>modules</code>. You&#8217;ll probably
want a development branch (I tend to name this <code>devel</code>) and a
production branch (for which I often use <code>master</code>).</p></li>
</ul>


<p>When you need to update core, you do so in the <code>core</code> branch, then
merge <code>core</code> into <code>modules</code> and any other branch that depends on
it. When you need to update a module, you do so by switching to the
<code>module</code> branch, performing and committing the update, and then
merging <code>module</code> into your development branches.</p>

<h3>Tell git to ignore certain files</h3>

<p>There are certain files in your Drupal installation that you should
probably not have under version control at all:</p>

<ul>
<li><p>The <code>files</code> directory, which contains uploaded files.</p></li>
<li><p>Any <code>settings.php</code> files.</p></li>
<li><p>Utility files used by your editor or IDE: <code>.project</code> files, <code>TAGS</code>
files, etc.</p></li>
</ul>


<p>There are two ways to make git ignore certain files. One is to put the
names of those files in a file called <code>.gitignore</code> in the base
directory of the respository, right next to the <code>.git</code> directory. The
other is inside the <code>.git</code> directory itself: If you add the name of a
file to <code>.git/info/exclude</code> it will be excluded from the repository.</p>

<p>No matter which method you use, git won&#8217;t delete the ignored files &#8211;
it will just pretend that they aren&#8217;t there. You can ignore whole
directories, and you can use wildcards to make git ignore entire sets
of files with similar names.</p>

<p>How do you choose which ignoring method to use? The idea is that
<code>.gitignore</code> is part of your project: You check it in to git, and it
gets copied around wherever your project goes (e.g. to your
development server). So if you want to ignore a file across all
servers (like the <code>files</code> directory, which will exist everywhere you
install the code), you should put that file&#8217;s name in
<code>.gitignore</code>. Whereas <code>.git/info/exclude</code> is for files that only occur
in your local repository and aren&#8217;t expected to be anywhere else, like
editor settings files, or the directory beneath <code>sites</code> which
corresponds to your local machine&#8217;s test domain.</p>

<h3>Example</h3>

<p>Here&#8217;s a set of example commands for building a new project. We&#8217;ll
assume you&#8217;ve already downloaded the necessary Drupal tar files to
<code>~/Downloads</code>.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>mkdir myproject
</span><span class='line'><span class="nb">cd </span>myproject
</span><span class='line'>git init
</span><span class='line'>
</span><span class='line'><span class="c"># make .gitignore right away. </span>
</span><span class='line'><span class="c"># This will be handy later; it also</span>
</span><span class='line'><span class="c"># gives us something to check in immediately. </span>
</span><span class='line'><span class="c"># You can&#39;t start creating branches without</span>
</span><span class='line'><span class="c"># checking something in first</span>
</span><span class='line'>
</span><span class='line'><span class="nb">echo</span> <span class="s2">&quot;files&quot;</span> &gt; .gitignore
</span><span class='line'>git add .gitignore
</span><span class='line'>git commit -m <span class="s2">&quot;New Drupal project: myproject&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="c"># create the core branch and install drupal core</span>
</span><span class='line'>git branch core
</span><span class='line'>git checkout core
</span><span class='line'>tar xvfz ~/Downloads/drupal-6.9.tar.gz
</span><span class='line'>git add .
</span><span class='line'>git commit -m <span class="s2">&quot;Installed Drupal 6.9 core&quot;</span>
</span><span class='line'>git tag DRUPAL-6-9
</span><span class='line'>
</span><span class='line'><span class="c"># create the modules branch and install a </span>
</span><span class='line'><span class="c"># couple of modules.</span>
</span><span class='line'><span class="c"># This time let&#39;s make the branch and check it out </span>
</span><span class='line'><span class="c"># in one command.</span>
</span><span class='line'>git checkout -b modules core
</span><span class='line'>mkdir sites/all/modules
</span><span class='line'><span class="nb">cd </span>sites/all/modules
</span><span class='line'>tar xvfz ~/Downloads/views-6.x-2.2.tar.gz
</span><span class='line'>git add .
</span><span class='line'>git commit -m <span class="s2">&quot;Installed Views 6.x-2.2&quot;</span>
</span><span class='line'>tar xvfz ~/Downloads/cck-6.x-2.1.tar.gz
</span><span class='line'><span class="c"># add and commit in one command</span>
</span><span class='line'>git commit -a -m <span class="s2">&quot;Installed CCK 6.x-2.1&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="c"># now get to work on your own code</span>
</span><span class='line'>git checkout -b devel modules
</span></code></pre></td></tr></table></div></figure>


<p>When it comes time to upgrade core:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>git checkout core
</span><span class='line'>tar xvfz ~/Downloads/drupal-6.10.tar.gz
</span><span class='line'>git commit -a -m <span class="s2">&quot;Upgraded to Drupal 6.10&quot;</span>
</span><span class='line'>git tag DRUPAL-6-10
</span><span class='line'>git checkout modules
</span><span class='line'>git merge core
</span><span class='line'>git checkout devel <span class="c"># or any other branch</span>
</span><span class='line'>git merge modules
</span></code></pre></td></tr></table></div></figure>


<p>Now, if you need to know the difference between the current version of
core and the previous one:</p>

<pre><code>git diff core^ core
</code></pre>

<p>If you need to know the difference between the current official
version of the Views module and the one in your code (perhaps because
you&#8217;ve made a few patches):</p>

<pre><code>git diff modules devel sites/all/modules/views
</code></pre>

<p>Or, for all the work you&#8217;ve done on the Views module in the <code>devel</code>
branch since the last time you merged <code>modules</code> and <code>devel</code>:</p>

<pre><code>git diff modules...devel sites/all/modules/views
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Celebrating Drupal 6 With A Test Post]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/129-celebrating-drupal-6-test-post"/>
    <updated>2009-02-27T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/celebrating-drupal-6-with-a-test-post</id>
    <content type="html"><![CDATA[<p>The blog has now been updated to Drupal 6. There aren&#8217;t a lot of
visible differences yet (unless you are an IE6 user&#8230; you folks have
been officially deprecated) &#8211; the very nice Drupal 6 theming
improvements made it pretty easy to duplicate my old style, while
cleaning it up a lot at the same time.</p>

<p>Some people have accused D6 of being both easier and harder to theme,
but so far all I can perceive is the &#8220;easier&#8221; part, perhaps because
I&#8217;ve been elbow-deep in the Drupal 5 theming functions and know how
complicated <em>that</em> was.</p>

<!--break-->

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Did you know Internet Explorer 6 limits how many stylesheets are loaded?]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/128-did-you-know-internet-explorer-6-limits-how-many-stylesheets-are-loaded"/>
    <updated>2009-01-19T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/did-you-know-internet-explorer-6-limits-how-many-stylesheets-are-loaded</id>
    <content type="html"><![CDATA[<p>As a matter of fact,
<a href="http://tech.forumone.com/archives/144-Did-you-know-Internet-Explorer-6-limits-how-many-stylesheets-are-loaded.html">I did not</a>.</p>

<p>Worse, IE7 apparently does the same thing.</p>

<p>It&#8217;s funny how much time I spent looking for a much more obscure IE6
problem (you know, one like the other 1,001 IE6 problems) when the
evidence of this one was staring me in the face. It took a while
before I thought of googling &#8220;IE6 too many stylesheets bug&#8221;, because
<em>who would impose an arbitrary thirty-stylesheet limit</em>? What would be
the <em>point</em> of that?</p>

<p>I never saw it coming. Touché, Microsoft engineers!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Checking out an open-source git project: the right way]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/127-checking-out-open-source-git-project-right-way"/>
    <updated>2008-11-07T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/checking-out-an-open-source-git-project-the-right-way</id>
    <content type="html"><![CDATA[<p>(<em>Paraphrased from
<a href="http://blog.mhartl.com/2008/10/14/setting-up-your-git-repositories-for-open-source-projects-at-github/">Long Nguyen&#8217;s guide to checking out projects from GitHub</a>
&#8211; which is excellent, except that Long uses the name &#8220;long&#8221; for too
many different things, making the code hard for mere mortals to
read.</em>)</p>

<p>Suppose you would like to work on the open-source Insoshi project. You
have the URL of its official git repository:</p>

<pre><code>git://github.com/insoshi/insoshi.git
</code></pre>

<p>You could simply clone this URL to your own machine:</p>

<pre><code>$ git clone git://github.com/insoshi/insoshi.git
</code></pre>

<p>after which you could mess around with your local copy as much as you
like. But it&#8217;s hard to share a local repository with your friends, or
among several machines, so perhaps you&#8217;d rather create a private fork
on a server somewhere. It&#8217;s easy to do this with a GitHub-hosted
project like Insoshi &#8211; you get a GitHub account, then press GitHub&#8217;s
&#8220;fork&#8221; button, and you rewarded with the URL for your own personal
GitHub-hosted fork:</p>

<pre><code>git@github.com:mechfish/insoshi.git
</code></pre>

<p>Now you could make a local clone of that remote fork:</p>

<pre><code>$ git clone git@github.com:mechfish/insoshi.git
</code></pre>

<p>but there are disadvantages to that. One is that the local clone will
have a different parent: its <code>origin</code> will be remote fork, while the
remote fork&#8217;s <code>origin</code> is the official project repository. Ideally,
you would want the two repositories to be interchangeable, so that you
won&#8217;t get confused when comparing them, and so you can upload the
local version to replace the remote version if it gets lost or
corrupted.</p>

<p>You&#8217;d also like to be able to pull changes from the official
repository directly into your local copy, then push them up to the
remote fork, rather than having to pull every change forward through
the chain: official -> remote fork -> local copy. That&#8217;s painful.</p>

<p>So here&#8217;s what to do:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>git clone git://github.com/insoshi/insoshi.git
</span><span class='line'><span class="nb">cd </span>insoshi
</span><span class='line'>git branch devel master
</span><span class='line'>git checkout devel
</span><span class='line'>git remote add fork git@github.com:mechfish/insoshi.git
</span><span class='line'>git fetch fork
</span><span class='line'>git push fork devel:refs/heads/devel
</span><span class='line'>git config branch.devel.remote fork
</span><span class='line'>git config branch.devel.merge refs/heads/devel
</span></code></pre></td></tr></table></div></figure>


<p>Here&#8217;s what these commands accomplish:</p>

<ul>
<li><p>Clone the official repository and <code>cd</code> into the local copy.</p></li>
<li><p>Create a <code>devel</code> branch to develop on. Note that if we want to base
our development branch on the &#8220;edge&#8221; version of the project instead
of the stable version we should do this instead: <code>$ git branch
--track edge origin/edge; git branch devel edge</code></p></li>
<li><p>Checkout our new <code>devel</code> branch.</p></li>
<li><p>Add a remote named &#8220;fork&#8221; that points to our private fork on the remote server.</p></li>
<li><p>Fetch the remote fork&#8217;s contents.</p></li>
<li><p>Push our new <code>devel</code> branch to the remote fork, where it should have the same name.</p></li>
<li><p>Set the <code>config</code> for the <code>devel</code> branch so that it automatically
pushes changes to the <code>devel</code> branch on the remote fork when we do a
plain <code>git push</code>, and automatically pulls from the <code>devel</code> branch on
the remote fork when we do a plain <code>git pull</code>.</p></li>
</ul>


<p>Note that with this setup you automatically get the feature that a
<code>git push</code> will push up all changes to all branches, including the
<code>master</code> branch. (That&#8217;s because the default refspec for remotes is
<code>refs/heads/*:refs/heads/*</code>.) So you can pull changes from <code>origin</code>
directly to your local copy, with the assurance that those changes
will be automatically migrated to your remote fork repository when you
push.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing PHP, Apache, MySQL, and Ruby on Mac OS 10.5 Leopard]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/126-installing-php-apache-mysql-and-ruby-mac-os-105-leopard"/>
    <updated>2008-11-04T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/installing-php-apache-mysql-and-ruby-on-mac-os-10-5-leopard</id>
    <content type="html"><![CDATA[<p>If you want to get up and running quickly using Drupal on Mac OS 10.5
your best bet is to use MAMP,
<a href="http://www.sysarchitects.com/node/58">as John VanDyk suggests in his comments</a>. There
are MAMP setup instructions
<a href="http://drupal.org/node/66187">on Drupal.org</a>.</p>

<p>But I decided to try moving away from MAMP. One reason is that MAMP
doesn&#8217;t come with certain features &#8211; for example, I&#8217;m told that it&#8217;s
hard to get SSL working. Another is that the upgrade cycle for PHP and
MySQL is different from that of MAMP, and I sometimes want to be able
to roll my own upgrade on my own timeframe. In addition, I want to
play with Ruby technologies like <a href="http://www.merbivore.com/">Merb</a> and
<a href="http://rack.rubyforge.org/">Rack</a> and
<a href="http://code.macournoyer.com/thin/">Thin</a>, and I didn&#8217;t relish trying
to hack them into MAMP&#8217;s config files &#8211; though it would probably be
possible to do so, the Ruby docs and blogs tend to be aimed at people
who are working outside of MAMP.</p>

<p>So I&#8217;ve just gotten everything installed. Here&#8217;s a quick sketch of the
process:</p>

<ul>
<li><p>Follow
<a href="http://hivelogic.com/articles/2007/11/installing-mysql-on-mac-os-x">Dan Benjamin&#8217;s instructions for compiling MySQL</a>. This
will involve creating <code>/usr/local</code> and adding it to your path,
assuming you haven&#8217;t already done so.</p>

<p>I&#8217;m with <a href="http://www.sysarchitects.com/node/58">VanDyk</a>, who
suggests running <code>mysql_secure_installation</code> once you have MySQL
installed.</p></li>
<li><p>Follow
<a href="http://hivelogic.com/articles/2008/02/ruby-rails-leopard">Benjamin&#8217;s instructions</a>
for compiling your own Ruby and Rubygems. This is a more dubious
move, since Apple has provided preinstalled versions of Ruby and
Gems in Leopard, and they work pretty well. But I decided to install
my own version so that I can keep control over the upgrades.</p></li>
<li><p>I recommend avoiding the stock Apache. I spent a while trying to
compile a PHP that would work with it, and ran into
trouble. Instead, install <a href="http://www.macports.org/">MacPorts</a> and
use that to
<a href="http://seancoates.com/php-5-2-5-on-leopard">install Apache, then download and compile PHP</a>.</p></li>
</ul>


<p>Note that I installed MacPorts&#8217; Apache, then downloaded and built the
PHP source myself, using the following <code>./configure</code> options:</p>

<pre><code> ./configure --prefix=/usr/local/php \
--with-apxs2=/opt/local/apache2/bin/apxs \
--with-mysql=/usr/local/mysql \
--with-curl --with-pgsql=shared \
--with-pdo-pgsql=shared,/usr/local/pgsql \
--with-pdo-mysql=shared,/usr/local/mysql \
--with-mcrypt=shared,/opt/local \
--with-openssl=shared,/opt/local \
--with-pear \
--with-gd \
--with-jpeg-dir=/opt/local \
--with-png-dir=/opt/local \
--without-iconv 
</code></pre>

<p>I&#8217;m not sure there&#8217;s a good reason to do this instead of just using
MacPorts&#8217; PHP. For that matter, I&#8217;m not sure that using your own MySQL
is better than having MacPorts install MySQL, or using the binary
distribution from MySQL AG. There are lots of options. But these
options seemed to work for me.</p>

<p>Of course, you&#8217;ve also got to set up a <code>php.ini</code> and an <code>httpd.conf</code>
and get PHP and Apache pointing at them. And I&#8217;ve still got
<a href="http://2bits.com/articles/benchmarking-apc-vs-eaccelerator-using-drupal.html">eAccelerator</a>
and
<a href="http://debuggable.com/posts/setting-up-xdebug-on-mac-os-x-or-win32-linux:480f4dd6-0240-4a90-8fa1-4e41cbdd56cb">XDebug</a>
to install. It&#8217;s a bit of work. I&#8217;d advise anybody who wants to avoid
trouble to stick with the MAMP option.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Actuarial]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/125-actuarial"/>
    <updated>2008-10-24T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/actuarial</id>
    <content type="html"><![CDATA[<p>As usual, <a href="http://xkcd.com/493/">today&#8217;s XKCD</a> makes you think.</p>

<p><img src="http://imgs.xkcd.com/comics/actuarial.png" alt="XKCD cartoon: Actuarial" /></p>

<ul>
<li><a href="http://en.wikipedia.org/wiki/Life-Line">Life-Line</a>, the story of an inventor who learns how to predict the time of a person&#8217;s death to within a single hour, was the first story that Robert Heinlein ever sold, in 1939. As in all Heinlein stories, the great part of this story is the portrait of a character: The inventor, who successfully (and a bit annoyingly) remains calm and rational about the fact of death, including his own death, even as everyone around him is freaking out.</li>
</ul>


<p>Asimov treated the story of the soothsayer as a grand historical epic (<em>Foundation</em>); Clarke wrote stories full of spiritual awe (e.g. <em>The Nine Billion Names of God</em>, <em>2001</em>), but Heinlein boiled it all down to this one guy in a shabby office. He was the Raymond Chandler of science fiction &#8211; until the 1960s, at any rate.</p>

<ul>
<li>Kevin Kelly has a <a href="http://kk.org/ct2/2007/09/my-life-countdown-1.php">countdown clock of the days he has left to live</a>:</li>
</ul>


<blockquote><p>My friend Stewart Brand, who is now 69, has been arranging his life in blocks of 5 years. Five years is what he says any project worth doing will take. From moment of inception to the last good-riddance, a book, a campaign, a new job, a start-up will take 5 years to play through. So, he asks himself, how many 5 years do I have left? He can count them on one hand even if he is lucky. So this clarifies his choices. If he has less than 5 big things he can do, what will they be?</p></blockquote>

<p>I appear to have <a href="http://www.cdc.gov/nchs/fastats/lifexpec.htm">eight big things I can do</a> &#8211; forty years, 14691 days.</p>

<ul>
<li>I think that a timeline which plotted the lifetimes of famous people &#8211; including the expected lifetimes of people who are alive right now &#8211; would be a great tool. I&#8217;ve loved timelines ever since I thumbed through <a href="http://www.amazon.com/Timetables-History-Horizontal-Linkage-People/dp/067174271X">The Timetables of History</a> as a kid.</li>
</ul>


<p>You need to occasionally think on a timescale that is longer than a single human life. You need to accept that people&#8217;s lives have arcs, like stories. You need to remember that <a href="http://www.longnow.org/">the world will go on after you</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal's Data Structures and the Properties Pattern]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/124-drupals-data-structures-and-properties-pattern"/>
    <updated>2008-10-22T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/drupals-data-structures-and-the-properties-pattern</id>
    <content type="html"><![CDATA[<p>I might be crazy, but as I read <a href="http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html#Intro">Steve Yegge&#8217;s essay on the Properties Pattern</a> I felt as if I was being introduced to something I already knew. And that&#8217;s not just because the essay describes Javascript. I think that&#8217;s because Properties lists are the fundamental Drupal data structure.</p>

<p>This line stuck out:</p>

<blockquote><p>I&#8217;ve talked about the main problems imposed by the Properties pattern: performance, data integrity, and navigability/queryability. They&#8217;re all trade-offs; you&#8217;re sacrificing in these areas in order to achieve big wins in flexibility and open-ended future extensibility for users you may never meet.</p></blockquote>

<p>Yep, that sure sounds like Drupal&#8217;s <code>$node</code>, <code>$user</code>, and <code>$form</code> objects to me.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A Horse Designed By an Open-Source Committee]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/123-horse-designed-open-source-committee"/>
    <updated>2008-09-16T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/a-horse-designed-by-an-open-source-committee</id>
    <content type="html"><![CDATA[<p>I have only three things to say about the heroic efforts of <a href="http://www.markboultondesign.com/news/detail/initial_wordmark_designs/">Mark Boulton</a> to come up with a design for a Drupal wordmark that will satisfy the entire Drupal community.</p>

<p>First: Mark is a brave man.</p>

<p>Second: I hereby officially delegate my opinion on the Drupal wordmark to Mark, Dries Buytaert, Barry Jaspan, and Angie Byron. If they like it, I like it, by definition. My desire to further influence the decision is more than trumped by my belief that such artistic decisions can&#8217;t be made by a giant, public committee.</p>

<p>Finally: Voting. Draw up three strong contenders, then let the community respond to a questionnaire. Don&#8217;t request <em>too</em> much free-form feedback in open forums during your design process. You will go stark raving mad.</p>

<p>The firm that recently redesigned my <a href="http://cwru.edu/">alma mater&#8217;s logo</a> did a great job with this: The first I heard of the project was when I received an email link to an online questionnaire. The questionnaire took ten or twenty minutes to complete, featured three variations of the logo, and asked all sorts of fuzzy questions &#8211; I can&#8217;t remember any of them, but they were something like &#8220;does this logo express the intellectual qualities you associate with the university.&#8221; Or whatever. In retrospect, it didn&#8217;t really matter what the questions were &#8211; the important thing was that they asked a sufficient number of important-sounding questions to convince me that I was participating in a <em>thorough</em>, <em>serious</em> decision-making process.</p>

<p>Then, a few months later, the university announced the winner, and, lo! I was happy. Because, hey, the new logo looks pretty good! And because I had been asked.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Javascript: Packing, Unpacking, and Beautifying]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/122-javascript-packing-unpacking-and-beautifying"/>
    <updated>2008-06-18T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/javascript-packing-unpacking-and-beautifying</id>
    <content type="html"><![CDATA[<p>A lot of the Javascript on the web ships in compressed form. This is particularly irritating if you discover that, say, Drupal 5&#8217;s <a href="http://drupal.org/project/jstools" title="Drupal: Javascript Tools">jstools</a> module has bugs that you&#8217;d like to fix, but the module ships with nothing but compressed versions of the Javascript code. (<em>What were they thinking?</em>)</p>

<p>A common method of packing Javascript is <a href="http://dean.edwards.name/packer/" title="the packer tool">Dean Edwards&#8217; packer algorithm</a>, which has a convenient online version. You can recognize code that&#8217;s been through the packer by looking for the cute function signature at the beginning:</p>

<pre><code>eval(function(p,a,c,k,e,r){...
</code></pre>

<p>It turns out that you can unpack code like this using Dean Edwards&#8217; <a href="http://dean.edwards.name/packer/">online tool</a>. This isn&#8217;t immediately apparent, because the tool doesn&#8217;t enable this feature by default (presumably because it&#8217;s trying to pretend that packing is an effective form of code obfuscation). But if you run <a href="http://yaisb.blogspot.com/2006/10/defeating-dean-edwards-javascript.html">the handy &#8220;reEnable&#8221; bookmarklet</a> the packer page becomes an &#8220;unpacker&#8221; page.</p>

<p>Once your function is unpacked you are only halfway home, because it will look like this example (from the <a href="http://stilbuero.de/jquery/history/index.html">jQuery History/Remote plugin</a> included with Drupal jstools):</p>

<pre><code>(function($){$.ajaxHistory=new function(){var c='historyReset';var k=location.hash;var e=null;var g;this.update=function(){};var h=function(){$('.remote-output').empty()};$(document).bind(c,h);if($.browser.msie){var f,initialized=false;$(function(){f=$('&lt;iframe style="display: none;"&gt;&lt;/iframe&gt;').appendTo(document.body).get(0);var ...
</code></pre>

<p>No line breaks, not so readable. So feed it through the <a href="http://elfz.laacz.lv/beautify/">online beautifier for Javascript</a> and you&#8217;ll get</p>

<pre><code>(function($) {
$.ajaxHistory = new
function() {
    var c = 'historyReset';
    var k = location.hash;
    var e = null;
    var g;
    this.update = function() {};
    var h = function() {
        $('.remote-output').empty()
    };
    $(document).bind(c, h);
    if ($.browser.msie) {
        var f, initialized = false;
        $(function() {
           ...
</code></pre>

<p>Much better.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The spammers have me outnumbered]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/121-the-spammers-have-me-outnumbered"/>
    <updated>2008-05-11T00:00:00-04:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/the-spammers-have-me-outnumbered</id>
    <content type="html"><![CDATA[<p>Whew, just cleaned out several hundred spam comments. Those bots are <em>prolific</em>. I guess it&#8217;s time to see what Dries Buytaert&#8217;s <a href="http://mollom.com/">anti-spam project</a> is all about&#8230;</p>

<p>In the meantime, lest you suspect that I&#8217;ve made a New Year&#8217;s resolution to stop writing, I should tell you that I&#8217;ve been spending too much of my writing time posting as <a href="http://news.ycombinator.com/user?id=mechanical_fish">mechanical_fish</a> on <a href="http://news.ycombinator.com">Hacker News</a>, a fairly awesome site full of people who know much more about software than I.</p>

<p>UPDATE: From my <a href="http://www.mollom.com">Mollom</a> page: &#8220;Mollom blocked 7360 spam attempts the past 10 days&#8221;. So far, so good. Mollom is hereby recommended.</p>

<p>UPDATE 2: That seems to have been a typo on the Mollom site: I think they meant <em>736</em> spam attempts over 10 days. Much more believeable. And still scary.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Drupal and PHPass, Macs and GPG]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/120-drupal-and-phpass-macs-and-gpg"/>
    <updated>2007-12-30T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/drupal-and-phpass-macs-and-gpg</id>
    <content type="html"><![CDATA[<p>As I was setting up a new Drupal site, I decided to try out the hilariously named <a href="http://drupal.org/project/phpass">phpass</a> module. (I cannot read that as &#8220;PH Pass&#8221; to save my life. It always comes out as&#8230; something else.)</p>

<p>The good news about this module is that it builds upon a PHP project called, um, <a href="http://www.openwall.com/phpass/">phpass</a> to add better password hashing to Drupal. The traditional way to handle passwords is to ask the user for one, compute a hash function on it, and store the hashed version. Unix systems use the Unix <code>crypt</code> utility to make the hash. Some newer and more naive systems, like core Drupal, use <code>MD5</code> hashing, presumably because it&#8217;s newer (and, therefore, niftier by definition) and also because it&#8217;s faster.</p>

<p>Unfortunately, it&#8217;s <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">a bad idea to use a fast hash function to hash your passwords</a>, because the speed makes the brute-force attacks that much more efficient. The Right Thing to do, if we trust the professionals at <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">Matasano Chargen</a>, is to use an adaptive hashing scheme like <code>bcrypt</code>, which is tricky and slow, and can be made slower and trickier as computers get faster and faster.</p>

<p>Unfortuately, neither my Mac nor my Ubuntu deployment box supports <code>CRYPT_BLOWFISH</code>, the encryption scheme that&#8217;s needed for all-out bcrypt support. So I am using the phpass fallback scheme for now. I could try to install <code>CRYPT_BLOWFISH</code> using the <a href="http://www.hardened-php.net/">Suhosin PHP hardening extension</a>, but would need to test this carefully to make sure I don&#8217;t break Drupal in the process.</p>

<p>In the meantime, I got halfway into the Suhosin downloading process before I decided to put it off until tomorrow. Part I of the process was to finally install <a href="http://www.gnupg.org/">Gnu Privacy Guard</a>, which I have always resisted because it seemed to be a usability horrorshow with few actual uses. I only know two people who really seem to use GPG-signed mail, let alone GPG-encrypted mail. But it turns out that there&#8217;s now a <a href="http://www.wasuvi.com/?page_id=2368">handy set of instructions for installing GPG on a Mac</a> using the <a href="http://macgpg.sourceforge.net/">MacGPG project</a>. And I might even get GPG working with Mail once <a href="http://www.sente.ch/software/GPGMail/English.lproj/GPGMail.html">the GPGMail utility</a> finishes being ported to Mac OS 10.5.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing a git server using gitosis]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/119-installing-git-server-using-gitosis"/>
    <updated>2007-12-27T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/installing-a-git-server-using-gitosis</id>
    <content type="html"><![CDATA[<p>I&#8217;m switching all my personal projects to <a href="http://git.or.cz/">git</a> from <a href="http://svnbook.red-bean.com/">Subversion</a>. After watching the <a href="http://peepcode.com/products/git">Peepcode git screencast</a>, Subversion feels oh-so-2002 and I can&#8217;t wait to bury it forever.</p>

<p>First we have to get git running on my Ubuntu server. I tried</p>

<pre><code>sudo apt-get install git-core #do not do this!
</code></pre>

<p>but that led to trouble down the line. Better to just fetch the source and build from that:</p>

<pre><code>sudo apt-get install libexpat1-dev zlibc curl gettext
cd ~/src
wget http://www.kernel.org/pub/software/scm/git/git-1.5.4.rc2.tar.gz
cd git-1.5.4.rc2
make prefix=/usr/local all
sudo make prefix=/usr/local install
</code></pre>

<p>Then, following <a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">the excellent instructions on scie.nti.st</a>, we grab the gitosis code:</p>

<pre><code>cd ~/src
git clone git://eagain.net/gitosis.git
</code></pre>

<p>Then:</p>

<pre><code>cd gitosis
sudo apt-get install python-setuptools
python setup.py install
</code></pre>

<p>Next we have to create a git user to own the repositories:</p>

<pre><code>sudo adduser \
    --system \
    --shell /bin/sh \
    --gecos 'git version control' \
    --group \
    --disabled-password \
    --home /home/git \
    git
</code></pre>

<p>We copy my public ssh key into <code>/tmp/id_rsa.pub</code>, then run</p>

<pre><code>sudo -H -u git gitosis-init &lt; /tmp/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update
</code></pre>

<p>And that&#8217;s the end of the server-side setup! On the local machine, we check out the files that are needed to control the server. First we have to account for the fact that I run SSH on a nonstandard port: edit <code>~/.ssh/config</code> and put this inside:</p>

<pre><code>Host www.example.com
    Port 32767
</code></pre>

<p>Then you can do:</p>

<pre><code>git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
cd gitosis-admin
</code></pre>

<p>This is the directory where you administer gitosis.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Social Networks: Stop Designing Out The Fun]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/118-social-networks-stop-designing-out-fun"/>
    <updated>2007-12-26T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/social-networks-stop-designing-out-the-fun</id>
    <content type="html"><![CDATA[<p>Today in the news we find that Google is <a href="http://slashdot.org/~Felipe+Hoffa/journal/191246">adding lame, privacy-defeating &#8220;social networking&#8221; features to popular apps without user consent</a>. This comes on the heels of <a href="http://www.zephoria.org/thoughts/archives/2007/12/11/facebooks_optou.html">Facebook&#8217;s Beacon trainwreck</a>, which was preceded by a <a href="http://www.danah.org/papers/FacebookAndPrivacy.html">similar Facebook privacy trainwreck</a>.
There are many lessons to learn from these incidents: That users really <em>do</em> care about privacy as soon as you start abusing their data; that web users <a href="http://icanhascheezburger.com/2007/09/09/do-not-want-7/">DO NOT WANT</a> to have the same persistent, verifiable &#8211; and easily traced &#8211; ID attached to all their online actions; that my innate distrust of Gmail is not as paranoid as I once thought.
But let&#8217;s focus on a fundamental problem: Social networking is one of the most significant developments on the web today, and our leading app designers apparently have <em>no clue</em> about how socializing works and why we humans work so hard at it.</p>

<h2>Stop Designing the Neutron Bomb</h2>

<blockquote><p> It would be trivial to design a better interface than DOOM if the goal was to kill the bad guys as quickly as possible: give me a 2D map of the area with icons for enemy troops and let me drop bombs on them by clicking the icons. Presto: game over in a few seconds and the good guys win every time. That&#8217;s the design you want if you are the Pentagon, but it makes for a boring game.
<span class="sig"><a http://www.useit.com/alertbox/981115.html">Jakob Nielsen</a></span></p></blockquote>

<p>Facebook and Google &#8211; and, one fears, a bunch of current and future startups &#8211; operate on the assumption that sharing links with your friends is a tedious chore. Telling your friends about your most recent purchases is a chore. Figuring out which addresses in your book correspond to your best friends is a chore. So they try to automate these chores away: In the spirit of Jakob Nielsen&#8217;s high-efficiency first-person shooter, they build one big flat list of all your friends and offer you an elegant one-button interface: SOCIALIZE.</p>

<p>Hello? <strong>People use social networks because they are fun.</strong> Tweaking your Friend list is fun. Personally choosing the links to be sent to your friends is fun. Choosing when and how to poke people is fun. Flirting is fun! Deciding which of your friends should be introduced to each other is a source of social anxiety, but it is also fun.</p>

<p>Feel free to automate the cleaning of my laundry and the removal of my trash. I don&#8217;t really enjoy those things. But <strong>stop thinking of my social life and my public persona as tasks that I want to outsource, instead of as hobbies that define my personality.</strong></p>

<h2>Fun is Deadly Serious</h2>

<p>Perhaps I should stop writing right now. Once you&#8217;ve told people to stop designing out the fun, is there any more to say?</p>

<p>Maybe. <strong>The problem with fun is that many people don&#8217;t respect it.</strong> They think it&#8217;s frivolous, and trivial, and arbitrary. Because people share links &#8220;just for fun&#8221;, designers feel free to quietly, unilaterally change the way that shared links work. &#8220;Why are you taking Google Reader so seriously?&#8221;, they say. &#8220;Lighten up and share your data!&#8221;</p>

<p>These designers are insane. Fun is serious business. Just look at how animals have fun: Cats think that stalking fast-moving objects is fun, dogs think that herding and chasing are fun, gerbils think that burrowing and chewing are fun, and parrots think that &#8211; believe it or not &#8211; social networking is fun. For animals, <strong>fun is associated with the practice of vital survival skills.</strong></p>

<p>Humans work the same way. Reproduction? Fun. Looking at babies, especially your own? Fun. Hunting, watching birds, playing Half-Life? It&#8217;s fun, and it&#8217;s also a way to practice the stalking skills that you&#8217;d use for hunting game or fighting wars. Chess? Strategic training for warfare. (Just ask any well-educated kid from the Middle Ages.) Gardening? Practice for farming. Stamp collecting and Pokemon? You&#8217;re practicing taxonomy, exercising the parts of  your brain that evolved to remember which things you can eat, which things can eat <em>you</em>, which are poisonous, which are likely to be found under trees in July.</p>

<p><strong>Social networking is one of the most fun things of all, because it&#8217;s a survival skill that humans are heavily invested in.</strong> We&#8217;re <em>designed</em> for it. Human language itself is a social networking tool.</p>

<p>Some fun activities are no longer vital for survival: We&#8217;ve invested lots of time, energy, and money to ensure that I can eat without knowing how to tell one plant from another, defend myself without knowing how to shoot, and stay warm without flint and tinder. Social networking is not in this category. <strong>Social networking may be more important now than ever before in human history.</strong> Many historical humans had very little interaction with strangers. They didn&#8217;t marry anyone that their parents didn&#8217;t already know, and their friends lived within a ten-minute walk. (Of course, even <em>these</em> people had a social network that was too complicated for a computer to manage.)</p>

<p><strong>Modern social networks are very complicated.</strong> We travel a lot. We move through many different social groups during our lives. We have multiple overlapping circles of friends. We have technical friends, gaming friends, friends from work, friends from school, friendly customers, friendly teachers, friends we aspire to marry, friends with benefits, platonic friends. We have friends who we met once at a conference in 2006, friends who we went to college with but don&#8217;t see more than once every three years, and friends who we used to see every day but who just moved to Idaho. We have relatives, who may or may not be our friends. We have the relatives of friends, and the friends of relatives. We have fundamentalist Christian friends and polyamorous anarchist friends.</p>

<p>Incidentally, we also have enemies.</p>

<p><strong>Mismanaging your social interactions can have terrible consequences.</strong> It can cost you your reputation, your spouse, your children, your inheritance, your job, your career, your freedom, and your sanity. If you make the wrong friend, and that friend turns into a stalker, it can cost you your life.</p>

<p>So:</p>

<ul>
<li><p><strong>Personally micromanaging your social network is fun.</strong></p></li>
<li><p><strong>The reason it&#8217;s fun is that humans are designed for it.</strong> This, in turn, is because <strong>it&#8217;s a vitally important personal skill that determines your income and your happiness.</strong> This is especially true in the 21st century.</p></li>
<li><p><strong>Nobody is going to entrust their social network to a computer, not ever.</strong> Computers have not spent millions of years evolving their social skills. Computers are stupid. You have not solved the strong AI problem. If, by chance, you <em>do</em> invent a computer that is smarter than a human, nobody will trust that, either.</p></li>
<li><p><strong>Build tools that empower people to make better decisions, not tools that try to make decisions for them.</strong></p></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Ruby vs. PHP BDD Beauty Contest: no contest]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/117-ruby-vs-php-bdd-beauty-contest-no-contest"/>
    <updated>2007-12-21T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/the-ruby-vs-php-bdd-beauty-contest-no-contest</id>
    <content type="html"><![CDATA[<p>For the last week I&#8217;ve been writing a Drupal utility in Ruby. This is
a dubious decision, because most Drupal developers would prefer a tool
written in Drupal&#8217;s native PHP. It&#8217;s less hassle to install, and less
hassle to modify.</p>

<p>But I went with Ruby anyway, at least for version 0.1 &#8211; partly to
keep myself in practice, and partly as an excuse to work out with
<a href="http://rspec.info">RSpec, the Behavior Driven Development (BDD) framework for Ruby</a>.</p>

<p>With BDD, before you write your code, you write a spec. Here&#8217;s a
section of one of my specs &#8211; it describes an Environment object that
can parse a Unix command line and pick out the arguments and the
option flags:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">Environment</span><span class="p">,</span> <span class="s2">&quot;created from the command line&quot;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">before</span><span class="p">(</span><span class="ss">:each</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="vi">@env</span> <span class="o">=</span> <span class="no">Environment</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should set the usage message attribute&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="sx">%w(foo bar baz quux)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">usage_message</span><span class="o">.</span><span class="n">should_not</span> <span class="n">be_empty</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should recognize arguments that are not options&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="sx">%w(foo bar baz quux)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">should</span> <span class="n">have</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">args</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should throw an exception if an illegal option is provided&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="sx">%w(foo -z bar)</span>
</span><span class='line'>    <span class="nb">lambda</span> <span class="p">{</span> <span class="vi">@env</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">}</span><span class="o">.</span><span class="n">should</span> <span class="n">raise_error</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should allow the cvs path to be set&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">test_path</span> <span class="o">=</span> <span class="s1">&#39;/bin/cvs&#39;</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;--cvspath&#39;</span><span class="p">,</span> <span class="n">test_path</span><span class="o">]</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">get_option</span><span class="p">(</span><span class="ss">:cvs_command_path</span><span class="p">)</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">test_path</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should be invalid if cvs path does not exist&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;--cvspath&#39;</span><span class="p">,</span> <span class="s1">&#39;nonexistent&#39;</span><span class="o">]</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">should_not</span> <span class="n">be_valid</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">errors</span><span class="o">.</span><span class="n">should</span> <span class="n">have_at_least</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">error</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">errors_on</span><span class="p">(</span><span class="ss">:cvs_path</span><span class="p">)</span><span class="o">.</span><span class="n">should</span> <span class="n">have</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">error</span>
</span><span class='line'>    <span class="vi">@env</span><span class="o">.</span><span class="n">errors_on</span><span class="p">(</span><span class="ss">:cvs_path</span><span class="p">)</span><span class="o">.</span><span class="n">should</span> <span class="n">match</span><span class="p">(</span><span class="sr">/not exist/</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>The idea is that you write a sentence about what the code should do,
<em>along</em> with an executable description that demonstrates the
sentence. Then you write the code itself until the description runs
without failing.</p>

<p>Advocates of Test-Driven Development (TDD) will recognize this as
<em>nearly</em> the same thing. But it does have a few advantages:</p>

<ul>
<li><p>BDD avoids using the word &#8220;test&#8221;, which carries uncomfortable
connotations like &#8220;broken&#8221; and &#8220;buggy&#8221; and &#8220;ISO 9002&#8221; and &#8220;let&#8217;s do
that last, after the documentation&#8221;. BDD uses words like &#8220;describe&#8221;
and &#8220;should&#8221; to guide you into a proper, positive frame of mind.</p></li>
<li><p>BDD in Ruby uses nifty readable syntax. The syntax is astoundingly
addictive. Why read this:</p></li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>assert(wallet.dollars >= 2e6)</span></code></pre></td></tr></table></div></figure>


<p>when you can read this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">wallet</span><span class="o">.</span><span class="n">should</span> <span class="n">have_at_least</span><span class="p">(</span><span class="mi">2</span><span class="n">e6</span><span class="p">)</span><span class="o">.</span><span class="n">dollars</span>
</span></code></pre></td></tr></table></div></figure>


<p>or this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">bank</span> <span class="o">=</span> <span class="n">mock</span><span class="p">(</span><span class="s1">&#39;a bank with 2 million dollars&#39;</span><span class="p">)</span>
</span><span class='line'><span class="n">bank</span><span class="o">.</span><span class="n">should_receive</span><span class="p">(</span><span class="ss">:withdraw</span><span class="p">)</span><span class="o">.</span><span class="n">at_least</span><span class="p">(</span><span class="ss">:twice</span><span class="p">)</span><span class="o">.</span><span class="n">with</span><span class="p">(</span><span class="mi">1</span><span class="n">e6</span><span class="p">)</span><span class="o">.</span><span class="n">and_return</span><span class="p">(</span><span class="ss">:ok</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Oh, sweet
<a href="http://rspec.info/documentation/mocks/index.html">RSpec mock syntax</a>. How
I wish you had an equivalent in other important languages, like PHP!</p>

<p>Well, the good news is that PHP has testing advocates of its own. Mock
objects are
<a href="http://blog.astrumfutura.com/archives/317-Mocks,-Stubs,-And-SimpleTest-Wins.html">apparently well covered by Simpletest</a>,
which just happens to be Drupal&#8217;s preferred PHP testing library. And
the syntax looks familiar &#8211; it&#8217;s quite nice, despite some additional
clutter:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="nv">$observer</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getStub</span><span class="p">(</span><span class="s1">&#39;Observer&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;update&#39;</span><span class="p">));</span>
</span><span class='line'><span class="nv">$observer</span><span class="o">-&gt;</span><span class="na">shouldReceive</span><span class="p">(</span><span class="s1">&#39;update&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">once</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">with</span><span class="p">(</span><span class="s1">&#39;something&#39;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>Meanwhile, at least one person,
<a href="http://blog.astrumfutura.com/index.php?/plugin/tag/phpspec">Pádraic Brady</a>,
is working on a BDD framework for PHP: the
<a href="http://dev.phpspec.org/">PHPSpec</a> project. Unfortunately, the results
are&#8230; less nice:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="k">class</span> <span class="nc">DescribeNewBowlingGame</span> <span class="k">extends</span> <span class="nx">PHPSpec_Context</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">private</span> <span class="nv">$_bowling</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">public</span> <span class="k">function</span> <span class="nf">before</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_bowling</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Bowling</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">public</span> <span class="k">function</span> <span class="nf">itShouldScore0ForGutterGame</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="nv">$i</span><span class="o">&lt;=</span><span class="mi">20</span><span class="p">;</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_bowling</span><span class="o">-&gt;</span><span class="na">hit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">spec</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_bowling</span><span class="o">-&gt;</span><span class="na">score</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">should</span><span class="o">-&gt;</span><span class="na">equal</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Compare this to the RSpec code which inspired it:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">describe</span> <span class="no">Bowling</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">before</span><span class="p">(</span><span class="ss">:each</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="vi">@bowling</span> <span class="o">=</span> <span class="no">Bowling</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">it</span> <span class="s2">&quot;should score 0 for gutter game&quot;</span> <span class="k">do</span>
</span><span class='line'>    <span class="mi">20</span><span class="o">.</span><span class="n">times</span> <span class="p">{</span> <span class="vi">@bowling</span><span class="o">.</span><span class="n">hit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>    <span class="vi">@bowling</span><span class="o">.</span><span class="n">score</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="mi">0</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>It&#8217;s enough to make you cry.</p>

<p>The thing is, I&#8217;m completely convinced that Pádraic is doing the best
he can. I am no expert on PHP syntax, having learned it by osmosis
from Drupal code, and maybe after I finish
<a href="http://www.oreilly.com/catalog/progphp/">Programming PHP</a> I&#8217;ll know
better, but PHPSpec seems to be fundamentally stymied by the ugly
syntax of PHP. Specifically:</p>

<h2>What&#8217;s <code>:this</code>?</h2>

<p>Why, it&#8217;s PHP&#8217;s inability to understand object scoping! You would
think that declaring <code>_bowling</code> to be <code>private</code> to a class would be
enough of a clue, but it looks like you&#8217;re still obligated to refer to
it as <code>$this-&gt;_bowling</code>.</p>

<h2>Little things matter</h2>

<p>Ruby uses <code>object.method</code> syntax. PHP uses <code>$object-&gt;method</code>. They
look so comparable! That is, until you run into a chain like:</p>

<pre><code>$this-&gt;spec(foo)-&gt;should-&gt;equal
</code></pre>

<p>which is less readable than:</p>

<pre><code>this.spec(foo).should.equal
</code></pre>

<p>It&#8217;s all about the typography: the whitespace above the tiny dot
separates the words better and makes their shape easier to recognize.</p>

<h2>It&#8217;s good to be an Object</h2>

<p> In Ruby, everything is an object, every object is a child of
 <code>Object</code>, and <code>Objects</code> can be monkey-patched. So you can magically
 attach new methods like <code>should</code> and <code>should_not</code> to the <code>Object</code>
 class and then write things like:</p>

<pre><code>@bowling.score.should be_big
</code></pre>

<p>Here we&#8217;re calling the <code>should</code> method on <code>@bowling.score</code>, which is
probably an <code>Integer</code>, although it might be a <code>BowlingScore</code> object,
or a <code>Real</code>, or even <code>Imaginary</code> if we&#8217;re bowling on the planet
Vulcan. Ruby does not care. Ruby can roll with those punches. Ruby
rocks.</p>

<p>Alas, PHP prosaically insists that you call the <code>should</code> method on
specific objects that can actually understand it. So we have to wrap
the subject of <code>should</code> in a <code>$this-&gt;spec()</code>, like this:</p>

<pre><code>$this-&gt;spec($this-&gt;_bowling-&gt;score)-&gt;should-&gt;equal(0);
</code></pre>

<p>This line makes my brain hurt because it&#8217;s got two instances of
<code>$this</code>, both of which are 100% free of significant meaning. The thing
which they refer to &#8211; the enclosing <code>PHPSpec_Context</code> object &#8211; is an
irrelevant piece of scaffolding that I <em>do not want</em> to have to think
about.</p>

<p>The PHP version of the Bowling spec reads like this:</p>

<blockquote><p>This paragraph is a spec, and it-describes-Bowling. Consider the
  game of bowling that we will discuss in this paragraph. The
  score-should-be-zero-for-a-gutter-game. That is, if a &#8216;hit&#8217; that
  scores zero pins happens twenty times, this sentence of this
  paragraph will be true: this paragraph&#8217;s game&#8217;s score should equal
  zero.</p></blockquote>

<p>Here&#8217;s the RSpec version:</p>

<blockquote><p>Let&#8217;s talk about Bowling. Consider a game of bowling. The score
  should be zero for a gutter game. That is, if a &#8216;hit&#8217; that scores
  zero pins happens twenty times, the game&#8217;s score should equal zero.</p></blockquote>

<p>(Note: Fun as it would be to write down the prose equivalent of a
<code>for</code> loop &#8211; it would look like a number-theory textbook &#8211; I decided
not to blame PHP for that. I&#8217;m pretty sure the language <em>does</em> have
iterators&#8230;)</p>

<p>PHP&#8217;s syntactic cyanide is so bitter that I wonder: is PHPSpec worth
it? If the language itself insists on mangling my syntax, why should I
bother trying to apply the subtle shading that is BDD? It just gets
lost in the noise. Here&#8217;s a comparison from
<a href="http://dev.phpspec.org/manual/source.code.examples.as.documentation.html">the PHPSpec docs themselves</a>:
the TDD version (PHPUnit):</p>

<pre><code>$logger = new Logger;
$this-&gt;assertTrue($logger-&gt;hasFile());
</code></pre>

<p>and the BDD version (PHPSpec):</p>

<pre><code>$logger = new Logger;
$this-&gt;spec($logger)-&gt;should-&gt;haveFile();
</code></pre>

<p>Frankly, I think the first version is clearer: it&#8217;s shorter, the call
to <code>hasFile()</code> is in its natural location, and since neither version
is readable, why not pick the one that&#8217;s closest to idiomatic PHP?
Others seem to agree with me; just look at
<a href="http://blog.astrumfutura.com/archives/306-Any-Behaviour-Driven-Development-Tools-for-PHP.html">this comment thread</a>.</p>

<p>Pádraic has his work cut out for him, battling heroically against the
fundamental structures of the PHP universe. I really feel for the guy,
and would sincerely like to help. My personal inclination is to build
a macro processor that allows you to write something sensible and have
it JIT-compiled into PHP. But maybe I can get used to PHPSpec if I
make some subtle vocabulary changes:</p>

<pre><code>$this-&gt;thing($this-&gt;_bowling-&gt;score)-&gt;thing-&gt;should-&gt;equal(0)
</code></pre>

<p>This thing, this PHP syntax thing&#8230; we will learn to cope with it.</p>

<hr />

<h3>Update: Jan 6, 2012</h3>

<p><a href="http://en.gravatar.com/dbernar1">Dan Bernardic</a> writes:</p>

<blockquote><p>&#8220;All PHPspec is missing is a DSL on top of what he has. Except that
  I expect it would be a better idea to implement a way for ruby to
  run PHP code and inspect PHP memory state, just cause rspec for ruby
  already exists&#8230;&#8221;</p></blockquote>

<p>and includes a <a href="https://gist.github.com/1569735">proof-of-concept Gist</a>.</p>

<p>I&#8217;ve toyed with this idea myself - which is to say, I&#8217;ve sat in an
armchair and imagined it, not actually hacked on it - but there are
drawbacks. The biggest is that it&#8217;s not enough to test one&#8217;s PHP code
in isolation; one should test it in an environment that&#8217;s as close as
possible to the production environment. Unless you plan to run your
production PHP code inside a Ruby wrapper - and, believe me, you don&#8217;t
- a Ruby-with-embedded-PHP testing framework is going to trade
reliability for syntax, and that&#8217;s not a good trade unless the syntax
is truly <a href="http://en.wikipedia.org/wiki/Brainfuck">brainf**ked</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby, Rspec, and Autotest bug on Mac OS 10.5 Leopard]]></title>
    <link href="http://www.mechanicalrobotfish.com/posts/116-ruby-rspec-and-autotest-bug-mac-os-105-leopard"/>
    <updated>2007-12-13T00:00:00-05:00</updated>
    <id>http://www.mechanicalrobotfish.com/posts/ruby-rspec-and-autotest-bug-on-mac-os-10-5-leopard</id>
    <content type="html"><![CDATA[<p>Now <a href="http://ruby-on-rails.mynn.com/story/249018/secret-incantations">this</a> is an obscure bug: Autotest on Leopard will break when used with projects containing Rspec specs, because it can&#8217;t find the &#8220;spec&#8221; command in the right place. It doesn&#8217;t look in <code>/usr/bin/spec</code>, where Leopard places it.</p>

<p>I tried the tricky answer before I gave up and adopted the simple answer:</p>

<pre><code>$ sudo ln -s /usr/bin/spec /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/spec
</code></pre>
]]></content>
  </entry>
  
</feed>

