<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title type="text">Effectif Development</title>
  <generator uri="http://effectif.com/nesta">Nesta</generator>
  <id>tag:effectif.com,2009:/</id>
  
  <link href="http://effectif.com" rel="alternate" />
  <subtitle type="text">Graham Ashton on Ruby, Python, JavaScript and Web Development.</subtitle>
  <author>
    <name>Graham Ashton</name>
    <uri>http://effectif.com</uri>
    <email>graham@effectif.com</email>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/effectif-development" /><feedburner:info uri="effectif-development" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title>Fixing the Xcode Project Templates</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/UjiFHtIlgg8/xcode-template-problems" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2010-01-02:/articles/xcode-template-problems</id>
    <content type="html">&lt;p&gt;I recently upgraded my copy of Xcode and installed the iPhone SDK. A short while later, while following an example in the Pragmatic Programmer&amp;#8217;s &lt;a href='http://www.pragprog.com/titles/dscpq/cocoa-programming' title='The Pragmatic Bookshelf | Cocoa Programming'&gt;Cocoa Programming&lt;/a&gt; book, I found that my copy of Xcode wasn&amp;#8217;t creating some key files.&lt;/p&gt;

&lt;p&gt;Specifically, when I created a new project from the &lt;code&gt;Cocoa Application&lt;/code&gt; template, the app delegate files (&lt;code&gt;ProjectNameAppDelegate.*&lt;/code&gt;) weren&amp;#8217;t being created. Yet there they were in the book, which has been freshly updated for Snow Leopard and the latest version of Xcode (both of which I have). Hmmm.&lt;/p&gt;

&lt;p&gt;I did some searching online, and found that I&amp;#8217;m not alone. Others on the &lt;a href='http://forums.pragprog.com/forums/86/topics/3397' title='Pragmatic Forums | Chapter 4 - Requires Snow Leopard?'&gt;Pragmatic forums&lt;/a&gt; have had the same trouble, and Martin Wood has written a &lt;a href='http://martinwood.org/2009/11/17/xcode-project-template-bug-on-snow-leopard/' title='XCode Project Template bug on Snow Leopard'&gt;useful post&lt;/a&gt; explaining that the Xcode project template files were messed up. Having read Martin&amp;#8217;s post I was curious about what had gone wrong, and dug a little deeper.&lt;/p&gt;

&lt;p&gt;Xcode stores template files for creating new projects in this folder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/Developer/Library/Xcode/Project Templates&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Cocoa Application&lt;/code&gt; template (the one that I found to be dodgy) belongs here:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/Developer/Library/Xcode/Project Templates/Application/Cocoa Application&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Inside it you should find the following files and directories:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;English.lproj/
main.m
___PROJECTNAMEASIDENTIFIER___-Info.plist
___PROJECTNAMEASIDENTIFIER___AppDelegate.h
___PROJECTNAMEASIDENTIFIER___AppDelegate.m
___PROJECTNAMEASIDENTIFIER____Prefix.pch
___PROJECTNAME___.xcodeproj/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I found something rather different; I had several template directories inside my &lt;code&gt;Cocoa Application&lt;/code&gt; folder, that should have been in the parent directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Cocoa Application/Cocoa Application
Cocoa Application/Cocoa Document-based Application
Cocoa Application/Core Data Application
Cocoa Application/Core Data Application with Spotlight Importer
Cocoa Application/Core Data Document-based Application
Cocoa Application/Core Data Document-based Application with Spotlight Importer&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Interestingly, all these template folders (except for &lt;code&gt;Core Data Application with Spotlight Importer&lt;/code&gt;) already existed inside &lt;code&gt;Project Templates/Application&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The folders in &lt;code&gt;Project Templates/Application&lt;/code&gt; dated from 2007 and used the outdated binary Nib files (with a &lt;code&gt;.nib&lt;/code&gt; file extension). The templates in inside &lt;code&gt;Cocoa Application&lt;/code&gt; dated from May 2009 and used the more up to date &lt;code&gt;.xib&lt;/code&gt; file format. It seems fairly clear that those are the ones we should be using.&lt;/p&gt;

&lt;p&gt;I ran the following commands to move the older copies out of the way:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mkdir ~/xcode-backup
$ cd /Developer/Library/Xcode/Project Templates/Application
$ for template in \
&amp;gt;   $(find Cocoa\ Application -type d -mindepth 1 -maxdepth 1 | egrep &amp;#39;(Core |Cocoa D)&amp;#39;); do
&amp;gt;     old=&amp;quot;$(basename $template)&amp;quot;
&amp;gt;     [ -e $old ] &amp;amp;&amp;amp; mv &amp;quot;$old&amp;quot; ~/xcode-backup
&amp;gt;     mv &amp;quot;$template&amp;quot; .
&amp;gt;   done
$ mv &amp;quot;Cocoa Application&amp;quot; ~/xcode-backup
$ mv &amp;quot;~/xcode-backup/Cocoa Application/Cocoa Application&amp;quot; .&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I restarted Xcode and made myself a new project and found that the delegate files were present and correct. I also noticed that the &lt;code&gt;Cocoa Application&lt;/code&gt; project (which had previously had the standard blue project icon) now stood out with a separate icon:&lt;/p&gt;
&lt;img src='/attachments/new-xcode-project.png' /&gt;</content>
    <published>2010-01-02T00:00:00+00:00</published>
  <feedburner:origLink>http://effectif.com/articles/xcode-template-problems</feedburner:origLink></entry>
  <entry>
    <title>Ruby Manor</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/Vuz8SxPPl5g/manor" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-12-12:/ruby/manor</id>
    <content type="html">&lt;p&gt;Ruby Manor is one of those alternative conferences. It&amp;#8217;s not run for a profit, and costs just £8 for a ticket (you pay just enough to cover the cost of the room and equipment). You even get a free beer afterwards in the local boozer (and it&amp;#8217;s at least £3 a pint in London these days). Due to the unique way that Ruby Manor is funded (actually, that&amp;#8217;s nothing to do with it) you can even &lt;a href='http://www.flickr.com/photos/h-lame/4181396105/'&gt;check the bar bill&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There were some great talks again this year, and it&amp;#8217;s far and away my favourite date on the conference calendar. Congratulations to &lt;a href='http://twitter.com/hlame'&gt;Murray&lt;/a&gt;, &lt;a href='http://twitter.com/lazyatom'&gt;James&lt;/a&gt; and &lt;a href='http://twitter.com/kalv'&gt;Kalv&lt;/a&gt; on organising such a runaway success.&lt;/p&gt;

&lt;p&gt;I spent most of the day typing frantically, but I didn&amp;#8217;t manage to capture everything. The photos that are littered through the following articles are all thanks to &lt;a href='http://twitter.com/glenngillen'&gt;@glenngillen&lt;/a&gt; from &lt;a href='http://rubypond.com/' title='Ruby on Rails Developers, Online Marketing, Social Networking | Ruby Pond'&gt;Rubypond&lt;/a&gt;, who was sat next to me snapping away for most of the day.&lt;/p&gt;

&lt;p&gt;So, in alphabetical order, here are my notes from &lt;strong&gt;every talk&lt;/strong&gt; at Ruby Manor&amp;#160;2 (also known as &amp;#8220;Ruby Manor Harder&amp;#8221;). Each talk gets a page of it&amp;#8217;s own this year, mainly to help you see the wood for the trees. You can also find a couple of articles covering Ruby Manor 2008 at the bottom of the list.&lt;/p&gt;

&lt;p&gt;P.S. If you&amp;#8217;re one of the speakers and spot a mistake, or want me to change anything, just &lt;a href='http://twitter.com/grahamashton'&gt;get in touch&lt;/a&gt; on Twitter and I&amp;#8217;ll sort it out pronto.&lt;/p&gt;</content>
    <published>2009-12-12T00:00:00+00:00</published>
    <category term="ruby" />
  <feedburner:origLink>http://effectif.com/ruby/manor</feedburner:origLink></entry>
  <entry>
    <title>3 Unix commands for finding performance problems</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/6ajuDqWGRww/finding-performance-problems" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-11-20:/articles/finding-performance-problems</id>
    <content type="html">&lt;p&gt;A user recently reported a performance problem on one of our Rails apps. I pulled up New Relic&amp;#8217;s performance graphs and checked what was happening around the time that we received the email. Sure enough there was a massive spike in the time taken to serve a request.&lt;/p&gt;

&lt;p&gt;We gave the problem a couple of minutes thought and came up with a hypothesis; we&amp;#8217;ve got one long running request in this app that really ought to be run in a background job. Could that request be responsible? Due to the way we&amp;#8217;ve configured our web servers, there would need to be at least 8 concurrent requests for that page.&lt;/p&gt;

&lt;p&gt;So how many concurrent requests were there? Each one creates a line in the Rails log file like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Processing MyController#create (for 172.16.5.45 at 2009-11-16 04:03:44) [POST]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The key thing here is that the time is in the log file, so we can get a rough feel for usage by counting how many requests &lt;code&gt;MyController#create&lt;/code&gt; receives in a minute.&lt;/p&gt;

&lt;p&gt;You could write a script to work that out for you. It probably wouldn&amp;#8217;t take more than 10 minutes, but it feels like a bit of a chore and &amp;#8211; frankly &amp;#8211; I&amp;#8217;m too lazy to bother.&lt;/p&gt;

&lt;p&gt;Alternatively, you could spend 10 seconds cooking up a Unix command line like this one:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | \
    cut -d &amp;#39; &amp;#39; -f 7 | cut -d : -f 1,2 | \
    sort | uniq -c | sort -nr | head -n 5
  18 18:21
  16 17:04
  15 18:31
  14 22:47
  14 20:42&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Neat. Looks really clever, but it&amp;#8217;s actually really easy and anybody can use it.&lt;/p&gt;

&lt;p&gt;The output tell us how many times &lt;code&gt;MyController#create&lt;/code&gt; was called per minute, for the five busiest minutes in the log file. To give you an idea of how to read it, we peaked at 18 requests per minute at 18:21. Given that we already know that we can only support 8 of these requests at once there&amp;#8217;s a very good chance we&amp;#8217;ve found our performance problem. It&amp;#8217;s probably time to re-implement this rewrite the relevant code as a background job.&lt;/p&gt;

&lt;p&gt;To nobody&amp;#8217;s surprise, our customer feedback dates from 18:30, which is also when the New Relic graphs indicated that we had a performance problem (requests were backing up in Mongrel&amp;#8217;s queue while the Mongrel servers were tied up by our long running &lt;code&gt;create&lt;/code&gt; action).&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s break that command down a bit while I show you how I built it.&lt;/p&gt;

&lt;h2 id='step_1_finding_the_time_of_each_request'&gt;Step 1: Finding the time of each request&lt;/h2&gt;

&lt;p&gt;Step 1 is to have a quick look at some example log messages to see what information we&amp;#8217;ve got to play with. All we really need is the time of each request, and lo and behold, there it is&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | head -n 1
Processing MyController#create (for 172.16.5.45 at 2009-11-16 04:03:44) [POST]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;zgrep&lt;/code&gt; is just like &lt;code&gt;grep&lt;/code&gt;, but it can read compressed logs.&lt;/p&gt;

&lt;p&gt;The time the request was made is the seventh field in the log message, if you split the line on white space. The &lt;code&gt;cut&lt;/code&gt; command can do that for us, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | \
    cut -d &amp;#39; &amp;#39; -f 7 | head -n 3
  04:03:44)
  04:03:48)
  04:04:51)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; switch specifies the delimiter (a space) and &lt;code&gt;-f&lt;/code&gt; tells &lt;code&gt;cut&lt;/code&gt; which fields we want. We need to clean &amp;#8220;04:03:44)&amp;#8221; up a bit. As we&amp;#8217;re counting the number of requests per minute we can throw away the seconds. We can do that with &lt;code&gt;cut&lt;/code&gt; again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | \
    cut -d &amp;#39; &amp;#39; -f 7 | cut -d : -f 1,2 | head -n 3
  04:03
  04:03
  04:04&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='step_2_counting_requests_per_minute'&gt;Step 2: Counting requests per minute&lt;/h2&gt;

&lt;p&gt;We can count each minute with the &lt;code&gt;uniq&lt;/code&gt; command. Normally &lt;code&gt;uniq&lt;/code&gt; will just remove all the duplicate lines from a sorted list, but with the &lt;code&gt;-c&lt;/code&gt; switch we can ask it to tell us how many times each line occurs.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | \
    cut -d &amp;#39; &amp;#39; -f 7 | cut -d : -f 1,2 | \
    sort | uniq -c | head -n 3
  2 04:03
  1 04:04
  3 04:06&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;uniq&lt;/code&gt; has added the count in front of the time. Now we&amp;#8217;re getting somewhere (though there&amp;#8217;s clearly not a lot going on at 4&amp;#160;o&amp;#8217;clock in the morning)!&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;uniq&lt;/code&gt; requires it&amp;#8217;s input to be sorted, so I&amp;#8217;ve piped the output of &lt;code&gt;cut&lt;/code&gt; through &lt;code&gt;sort&lt;/code&gt; first. I really didn&amp;#8217;t need to do that in this case as the lines in my web logs are already in chronological order, but it&amp;#8217;s a good habit to get into when using &lt;code&gt;uniq -c&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id='step_3_finding_the_hotspots'&gt;Step 3: Finding the hotspots&lt;/h2&gt;

&lt;p&gt;Okay, so how do we find out when things start to get busy? We can use &lt;code&gt;sort&lt;/code&gt; again, and ask it to list the rows in descending order of popularity. &lt;code&gt;sort -r&lt;/code&gt; will do that for us, but we also need to point out to &lt;code&gt;sort&lt;/code&gt; that it&amp;#8217;s sorting numbers (otherwise when sorting &amp;#8220;23&amp;#8221; and &amp;#8220;100&amp;#8221; it will just compare &amp;#8220;2&amp;#8221; to &amp;#8220;1&amp;#8221; and conclude that &amp;#8220;23&amp;#8221; is bigger). So that gives us &lt;code&gt;sort -nr&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ zgrep MyController#create production.log.1.gz | \
    cut -d &amp;#39; &amp;#39; -f 7 | cut -d : -f 1,2 | \
    sort | uniq -c | sort -nr | head -n 5
  18 18:21
  16 17:04
  15 18:31
  14 22:47
  14 20:42&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And there you have it &amp;#8211; it doesn&amp;#8217;t seem so clever now does it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Andrew McDonough got in touch on Twitter to show me &lt;a href='http://twitter.com/andrewmcdonough/status/6462006581'&gt;how he&amp;#8217;d do it&lt;/a&gt; with &lt;code&gt;awk&lt;/code&gt;. Nice.&lt;/p&gt;</content>
    <published>2009-11-20T00:00:00+00:00</published>
    <category term="ruby-on-rails" />
    <category term="system-administration" />
  <feedburner:origLink>http://effectif.com/articles/finding-performance-problems</feedburner:origLink></entry>
  <entry>
    <title>Tools of the trade</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/yPlqi7hCFX4/tools-of-the-trade" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-11-12:/articles/tools-of-the-trade</id>
    <content type="html">&lt;p&gt;Peter Cooper of Ruby Inside &lt;a href='http://www.rubyflow.com/items/2865'&gt;recently asked&lt;/a&gt; if people wanted to write about the things that they use in their development work. So I jumped squarely onto that band wagon&amp;#8230;&lt;/p&gt;

&lt;h2 id='get_organised_with_things'&gt;Get organised with Things&lt;/h2&gt;
&lt;a href='http://culturedcode.com/things/'&gt;
  &lt;img alt='Things icon' class='flow alternate' src='/attachments/things-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;I used to manage my tasks in the legendary &lt;a href='http://en.wikipedia.org/wiki/Lotus_Agenda'&gt;Lotus Agenda&lt;/a&gt;, running in a DOS emulator on Linux. Since I&amp;#8217;ve switched to a Mac I&amp;#8217;ve stopped using it, but reproducing the power of Agenda in Cocoa would be, without a shadow of doubt, my holy grail of desktop todo list management.&lt;/p&gt;

&lt;p&gt;Agenda&amp;#8217;s flexibility allowed me to apply GTD the way I wanted; I would setup a list of tasks to work on today, and then a bunch of tasks that I&amp;#8217;d get around to later. It didn&amp;#8217;t make the mistake of forcing you to assign due dates.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://culturedcode.com/things/' title='Things - task management on the Mac'&gt;Things&lt;/a&gt; is the first modern desktop application I&amp;#8217;ve seen that allows me to work this way, and it does it brilliantly. It also synchs with my iPhone. Perfect.&lt;/p&gt;

&lt;p&gt;The only downside &amp;#8211; you can&amp;#8217;t export (i.e. backup) your data in a human readable form. Ouch.&lt;/p&gt;

&lt;h2 id='textmate'&gt;TextMate&lt;/h2&gt;
&lt;a href='http://macromates.com/'&gt;
  &lt;img class='flow' src='/attachments/textmate-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;I came across &lt;a href='http://macromates.com/' title='TextMate — The Missing Editor for Mac OS X'&gt;TextMate&lt;/a&gt; in the first Rails &amp;#8220;blog in 15 minutes&amp;#8221; screencast. Then I went out and bought my first Mac.&lt;/p&gt;

&lt;p&gt;Get yourself a copy of the Pragmatic Programmers&amp;#8217; &lt;a href='http://www.pragprog.com/titles/textmate/index.html' title='The Pragmatic Bookshelf | TextMate'&gt;TextMate book&lt;/a&gt;; it&amp;#8217;s a great way to both learn the basics and learn about what&amp;#8217;s under the hood.&lt;/p&gt;

&lt;h2 id='writeroom'&gt;WriteRoom&lt;/h2&gt;
&lt;a href='http://www.hogbaysoftware.com/products/writeroom'&gt;
  &lt;img alt='WriteRoom icon' class='flow alternate' src='/attachments/writeroom-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;When I&amp;#8217;m writing articles or long emails I find it can be quite difficult to stay focussed on the task in hand. Not only do I have to block out everything that&amp;#8217;s going on around me (I haven&amp;#8217;t always got those Sennheisers on), I also have to mentally filter out all the distractions on my desktop that are just begging me to click on them (the menu, desktop icons, Tweetie, etc.). Or rather I did, before I started using &lt;a href='http://www.hogbaysoftware.com/products/writeroom' title='WriteRoom — Distraction free writing software for your Mac'&gt;WriteRoom&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;WriteRoom takes everything way and replaces it with a totally blank screen and a flashing cursor.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s beautifully simple; you don&amp;#8217;t even need to pause to save your work as WriteRoom automatically saves it as you go. When you&amp;#8217;re done just copy and paste your text into your blogging software, email client, or word processor. It&amp;#8217;s perfect for writing in Markdown.&lt;/p&gt;

&lt;p&gt;There are free and commercial versions. I find that the free version does everything I need.&lt;/p&gt;

&lt;h2 id='unix_for_er_anything'&gt;Unix for, er, anything&lt;/h2&gt;

&lt;p&gt;This is a fairly obvious one, but you really need to be using Unix. And when I say &amp;#8220;using Unix&amp;#8221; I don&amp;#8217;t just mean that you need to be writing your software on Linux or a Mac (you do, but there&amp;#8217;s much more to it than that).&lt;/p&gt;

&lt;p&gt;I mean that you need to know how to use the power of the Unix command line. Get familiar with your shell and learn how to automate repetitive tasks. I use find, xargs, sed, sort, uniq and bash itself to increase my productivity on a daily basis. You want to get yourself comfortable with writing little snippets of bash into your shell prompt. Here&amp;#8217;s an example from my bash history:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for p in $(grep -rl &amp;#39;Parent: nesta&amp;#39; pages/); do mv $p pages/nesta/; done&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Not very complicated, but damned useful.&lt;/p&gt;

&lt;p&gt;Install the &lt;a href='http://cheat.errtheblog.com/' title='$ command line cheat sheets'&gt;cheat gem&lt;/a&gt; and remember to read the cheat sheets to hand. Spend a spare five minutes reading some man pages.&lt;/p&gt;

&lt;h2 id='vmware_fusion'&gt;VMware Fusion&lt;/h2&gt;
&lt;a href='http://www.vmware.com/products/fusion/'&gt;
  &lt;img alt='VMware Fusion icon' class='flow' src='/attachments/vmware-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;If you deploy your code on Linux but like to use the Mac desktop, you&amp;#8217;ve got a problem. Sooner or later you&amp;#8217;ll find that something doesn&amp;#8217;t quite work when you roll it out, and you&amp;#8217;ll wish you&amp;#8217;d run your tests on a Linux box first.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s where &lt;a href='http://www.vmware.com/products/fusion/' title='VMware Fusion: Run Windows on Mac, for Mac Desktop Virtualization'&gt;VMware Fusion&lt;/a&gt; comes in. I mount a Linux VM over NFS to allow TextMate to access code on the VM, and then ssh into the VM to run the tests, rake, etc.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s not free, and there&amp;#8217;s no support (unless you pay for it), but it&amp;#8217;s still the best virtualisation solution on a Mac.&lt;/p&gt;

&lt;h2 id='omnigraffle'&gt;Omnigraffle&lt;/h2&gt;
&lt;a href='http://www.omnigroup.com/applications/OmniGraffle/'&gt;
  &lt;img alt='Omnigraffle icon' class='flow alternate' src='/attachments/omnigraffle-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;On the rare occassions that I need to capture a new data model I always use &lt;a href='http://www.omnigroup.com/applications/OmniGraffle/' title='The Omni Group - OmniGraffle'&gt;Omnigraffle&lt;/a&gt;. I find it faster than pen/paper for capturing a rapidly evolving data model.&lt;/p&gt;

&lt;p&gt;Most diagrams, wireframes or designs just get sketched on paper.&lt;/p&gt;

&lt;h2 id='make_backups_with_superduper'&gt;Make backups with SuperDuper!&lt;/h2&gt;
&lt;a href='http://www.shirt-pocket.com/SuperDuper/'&gt;
  &lt;img alt='SuperDuper! icon' class='flow' src='/attachments/superduper-icon.png' /&gt;
&lt;/a&gt;
&lt;p&gt;&lt;a href='http://www.shirt-pocket.com/SuperDuper/'&gt;SuperDuper!&lt;/a&gt; is the best backup utility I&amp;#8217;ve ever had (and yes, I also use Time Machine). SuperDuper!&amp;#8217;s speciality is in making clones of a hard drive. I regularly make a snapshot of my laptop&amp;#8217;s drive to an external disk. If I were to just dump everything on one disk onto another it would take &lt;strong&gt;4 hours&lt;/strong&gt;, but SuperDuper! can run an incremental backup that takes &lt;strong&gt;under 30 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can also boot from the backup, which is a life saver if your main disk fails. Hold down Option during start up to boot from a different disk. This trick saved me a fortune recently when my laptop spent two weeks with Apple getting the logic board replaced, and I started using a spare Mac mini.&lt;/p&gt;

&lt;p&gt;The UI is a rare example of a simple design that conceals great power. Rude not to buy it. Daft not to use it.&lt;/p&gt;

&lt;h2 id='git_for_version_control'&gt;Git for version control&lt;/h2&gt;

&lt;p&gt;We all know about Git by now. I&amp;#8217;ve invested some time in learning how to use some of Git&amp;#8217;s more useful features (branches, rebasing, squashed merges, the reflog, etc.) and it&amp;#8217;s really paid off.&lt;/p&gt;

&lt;h2 id='deploy_with_vlad'&gt;Deploy with Vlad&lt;/h2&gt;

&lt;p&gt;Capistrano is neat, but Vlad is cleaner. I still use cap, but for new projects I always choose Vlad.&lt;/p&gt;

&lt;h2 id='web_applications'&gt;Web applications&lt;/h2&gt;

&lt;p&gt;For continuous integration I use Integrity. It looks gorgeous and, being a Sinatra app, is very easy to setup. CI Joe looks nice too, but it came out 1 week after I&amp;#8217;d setup Integrity.&lt;/p&gt;

&lt;p&gt;I also use GitHub and Basecamp. One of my clients is using Mingle. It&amp;#8217;s good, but it&amp;#8217;s pricey and I&amp;#8217;m not sure if it&amp;#8217;s worth the wedge.&lt;/p&gt;

&lt;p&gt;I use most of these apps in Fluid.&lt;/p&gt;

&lt;h2 id='hosting'&gt;Hosting&lt;/h2&gt;

&lt;p&gt;I run most of my web apps on Ubuntu, running at slicehost. I&amp;#8217;ve also been toying with Heroku recently and first impressions are excellent. AppEngine is fun (I also love Python), but I usually need to be able to run background processes which often rules it out in production.&lt;/p&gt;

&lt;h2 id='books'&gt;Books&lt;/h2&gt;

&lt;p&gt;Mmm, maybe this should be a separate list, but it could get a bit dull. The short version goes something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you&amp;#8217;ve never read chapters 2 and 3 of Refactoring by Fowler then find a copy now. They&amp;#8217;ll make you a better programmer. If you can spare the time read chapters 1 and 4 as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='15_macbook_pro'&gt;15&amp;#8221; Macbook Pro&lt;/h2&gt;

&lt;p&gt;This is the best computer I&amp;#8217;ve ever had, bar none. For a long time I toyed with the idea of getting a less powerful Macbook and an iMac. It would have cost about the same money as my MBP and the accompanying 23&amp;#8221; screen, but I&amp;#8217;m glad of the convenience of having everything on one machine.&lt;/p&gt;

&lt;p&gt;Yes, I&amp;#8217;ve had my share of Apple hardware problems. The DVD drive gave up the ghost a while back, which I haven&amp;#8217;t bothered to fix. The hard disk failed just before it&amp;#8217;s second birthday; I replaced it myself with a 7200rpm 500GB drive and the laptop has never felt snappier.&lt;/p&gt;

&lt;h2 id='23_mac_cinema_display'&gt;23&amp;#8221; Mac cinema display&lt;/h2&gt;

&lt;p&gt;It&amp;#8217;s one of the original screens, with a matte finish. You can&amp;#8217;t get them any more and the new model has a glossy finish (lunacy, if you ask me). What on earth were Apple thinking?&lt;/p&gt;

&lt;h2 id='external_hard_drives'&gt;External hard drives&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve got 4 (3 USB and 1 firewire), all of them 250GB.&lt;/p&gt;

&lt;p&gt;The USB drives are 2.5&amp;#8221; Formac disk minis. I bought them off Amazon; reasonably cheap, aesthetically pleasing and (so far) reliable. I use one for Time Machine while the other two are in continual rotation as off site snapshots (more on that later).&lt;/p&gt;

&lt;p&gt;My firewire drive is a 3.5&amp;#8221; Lacie, and to be honest it&amp;#8217;s sold me on firewire. I&amp;#8217;ll be paying extra for firewire in future. It just feels smoother.&lt;/p&gt;

&lt;h2 id='sennheiser_headphones_bithead_amp'&gt;Sennheiser headphones, Bithead amp&lt;/h2&gt;

&lt;p&gt;Some music (typically electronica) helps me focus, shutting out the hubbub around me without having a negative impact on my ability to concentrate. I&amp;#8217;ve got a sneaky suspicion that it helps me achieve &lt;a href='http://en.wikipedia.org/wiki/Flow_(psychology)'&gt;flow&lt;/a&gt;.&lt;/p&gt;
&lt;a href='http://www.headphone.com/headphone-amps/amplifiers/headroom-total-bithead.php'&gt;
  &lt;img alt='Total Bithead headphone amplifier' class='flow alternate' src='/attachments/total-bithead.png' /&gt;
&lt;/a&gt;
&lt;p&gt;I invested in a cracking pair of high end Sennheiser headphones and a &lt;a href='http://www.headphone.com/headphone-amps/amplifiers/headroom-total-bithead.php' title='Headroom Total Bithead - Headphone Amplifier | HeadRoom Audio'&gt;Total Bithead&lt;/a&gt; headphone amplifier from headphone.com to power them. Sure, you could just plug your headphones into your computer, but with headphones as good as the Sennheisers the upgraded soundcard in the Bithead (and the higher quality signal that it delivers) makes a big difference. It sounds superb.&lt;/p&gt;
&lt;a href='http://www.amazon.com/AKG-Acoustics-K26P-26-Headphones/dp/B00066UTBS'&gt;
  &lt;img alt='AKG 26P headphones' class='flow' src='/attachments/akg-26p-headphones.png' /&gt;
&lt;/a&gt;
&lt;p&gt;If you find yourself working or reading on the train a portable pair of headphones to block out the noise is a good investment. I like the &lt;a href='http://www.amazon.com/AKG-Acoustics-K26P-26-Headphones/dp/B00066UTBS' title='Amazon.com: AKG K 26 P - Headphones ( ear-cup ): Electronics'&gt;AKG 26P&lt;/a&gt;; they&amp;#8217;re fairly cheap, have superb bass, and give you a good seal around your ear. I&amp;#8217;ve got some Shure in ear phones too, but they&amp;#8217;re a bit more fiddly and the bass response can&amp;#8217;t compete. They&amp;#8217;re good for flying and running though.&lt;/p&gt;

&lt;h2 id='brompton_folding_bike'&gt;Brompton folding bike&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve saved the best &amp;#8216;til last (photo courtesy of &lt;a href='http://commons.wikimedia.org/wiki/File:Brompton5.jpeg'&gt;Guy Chapman&lt;/a&gt;).&lt;/p&gt;
&lt;a href=''&gt;
  &lt;img alt='Folded Brompton bike' class='flow alternate' src='/attachments/brompton-folded.png' /&gt;
&lt;/a&gt;
&lt;p&gt;Cycling is the only sane way to get around London. A Brompton folding bike is the best way to get between your clients&amp;#8217; offices. You can bung it on the tube/metro, hop in a cab, or if you really need to be somewhere on time, just ride the blessed thing.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll obviously be taking your laptop with you, and if you stick it in the Brompton&amp;#8217;s bag (the new S bag is the one you want) then the bike will take the weight.&lt;/p&gt;

&lt;p&gt;Get yourself one with a hub dynamo and keep cycling through winter&amp;#8230;&lt;/p&gt;</content>
    <published>2009-11-12T00:00:00+00:00</published>
  <feedburner:origLink>http://effectif.com/articles/tools-of-the-trade</feedburner:origLink></entry>
  <entry>
    <title>URL shortener for Basecamp</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/Ba2fEyp9Nk4/basecamp-link-shortener" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-11-10:/articles/basecamp-link-shortener</id>
    <content type="html">&lt;p&gt;Basecamp&amp;#8217;s UI has one failing that keeps causing me problems &amp;#8211; it can&amp;#8217;t layout messages that contain long unwrappable URLs. I decided to fix it, and wrote a link shortening user script for Fluid and Basecamp.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;
&lt;img alt='Basecamp&amp;apos;s layout is affected by a link with long, unwrappable, link text' src='/attachments/long-link.png' /&gt;
&lt;p&gt;While it looks like a corner case, it&amp;#8217;s a problem that has occurred far too often for my liking. When it does occur, all the comments on a message are similarly affected, making it extremely difficult to follow the thread of a conversation.&lt;/p&gt;

&lt;p&gt;To fix it all 37signals would need to do is to abbreviate the text of the relevant link tags, without changing the destination of the link. Incase they don&amp;#8217;t ever get around to it, you can use &lt;a href='http://fluidapp.com/' title='Fluid - Free Site Specific Browser for Mac OS X Leopard'&gt;Fluid.app&lt;/a&gt; and my new &lt;a href='http://userscripts.org/scripts/show/61652'&gt;Link Shrinker user script&lt;/a&gt; to make the abbreviation for you.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the same page, fixed up with the Link Shrinker:&lt;/p&gt;
&lt;img alt='Basecamp link shortening in action' src='/attachments/abbreviated-link.png' /&gt;
&lt;p&gt;To install it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Basecamp in Fluid.&lt;/li&gt;

&lt;li&gt;Visit the &lt;a href='http://userscripts.org/scripts/show/61652'&gt;Link Shrinker&lt;/a&gt; home page.&lt;/li&gt;

&lt;li&gt;Click the &amp;#8220;Install&amp;#8221; button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reload any messages that contain long links, and you should find that they&amp;#8217;ve been appropriately abbreviated.&lt;/p&gt;</content>
    <published>2009-11-10T00:00:00+00:00</published>
  <feedburner:origLink>http://effectif.com/articles/basecamp-link-shortener</feedburner:origLink></entry>
  <entry>
    <title>Benchmarking Ruby exception handling</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/lwyT3BNKdxg/cost-of-exception-handling" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-11-06:/ruby/cost-of-exception-handling</id>
    <content type="html">&lt;p&gt;Which is better, handling an exception or explicitly checking to see whether or not your code is going to break? The answer is &amp;#8220;it depends&amp;#8221;. On the one hand exception handling allows us to write more legible code (often summed up by the saying &amp;#8220;it&amp;#8217;s easier to ask forgiveness than permission&amp;#8221;). On the other, handling an exception is often a costly operation; it can be faster to &amp;#8220;look before you leap&amp;#8221;.&lt;/p&gt;

&lt;p&gt;But just how costly is exception handling? Happily it&amp;#8217;s very easy to find out. I was working away with my pair recently when this very question came up. We were calculating a ratio between two numbers, but wanted to modify the calculation so that if the denominator was 0, we&amp;#8217;d use 0.5 instead. Our function looked something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def calculate_ratio(apples, oranges)
  apples / oranges
rescue ZeroDivisionError
  apples / 0.5
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s succinct and, I think, very readable. We call this function a lot, and in a large percentage of those calls oranges will be 0. Just how expensive is that? There&amp;#8217;s only one way to find out. Test it!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Benchmark&lt;/code&gt; module contains a few nifty functions for testing this kind of scenario. I wrote two functions, &lt;code&gt;ask_forgiveness&lt;/code&gt; and &lt;code&gt;ask_permission&lt;/code&gt; and ran each of them a few million times with the &lt;code&gt;bm()&lt;/code&gt; function.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;quot;benchmark&amp;quot;

include Benchmark

LOOP_COUNT = 1000000

def ask_forgiveness(a)
  1 / a
rescue ZeroDivisionError
  1 / 0.5
end

def ask_permission(a)
  denominator = (a == 0) ? 0.5 : a
  1 / denominator
end

bm(5) do |test|
  test.report(&amp;quot;Forgiveness:&amp;quot;) do
    LOOP_COUNT.times do |i|
      ask_forgiveness(i % 2)
    end
  end
  test.report(&amp;quot; Permission:&amp;quot;) do
    LOOP_COUNT.times do |i|
      ask_permission(i % 2)
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We assumed that 50% of our function calls would result in a ZeroDivisionError, which is why we&amp;#8217;re passing &lt;code&gt;i % 2&lt;/code&gt; into our two functions (it alternates between 0 and 1).&lt;/p&gt;

&lt;p&gt;And the results?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;              user       system     total       real
Forgiveness:  6.780000   0.360000   7.140000 (  7.172876)
 Permission:  1.080000   0.010000   1.090000 (  1.090219)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A clear win (in this case) for checking ahead of time. It was worth benchmarking as I&amp;#8217;d normally go with the more legible exception handling approach every time.&lt;/p&gt;

&lt;p&gt;Exception handling is at it&amp;#8217;s best when exceptions really are the exception to the rule&amp;#8230;&lt;/p&gt;</content>
    <published>2009-11-06T00:00:00+00:00</published>
    <category term="ruby" />
  <feedburner:origLink>http://effectif.com/ruby/cost-of-exception-handling</feedburner:origLink></entry>
  <entry>
    <title>Installing Nokogiri on Leopard</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/oG2noWefopg/installing-nokogiri-on-leopard" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-10-07:/articles/installing-nokogiri-on-leopard</id>
    <content type="html">&lt;p&gt;Nokogiri is a popular (and fast) XML parsing library for Ruby. One of the reasons that it&amp;#8217;s so fast is that it&amp;#8217;s written in C, and makes use of the excellent libxml2 and libxslt C libraries.&lt;/p&gt;

&lt;p&gt;I just installed the Nokogiri Ruby gem on my Mac, which runs OS X 10.5.8 (i.e.&amp;#160;Leopard). Imagine my surprise (given that I&amp;#8217;m supposed to be running one of the most advanced operating systems in the world!) when Nokogiri printed this message in my terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HI. You&amp;#39;re using libxml2 version 2.6.16 which is over 4 years old and has
plenty of bugs. We suggest that for maximum HTML/XML parsing pleasure, you
upgrade your version of libxml2 and re-install nokogiri. If you like using
libxml2 version 2.6.16, but don&amp;#39;t like this warning, please define the
constant I_KNOW_I_AM_USING_AN_OLD_AND_BUGGY_VERSION_OF_LIBXML2 before
requring nokogiri.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Good one, Apple.&lt;/p&gt;

&lt;p&gt;Aaron Kalin tells us &lt;a href='http://martinisoftware.com/2009/07/31/nokogiri-on-leopard.html'&gt;how to solve this problem&lt;/a&gt; on his blog, by compiling new versions of libxml2 and libxslt from source.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;d rather use MacPorts. Taking Aaron&amp;#8217;s advice and modifying it for ports, here&amp;#8217;s what you do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo port install libxml2 libxslt -d
$ sudo gem install nokogiri -- \
    --with-xml2-include=/opt/local/include/libxml2 \
    --with-xml2-lib=/opt/local/lib&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, this post is largely here to remind me what to do next time this crops up. As you were&amp;#8230;&lt;/p&gt;</content>
    <published>2009-10-07T00:00:00+00:00</published>
    <category term="mac-os-x" />
    <category term="system-administration" />
  <feedburner:origLink>http://effectif.com/articles/installing-nokogiri-on-leopard</feedburner:origLink></entry>
  <entry>
    <title>Merging Nesta's categories and articles</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/i_uUodhP4KE/merging-categories-and-articles" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-09-15:/nesta/merging-categories-and-articles</id>
    <content type="html">&lt;p&gt;When I first started writing &lt;a href='/nesta'&gt;Nesta&lt;/a&gt; I wanted a CMS that would allow me to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write articles that would be published in an XML feed, and&lt;/li&gt;

&lt;li&gt;Collect my articles on topic specific category pages that would introduce each topic and link to relevant articles (see my &lt;a href='/ruby-on-rails'&gt;Ruby on Rails&lt;/a&gt; page for an example).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Articles and categories are a great way to organise a blog; they&amp;#8217;re user friendly and &lt;a href='http://www.wordtracker.com/academy/website-structure' title='Website Structure'&gt;search engines love them&lt;/a&gt;. So nothing&amp;#8217;s changed there; I still want articles and categories. However, I&amp;#8217;ve been using Nesta on e-commerce sites recently and have been finding that Nesta, as a general purpose CMS, didn&amp;#8217;t quite cut it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The work described below was originally carried out on a separate unification branch. As of 7 October 2009 the changes described below have been merged into the main code base.&lt;/p&gt;

&lt;h2 id='the_problem'&gt;The problem&lt;/h2&gt;

&lt;p&gt;I made a list of the things that I thought were holding Nesta back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To make a simple web page (e.g. a /contact page) I had to put a &lt;code&gt;contact.mdown&lt;/code&gt; file in the categories folder. It&amp;#8217;s not a category page, so this didn&amp;#8217;t feel quite right.&lt;/li&gt;

&lt;li&gt;You couldn&amp;#8217;t host a page at an arbitrary URL; /foo and /articles/foo were supported, while /foo/bar or /foo/bar/baz weren&amp;#8217;t.&lt;/li&gt;

&lt;li&gt;A category page could collect links to articles, but not to other category pages. This prevented me from building up a hierarchy of topics and limited Nesta&amp;#8217;s flexibility.&lt;/li&gt;

&lt;li&gt;There was no way to control which category pages appeared in the menu. It hadn&amp;#8217;t been a problem on my blog (I don&amp;#8217;t have many categories), but for larger sites it doesn&amp;#8217;t scale. You need to be able to choose what goes in the menu.&lt;/li&gt;

&lt;li&gt;There shouldn&amp;#8217;t be any need to specify the &amp;#8220;Parent&amp;#8221; metadata (it&amp;#8217;s used to setup the navigation links at the top of each page). If we&amp;#8217;re going to choose our own URLs then we can work out the parent automatically (e.g. /nesta is clearly the parent of /nesta/faq).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='the_solution'&gt;The solution&lt;/h2&gt;

&lt;p&gt;After mulling it over for a while I concluded that the only thing that makes articles different from any other page is that I want them to appear in my atom feed. I&amp;#8217;ve also noticed that only the pages that appear in the feed need a date.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Assumption 1:&lt;/strong&gt; Articles are just web pages that are published on a specific date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If articles are just pages, what&amp;#8217;s the difference between a category page and a generic web page? A page only becomes a category page when you&amp;#8217;ve got other pages with related content, and declare them to belong to that category.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Assumption 2:&lt;/strong&gt; Any web page can become a category page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you&amp;#8217;ve ever browsed the Nesta code you might have noticed that an &lt;code&gt;Article&lt;/code&gt; and a &lt;code&gt;Category&lt;/code&gt; were slightly different beasts, and yet we&amp;#8217;ve just concluded that they&amp;#8217;re both just web pages with different metadata. Whoops &amp;#8211; that&amp;#8217;s a design flaw.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve refactored Nesta, merging the &lt;code&gt;Article&lt;/code&gt; and &lt;code&gt;Category&lt;/code&gt; model classes into a new &lt;code&gt;Page&lt;/code&gt; class. You can see it (and try it) in the &lt;a href='http://github.com/gma/nesta/tree/unification'&gt;unification branch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A typical content folder might now look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;menu.txt
pages/
  |
  +---- articles/
  |       |
  |       +---- things.mdown
  |       +---- more-things.mdown
  +---- topic.mdown
  +---- topic/
  |       |
  |       +---- stuff.mdown
  |       +---- more-stuff.mdown
  +---- about.mdown
  +---- contact.mdown
attachments/
  |
  +---- foo.png
  +---- bar.png&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that &lt;code&gt;categories/&lt;/code&gt; and &lt;code&gt;articles/&lt;/code&gt; have been replaced with &lt;code&gt;pages/&lt;/code&gt;, and that there&amp;#8217;s nothing special about the new &lt;code&gt;pages/articles/&lt;/code&gt; directory; I just want to serve some pages with /articles in the URL. You could serve &lt;code&gt;things.mdown&lt;/code&gt; from /cabbages/things if you like; just rename the directory. You can create URLs like /foo/bar/baz simply by nesting directories.&lt;/p&gt;

&lt;p&gt;This seems like the way forward to me. I&amp;#8217;m planning on waiting a couple of weeks to give people a chance to try it out and give me some feedback, before merging the unification branch into master.&lt;/p&gt;

&lt;p&gt;As an added bonus the code is now &lt;strong&gt;simpler&lt;/strong&gt;, runs &lt;strong&gt;faster&lt;/strong&gt;, and uses &lt;strong&gt;fewer resources&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id='trying_it_out'&gt;Trying it out&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re not already running a copy of Nesta you can check out a fresh copy and get started straight away with the new unification branch (you&amp;#8217;ll need to install the relevant dependencies first &amp;#8211; see the &amp;#8220;Quick Start&amp;#8221; section on the &lt;a href='/nesta'&gt;main page&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git clone git://github.com/gma/nesta.git
$ cd nesta
$ git checkout -b unification origin/unification
$ cp config/config.yml.sample config/config.yml
$ rake setup:sample_content
$ shotgun app.rb  # point your browser at http://localhost:9393&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&amp;#8217;re already running Nesta you can get yourself a local copy of the unification branch like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git fetch origin unification
$ git checkout -b unification origin/unification&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&amp;#8217;ve got some existing content then we&amp;#8217;ll need to shuffle it around a bit. I&amp;#8217;ve written a &lt;a href='http://github.com/gma/nesta/blob/unification/scripts/unification-migration'&gt;migration script&lt;/a&gt; to do it for you. Run it from within your Nesta directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./scripts/unification-migration&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The script automates the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Makes a menu file (&lt;code&gt;&amp;lt;content&amp;gt;/menu.txt&lt;/code&gt;) from your old category pages.&lt;/li&gt;

&lt;li&gt;Moves &lt;code&gt;&amp;lt;content&amp;gt;/categories/*&lt;/code&gt; to &lt;code&gt;&amp;lt;content&amp;gt;/pages&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;Moves &lt;code&gt;&amp;lt;content&amp;gt;/articles/*&lt;/code&gt; to &lt;code&gt;&amp;lt;content&amp;gt;/pages&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;Removes &amp;#8220;Parent: &amp;#8230;&amp;#8221; metadata declarations, which are no longer used.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your content is stored in a git repository the script will stage the changes for you, but will leave the task of committing the changes to you.&lt;/p&gt;

&lt;p&gt;If you like the new layout of the content directory you can try merging the new Nesta code into your own site. If, for example, you had your own design changes stored in a branch called &lt;code&gt;mysite&lt;/code&gt; you could merge the two together like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd nesta
$ git checkout mysite
$ git merge unification
# Review the changes, resolve any conflicts...
$ git commit -m &amp;quot;Merged the unification branch.&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After resolving any conflicts that might occur (I only had one when I updated effectif.com which I fixed by removing the &lt;code&gt;category.haml&lt;/code&gt; file &amp;#8211; &lt;code&gt;page.haml&lt;/code&gt; has replaced it) you should find that your site looks just as it did before, but that it&amp;#8217;s suddenly a whole lot more flexible&amp;#8230;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;d love to know how you get on. You can get in touch &lt;a href='http://twitter.com/nestacms'&gt;via Twitter&lt;/a&gt; or &lt;a href='https://github.com/gma'&gt;on GitHub&lt;/a&gt;. Or just drop me an email at &lt;a href='mailto:graham@effectif.com'&gt;graham@effectif.com&lt;/a&gt;.&lt;/p&gt;</content>
    <published>2009-09-15T00:00:00+00:00</published>
    <category term="nesta" />
  <feedburner:origLink>http://effectif.com/nesta/merging-categories-and-articles</feedburner:origLink></entry>
  <entry>
    <title>Testing Rails with Rack::Test</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/zI-DHkAKlTo/testing-rails-with-rack-test" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-06-12:/articles/testing-rails-with-rack-test</id>
    <content type="html">&lt;p&gt;The biggest news in Rails 2.3 is its support for &lt;a href='http://rack.rubyforge.org/' title='Rack: a Ruby Webserver Interface'&gt;Rack&lt;/a&gt;, the &lt;a href='http://www.python.org/dev/peps/pep-0333/' title='PEP 333 -- Python Web Server Gateway Interface v1.0'&gt;WSGI&lt;/a&gt; inspired Ruby web server interface. Of all the Rack goodness that has come along lately, the one that has me the most excited is Bryan Helmkamp&amp;#8217;s &lt;a href='http://github.com/brynary/rack-test/tree/master' title='brynary&amp;apos;s rack-test at master - GitHub'&gt;Rack::Test&lt;/a&gt; library, of which Bryan said &amp;#8220;Basically, I extracted Merb’s request helper code into a small, reusable, framework agnostic library.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I loved Merb&amp;#8217;s request specs. I suspect that I&amp;#8217;m going to like Rack::Test too.&lt;/p&gt;

&lt;h2 id='installing_racktest'&gt;Installing Rack::Test&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ll start by installing Rack::Test and loading it into our Rails app. Append this line to &lt;code&gt;config/environments/test.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;config.gem &amp;quot;rack-test&amp;quot;, :lib =&amp;gt; &amp;quot;rack/test&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can now use &lt;code&gt;rake&lt;/code&gt; to install it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo rake gems:install RAILS_ENV=test&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='running_tests_with_rake_testrack'&gt;Running tests with &amp;#8220;rake test:rack&amp;#8221;&lt;/h2&gt;

&lt;p&gt;We want to be able to run these tests easily with rake, just like our unit or functional tests. Create a new file called &lt;code&gt;lib/tasks/rack-test.task&lt;/code&gt; and paste this code (courtesy of recipe 53 from the &lt;a href='http://www.pragprog.com/titles/fr_arr' title='The Pragmatic Bookshelf | Advanced Rails Recipes'&gt;Advanced Rails Recipes book&lt;/a&gt;) into it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;namespace :test do
  Rake::TestTask.new(:rack =&amp;gt; &amp;quot;db:test:prepare&amp;quot;) do |t|
    t.libs &amp;lt;&amp;lt; &amp;quot;test&amp;quot;
    t.pattern = &amp;quot;test/rack/**/*_test.rb&amp;quot;
    t.verbose = true
  end
  Rake::Task[&amp;quot;test:rack&amp;quot;].comment = &amp;quot;Run the Rack::Test tests in test/rack&amp;quot;
end

task :test do
  Rake::Task[&amp;quot;test:rack&amp;quot;].invoke
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we have also extended the &lt;code&gt;:test&lt;/code&gt; task so that our Rack tests will get run after our unit and functional tests.&lt;/p&gt;

&lt;p&gt;You should now be able to run &lt;code&gt;rake test:rack&lt;/code&gt;, but it won&amp;#8217;t do anything yet. Let&amp;#8217;s test it by dropping this code into a file called &lt;code&gt;test/rack/dummy_test.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require File.join(File.dirname(__FILE__), *%w[.. test_helper])

class DummyTest &amp;lt; ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    lambda { |env| [200, {}, &amp;quot;Coolness&amp;quot;] }
  end

  test &amp;quot;should be hooked up properly&amp;quot; do
    get &amp;quot;/&amp;quot;
    assert last_response.body.include?(&amp;quot;Cool&amp;quot;)
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you run &lt;code&gt;rake test:rack&lt;/code&gt; you should get something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rake test:rack
(in /Users/graham/data/effectif/projects/canvas)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I&amp;quot;lib:test&amp;quot; &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/rack/login_test.rb&amp;quot; 
Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.
Finished in 0.008904 seconds.

1 tests, 1 assertions, 0 failures, 0 errors&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='testing_your_rails_app'&gt;Testing your Rails app&lt;/h2&gt;

&lt;p&gt;You&amp;#8217;ll have noticed that the &lt;code&gt;app&lt;/code&gt; method (which is supposed to return an instance of the Rack application under test) doesn&amp;#8217;t actually have anything to do with Rails. It returns a callable object that needs to be compliant with the Rack API (apps are invoked via their &lt;code&gt;call&lt;/code&gt; method, which is also how you invoke a lambda).&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s fix that by making the &lt;code&gt;app&lt;/code&gt; method return an instance of our Rails application.&lt;/p&gt;

&lt;p&gt;For an example of how Rails instantiates a rack app have a look inside &lt;a href='http://github.com/rails/rails/blob/master/railties/lib/commands/server.rb' title='railties/lib/commands/server.rb at master from rails&amp;apos;s rails - GitHub'&gt;commands/server.rb&lt;/a&gt;. Scroll down until you find the call to &lt;code&gt;Rack::Builder.new&lt;/code&gt;. From there we can see that Rails is using &lt;code&gt;ActionController::Dispatcher.new&lt;/code&gt;. That should be enough for most purposes (if not you can see what else you may need to add by poking around in &lt;code&gt;server.rb&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;That gives us a template test file that looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require File.join(File.dirname(__FILE__), *%w[.. test_helper])

class MyTest &amp;lt; ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    ActionController::Dispatcher.new
  end

  test &amp;quot;home page&amp;quot; do
    get &amp;quot;/&amp;quot;
    assert last_response.ok?
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to get a bit more fancy and test things that aren&amp;#8217;t handled by &lt;code&gt;ActionController::Dispatcher&lt;/code&gt; you can put your app together with &lt;code&gt;Rack::Builder&lt;/code&gt;. As a contrived example, if you wanted to test for the presence of static files (I said it was contrived) you could create your app like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def app
  Rack::Builder.new {
    map &amp;quot;/&amp;quot; do
      use Rails::Rack::Static 
      run ActionController::Dispatcher.new
    end
  }.to_app
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This article was written using Rails 2.3.2, Rack 1.0.0 and Rack::Test 0.3.0.&lt;/p&gt;

&lt;h2 id='why_bother'&gt;Why Bother?&lt;/h2&gt;

&lt;p&gt;Shortly after I first posted this article, &lt;a href='http://www.reddit.com/r/ruby/comments/8sxle/testing_rails_with_racktest/' title='Testing Rails with Rack::Test : ruby'&gt;crispee commented on reddit&lt;/a&gt; asking why you&amp;#8217;d bother to use Rack::Test instead of the functional tests that come with Rails. It&amp;#8217;s a good question, and I completely failed to cover it. Ooops.&lt;/p&gt;

&lt;p&gt;Firstly, Rack::Test is more similar to the Rails integration tests than to the functional tests. Functional tests only allow you test the actions and views of a single controller. Rack::Test allows you to write tests that visit pages anywhere on your site &amp;#8211; you can simulate the behaviour of a real browser to ensure that your entire app hangs together properly.&lt;/p&gt;

&lt;p&gt;Secondly, both the Rails functional and integration tests are closely coupled to Rails. Imagine for a moment that you&amp;#8217;ve been running a Rails app for a while now. You&amp;#8217;ve invested a lot of effort in your application; users can log in and do all sorts of clever stuff. In the meantime you&amp;#8217;ve been hand crafting the sales pages (e.g. home page, tour, FAQ, etc.) have added them to your app. All these static pages are served by one big controller and your routes file is getting to be a bit of a mess. It&amp;#8217;s high time that you introduced a &lt;a href='http://en.wikipedia.org/wiki/Content_management_system' title='Content management system - Wikipedia, the free encyclopedia'&gt;CMS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ve also recently stumbled across a hot new rack compatible web framework (for the sake of argument, let&amp;#8217;s call it &lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt;). You quite fancy using a &lt;a href='/nesta' title='Nesta - Effectif Development'&gt;Sinatra CMS&lt;/a&gt; (sorry, shameless plug) while continuing to develop the main part of your application in Rails. Rack makes this very easy to do in the same Ruby process (see &lt;a href='http://m.onkey.org/2008/11/10/rails-meets-sinatra'&gt;Rails meets Sinatra&lt;/a&gt; for details).&lt;/p&gt;

&lt;p&gt;Obviously, you wrote a test to demonstrate that a new user can click on the &amp;#8220;Buy Now&amp;#8221; link on your home page, navigate their way through your signup forms, and end up on the home page. If you were also astute enough to write that test using Rack::Test, &lt;strong&gt;that test will still work after you move some of those pages into the Sinatra CMS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you refer to Pratik&amp;#8217;s &amp;#8220;Rails meets Sinatra&amp;#8221; post that I linked to above, you&amp;#8217;ll see that you&amp;#8217;d only have to change the way the rack app is instantiated in your test:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def app
  Rack::Builder.new {
    # URLs starting with /account (logged in users) go to Rails
    map &amp;quot;/account&amp;quot; do
      run ActionController::Dispatcher.new
    end

    # Everything else goes to your CMS
    map &amp;quot;/&amp;quot; do
      run Sinatra.application
    end
  }.to_app
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How cool is that?&lt;/p&gt;

&lt;h2 id='useful_resources'&gt;Useful Resources&lt;/h2&gt;

&lt;p&gt;For more information check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bryan&amp;#8217;s &lt;a href='http://www.brynary.com/2009/3/5/rack-test-released-a-simple-testing-api-for-rack-based-frameworks-and-apps' title='Rack::Test released: Simply test any Rack-compatible app - Bryan Helmkamp'&gt;original blog post on Rack::Test&lt;/a&gt; &amp;#8211; a good introduction to the test methods.&lt;/li&gt;

&lt;li&gt;The &lt;a href='http://www.sinatrarb.com/testing.html' title='Testing Sinatra with Rack::Test'&gt;Sinatra documentation&lt;/a&gt; &amp;#8211; includes some handy pointers on using Rack::Test.&lt;/li&gt;

&lt;li&gt;The &lt;a href='http://www.railsenvy.com/2009/6/11/rack-metal-and-rails-middleware' title='Rails Envy: RailsLab: Rack, Metal, and Rails Middleware'&gt;Scaling Rails screencast on Rack&lt;/a&gt; &amp;#8211; a terrific introduction to Rack, Metal and the Rails Rack middleware.&lt;/li&gt;
&lt;/ul&gt;</content>
    <published>2009-06-12T00:00:00+00:00</published>
    <category term="ruby-on-rails" />
    <category term="software-testing" />
  <feedburner:origLink>http://effectif.com/articles/testing-rails-with-rack-test</feedburner:origLink></entry>
  <entry>
    <title>Installing the pg PostgreSQL gem on Mac</title>
    <link href="http://feedproxy.google.com/~r/effectif-development/~3/G7JwA_zw6D4/installing-pg-gem-on-mac" type="text/html" rel="alternate" />
    <id>tag:effectif.com,2009-06-10:/articles/installing-pg-gem-on-mac</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve recently switched from using &lt;a href='http://www.mysql.com/' title='MySQL ::  The world&amp;apos;s most popular open source database'&gt;MySQL&lt;/a&gt; to &lt;a href='http://www.postgresql.org/' title='PostgreSQL: 
The world&amp;apos;s most advanced open source database'&gt;PostgreSQL&lt;/a&gt; for my Ruby projects. You can connect to a PostgreSQL database from Ruby using the &lt;code&gt;pg&lt;/code&gt; gem, but if the &lt;code&gt;pg_config&lt;/code&gt; program isn&amp;#8217;t in your path you&amp;#8217;ll run into problems during installation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo gem install pg 
Building native extensions.  This could take a while...
ERROR:  Error installing pg:
	ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install pg
extconf.rb:1: command not found: pg_config --version
ERROR: can&amp;#39;t find pg_config.
HINT: Make sure pg_config is in your PATH
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few minutes later I realised I&amp;#8217;d installed my copy of PostgreSQL using the one click installer, which puts the database server in the &lt;code&gt;/Library/PostgreSQL&lt;/code&gt; directory. This sorted it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ PATH=$PATH:/Library/PostgreSQL/8.3/bin sudo gem install pg&lt;/code&gt;&lt;/pre&gt;</content>
    <published>2009-06-10T00:00:00+00:00</published>
    <category term="mac-os-x" />
    <category term="system-administration" />
  <feedburner:origLink>http://effectif.com/articles/installing-pg-gem-on-mac</feedburner:origLink></entry>
</feed><!-- page cached: 2010-03-03 19:47:16 -->
