<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Will's Web Miscellany</title>
	<atom:link href="http://willj.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://willj.net</link>
	<description>will.thoughts.pop</description>
	<lastBuildDate>Tue, 02 Feb 2010 20:40:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Freecycle and Freegle group finder for the iPhone</title>
		<link>http://willj.net/2010/02/02/freecycle-freegle-group-finder-for-the-iphone/</link>
		<comments>http://willj.net/2010/02/02/freecycle-freegle-group-finder-for-the-iphone/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 20:40:56 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[finder]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[overcycle]]></category>
		<category><![CDATA[Freecycle]]></category>
		<category><![CDATA[Freegle]]></category>

		<guid isPermaLink="false">http://willj.net/?p=680</guid>
		<description><![CDATA[I&#8217;ve launched my first iPhone app, the Recycling Group Finder for iPhone. It complements the Recycling Group Finder web app making it even easier to find your closest Freecycle or Freegle group by using the iPhone&#8217;s in-built GPS. Check out the information page and give it a go, it&#8217;s free.
]]></description>
			<content:encoded><![CDATA[<div id="attachment_679" class="wp-caption alignnone" style="width: 408px"><a href="http://willj.net/wp-content/uploads/2010/02/large.png"><img class="size-full wp-image-679 " title="Recycling Group Finder app for the iPhone" src="http://willj.net/wp-content/uploads/2010/02/large.png" alt="" width="398" height="298" /></a><p class="wp-caption-text">Recycling Group Finder app for the iPhone</p></div>
<p>I&#8217;ve launched my first iPhone app, the <a title="Find Freecycle and Freegle groups on your iPhone" href="http://supershinyrobot.com/iphone/finder">Recycling Group Finder for iPhone</a>. It complements the <a title="Find Freecycle and Freegle groups close to you" href="http://recyclinggroupfinder.com/">Recycling Group Finder</a> web app making it even easier to find your closest Freecycle or Freegle group by using the iPhone&#8217;s in-built GPS. <a title="Recycling Group Finder for iPhone" href="http://supershinyrobot.com/iphone/finder">Check out the information page</a> and give it a go, it&#8217;s free.</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/02/02/freecycle-freegle-group-finder-for-the-iphone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generating a plist file in rails</title>
		<link>http://willj.net/2010/01/25/generating-a-plist-file-in-rails/</link>
		<comments>http://willj.net/2010/01/25/generating-a-plist-file-in-rails/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 12:01:29 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[builder]]></category>
		<category><![CDATA[plist]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://willj.net/?p=674</guid>
		<description><![CDATA[I recently wrote an iPhone app (Waiting for approval in the app store at the time of writing) that needed data exported from a website (recyclinggroupfinder.com). The simplest way of handling external data in an app it seems is using a plist file, so I wrote this to generate one for me.
First of all I [...]]]></description>
			<content:encoded><![CDATA[<p>I recently wrote an iPhone app (Waiting for approval in the app store at the time of writing) that needed data exported from a website (<a href="http://recyclinggroupfinder.com/">recyclinggroupfinder.com</a>). The simplest way of handling external data in an app it seems is using a plist file, so I wrote this to generate one for me.</p>
<p>First of all I made my action respond to the plist format:</p>
<p><script src="http://gist.github.com/281821.js"></script> Next I created a builder file to format the data:  <script src="http://gist.github.com/285786.js?file=gistfile1.rb"></script></p>
<p>Then register the MIME type at the bottom of environment.rb:</p>
<p><code>Mime::Type.register "text/plist", :plist</code></p>
<p>And that&#8217;s it! Well mostly. The XML file generated can be made significantly smaller by converting it into the binary plist format, run this on the command line in terminal after downloading the generated XML plist.</p>
<p><code>cat things_xml.plist | plutil -convert binary1 - -o things.plist</code></p>
<p>The resultant binary plist is almost half the size of the XML one, much better for inclusion in an iPhone app:</p>
<p><code>pleb:~ will$ ls -l things*<br />
-rw-r--r--  1 will  will  1247300 20 Jan 18:50 things.plist<br />
-rw-r--r--@ 1 will  will  2110437 20 Jan 18:50 things_xml.plist</code></p>
<p>Of course it would be much better to generate the binary format directly, and the <a title="plist-official" href="http://github.com/DanaDanger/plist-official">plist-official</a> gem looks like it can handle that and I mean to investigate, but I wrote the XML version before finding the gem, and it works for me!</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/01/25/generating-a-plist-file-in-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Next NWRUG meeting 21st January – UNIX: Rediscovering the wheel</title>
		<link>http://willj.net/2010/01/12/next-nwrug-meeting-21st-january-%e2%80%93-unix-rediscovering-the-wheel/</link>
		<comments>http://willj.net/2010/01/12/next-nwrug-meeting-21st-january-%e2%80%93-unix-rediscovering-the-wheel/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 14:49:05 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[NWRUG]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://willj.net/?p=671</guid>
		<description><![CDATA[The original announcement is available on the NWRUG site.
This month John Leach of Brightbox will be talking on UNIX: Rediscovering the wheel.
“Those who don’t understand UNIX are condemned to reinvent it, poorly.”
We in the Ruby Community seem to have a habit of re-inventing things. Sometimes this is for good reason, but in some cases we [...]]]></description>
			<content:encoded><![CDATA[<p><em>The original announcement is available on the </em><a href="http://nwrug.org/events/january10/"><em>NWRUG site</em></a><em>.</em></p>
<p>This month John Leach of <a href="http://www.brightbox.co.uk/">Brightbox</a> will be talking on UNIX: Rediscovering the wheel.</p>
<p>“Those who don’t understand UNIX are condemned to reinvent it, poorly.”</p>
<p>We in the Ruby Community seem to have a habit of re-inventing things. Sometimes this is for good reason, but in some cases we don’t know we’re even doing it! We’re wasting valuable time that could be spent learning Erlang!</p>
<p>UNIX-like operating systems have been around for decades and lots of problems have come and gone in that time. I’m going to talk about some of the tools available that can be used to solve common Ruby and Rails deployment and development problems.</p>
<p>Brightbox will also be sponsoring the event so there will be pizzas available after the meeting in Odder across the road from the meeting.</p>
<h3>Schedule</h3>
<p>6:30pm :: Welcome &amp; Pre-session bar visit.<br />
7:00pm :: UNIX: Rediscovering the wheel by John Leach of <a href="http://www.brightbox.co.uk/">Brightbox</a><br />
7:45pm :: Pizzas at the Odder bar across the road sponsored by <a href="http://www.brightbox.co.uk/">Brightbox</a></p>
<p>If you want more information email <a href="mailto://nwrug@willj.net">nwrug@willj.net</a>, call Will on 07939 547 962 or tweet <a href="http://twitter.com/will_j">@will_j</a>.</p>
<h3>Sign Up</h3>
<p>If you would like to attend this event please <a href="http://spreadsheets.google.com/viewform?formkey=cG9TNWpCQXVlamg5eGJYZEJNWkxLQ3c6MA">sign up here</a> as the BBC need a list of attendees before the event, and I need to arrange the correct amount of food.</p>
<h3>Location</h3>
<p>This meeting is being held at one of our regular venues, the BBC Manchester main building on Oxford Road in central Manchester (<a href="http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=BBC,+manchester&amp;sll=53.475612,-2.241763&amp;sspn=0.001291,0.002414&amp;ie=UTF8&amp;ll=53.476892,-2.237778&amp;spn=0.010331,0.019312&amp;t=h&amp;z=16&amp;iwloc=A">Directions</a>). If you get lost call Will on 07939 547 962.</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/01/12/next-nwrug-meeting-21st-january-%e2%80%93-unix-rediscovering-the-wheel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Whenever a link on your website opens in a new window a panda cries</title>
		<link>http://willj.net/2010/01/12/when-a-link-on-your-website-open-in-a-new-window-a-panda-cries/</link>
		<comments>http://willj.net/2010/01/12/when-a-link-on-your-website-open-in-a-new-window-a-panda-cries/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 13:57:39 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://willj.net/?p=658</guid>
		<description><![CDATA[You&#8217;ve got a great website. It&#8217;s amazing. It&#8217;s so good no-one will want to leave it. Ever. Here&#8217;s what you&#8217;re thinking:
OMG wow. Our website is amazing. It&#8217;s so good no-one will want to leave it. Ever. Let&#8217;s help users enjoy our website forever by making all external links open in new windows so then they [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;ve got a great website. It&#8217;s amazing. It&#8217;s so good no-one will want to leave it. Ever. Here&#8217;s what you&#8217;re thinking:</p>
<blockquote><p>OMG wow. Our website is amazing. It&#8217;s so good no-one will want to leave it. Ever. Let&#8217;s help users enjoy our website forever by making all external links open in new windows so then they close the other websites our site will still be open. Our users will thank us until the end of time for making it easier to stay on our site, and anyway Marketing said we had to do it and they know the internet better than anyone!</p></blockquote>
<h2>Sad Panda</h2>
<p>Oh dear. Most people don&#8217;t know this, but making external website links open in a new window makes pandas sad. Look, here&#8217;s a sad panda made sad because it used a website that opened external links in new windows.</p>
<div id="attachment_659" class="wp-caption alignnone" style="width: 510px"><a href="http://willj.net/wp-content/uploads/2010/01/sad_panda.jpg"><img class="size-full wp-image-659 " title="Sad panda" src="http://willj.net/wp-content/uploads/2010/01/sad_panda.jpg" alt="Sad panda" width="500" height="334" /></a><p class="wp-caption-text">Doesn&#39;t this panda look sad?</p></div>
<p>You did that, with your new window link opening. (<a href="http://www.flickr.com/photos/sholt/2463346624/">Panda</a> by <a href="http://www.flickr.com/photos/sholt/">sholt</a>).</p>
<h2>Why Pandas cry</h2>
<p>You need to consider that your website is going to be just one part of a users browsing session. The user will probably already have open tabs in their current browser window and the tab they have your website in will probably have history before your site. When you force a new window to open for a user you are interrupting their browsing flow. When this happens the user has a jarring user experience because of your website. Well done your website.</p>
<p>There are already controls in browsers to let users open links in new windows or tabs, in Safari they are the the first two options in the right-click context menu, or a Cmd+click:</p>
<div id="attachment_661" class="wp-caption alignnone" style="width: 510px"><a href="http://willj.net/wp-content/uploads/2010/01/browser_controls1.jpg"><img class="size-full wp-image-661 " title="Browser controls" src="http://willj.net/wp-content/uploads/2010/01/browser_controls1.jpg" alt="" width="500" height="367" /></a><p class="wp-caption-text">Browser controls already exist giving the user control over where links open</p></div>
<p>When you force the user to open links from your website in a new window you are taking away control the user already has.</p>
<h2>It&#8217;s a PITA and I have to work around it</h2>
<p>Here&#8217;s what I personally do when your website opens a link in a new window:</p>
<ol>
<li>Your website forces new window to open when I click on a link.</li>
<li>New window opens, I close it immediately.</li>
<li>On your website again I Cmd+click the link or right click and select &#8216;open in new tab&#8217;.</li>
<li>I <strong>close the tab your website was in</strong> and re-position the new tab with the new website in where the tab for your website used to be.</li>
<li>I mentally remove one karma point from your website in my internal website excellence tracker.</li>
</ol>
<p>Look at the amount of messing around your website made me do. And now, because of this messing around, your website is no-longer accessible via my browser back button. You&#8217;ve succeeded in making your website even less accessible, the exact opposite of that you were trying to achieve.</p>
<p>Luckily I&#8217;m mentally tough much like Chuck Norris and so can take this two, maybe three times before cracking, but Pandas aren&#8217;t as tough as me. If this happened to a panda the panda would just cry. Sad.</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/01/12/when-a-link-on-your-website-open-in-a-new-window-a-panda-cries/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Flushing memcached servers from Ruby</title>
		<link>http://willj.net/2010/01/08/flushing-memcached-servers-from-ruby/</link>
		<comments>http://willj.net/2010/01/08/flushing-memcached-servers-from-ruby/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 12:25:26 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[memcached]]></category>

		<guid isPermaLink="false">http://willj.net/?p=655</guid>
		<description><![CDATA[In Flushing memcached servers the easy way I highlighted a way to flush a memcached server without restarting it:
$ echo ”flush_all” &#124; nc localhost 11211
However I almost never use the actual shell version of this, mostly I do the equivalent in Ruby by opening up a socket and communicating through that. Here&#8217;s a simple example:
 [...]]]></description>
			<content:encoded><![CDATA[<p>In <a title="Flushing memcached" href="http://willj.net/2008/06/10/flushing-memcached-servers-the-easy-way/">Flushing memcached servers the easy way</a> I highlighted a way to flush a memcached server without restarting it:</p>
<p><code>$ echo ”flush_all” | nc localhost 11211</code></p>
<p>However I almost never use the actual shell version of this, mostly I do the equivalent in Ruby by opening up a socket and communicating through that. Here&#8217;s a simple example:</p>
<p><code> socket = TCPSocket.new( '127.0.0.1', 11211 )<br />
socket.write( "flush_all\r\n" )<br />
result =  socket.recv(2)<br />
puts "Success!" if result == 'OK'<br />
socket.close</code></p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/01/08/flushing-memcached-servers-from-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Carrot porn</title>
		<link>http://willj.net/2010/01/04/carrot-porn/</link>
		<comments>http://willj.net/2010/01/04/carrot-porn/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 16:10:39 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Fun]]></category>
		<category><![CDATA[photography]]></category>
		<category><![CDATA[carrot]]></category>
		<category><![CDATA[porn]]></category>
		<category><![CDATA[vegetable]]></category>

		<guid isPermaLink="false">http://willj.net/?p=651</guid>
		<description><![CDATA[Got this carrot in a bag, was most amused. Should probably try selling it on eBay.

]]></description>
			<content:encoded><![CDATA[<p>Got this carrot in a bag, was most amused. Should probably try selling it on eBay.</p>
<p><img class="alignnone" title="Carrot porn" src="http://farm3.static.flickr.com/2768/4245100700_d54b3315c7_b.jpg" alt="" width="482" height="819" /></p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2010/01/04/carrot-porn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What is the correct order to watch the Star Wars films in?</title>
		<link>http://willj.net/2009/12/31/what-is-the-correct-order-to-watch-the-star-wars-films-in/</link>
		<comments>http://willj.net/2009/12/31/what-is-the-correct-order-to-watch-the-star-wars-films-in/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 10:48:24 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Star Wars]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://willj.net/?p=641</guid>
		<description><![CDATA[A friend of mine recently announced on Twitter that he was introducing his wife to Star Wars, however to my shock and horror he said he would be starting off with Episode 1 which just seemed so wrong…

I&#8217;ll be starting my eldest daughter off on the first Star Wars film (Episode 4) soon too, it just [...]]]></description>
			<content:encoded><![CDATA[<p>A friend of mine recently announced on Twitter that he was introducing his wife to Star Wars, however to my shock and horror he said he would be starting off with Episode 1 which just seemed so wrong…</p>
<p><a href="http://willj.net/wp-content/uploads/2009/12/StarWars1.jpg"><img class="size-full wp-image-643 alignnone" title="What is the correct order to watch the Star Wars films in?" src="http://willj.net/wp-content/uploads/2009/12/StarWars1.jpg" alt="What is the correct order to watch the Star Wars films in?" width="424" height="67" /></a></p>
<p>I&#8217;ll be starting my eldest daughter off on the first Star Wars film (Episode 4) soon too, it just seems like the natural order. When I had calmed down and stopped frothing at the mouth I explained my worries to him and he asked for references.</p>
<p><img class="alignnone size-full wp-image-645" title="Can you cite any references?" src="http://willj.net/wp-content/uploads/2009/12/references.jpg" alt="" width="421" height="64" /></p>
<p>Every conversation I have ever had on the subject of the correct order to watch the Star Wars movies in has resulted in an agreement that 4, 5, 6, 1, 2, 3 is the correct order, but I never got it in writing so I decided it was time to get evidence, from Twitter!</p>
<p><a href="http://willj.net/wp-content/uploads/2009/12/The-question.jpg"><img class="alignnone size-full wp-image-646" title="The question" src="http://willj.net/wp-content/uploads/2009/12/The-question.jpg" alt="" width="416" height="80" /></a></p>
<p>The first response was direct to me in IRC:</p>
<p style="padding-left: 30px;">17:01 Caius: 4,5,6,1,2,3<br />
17:01 Caius: *IF* you let them watch 1,2,3</p>
<p>That&#8217;s fairly standard, it&#8217;s often debated wether bothering with Episodes 1, 2 and 3 is worth it, though I think I will show 4, 5 and 6 to my daughters <em>eventually</em>. The rest of the responses came quickly on Twitter:</p>
<p><a href="http://willj.net/wp-content/uploads/2009/12/StarWars.jpg"><img class="alignnone size-full wp-image-644" title="4, 5, 6!" src="http://willj.net/wp-content/uploads/2009/12/StarWars.jpg" alt="" width="425" height="513" /></a></p>
<p>Well that was the sort of response I was expecting, except the one person who suggested Episodes 4, 5 then 6 <a title="Star Wars Christmas Special" href="http://video.google.com/videoplay?docid=323909610753051544#"><em>followed by the Christmas Special</em></a>. <a href="http://twitter.com/mibly">@mibly</a>, you&#8217;re sick! Here is the response as a pie-chart to better illustrate the responses:</p>
<p><img class="alignnone" title="Opinions of Twitter on Star Wars film watching order" src="http://chart.apis.google.com/chart?cht=p3&amp;chd=t:0,12.5,62.5,25&amp;chs=450x150&amp;chl=123456|456123|456|456(maybe%20123)" alt="" width="450" height="150" /></p>
<p>Not a single person out of my highly representative sample group voted for Episode 1, 2 then 3 first. I kind of agree with <a title="Prettier Pixels" href="http://twitter.com/prettierpixels">@prettierpixels</a> that the in-jokes will be missed if Episodes 1, 2 and 3 are watched first, but I just have a sort of deep-down intuitive feeling that Star Wars will be spoiled if Episodes 4, 5 then 6 aren&#8217;t watched first.</p>
<p>Got an opinion? Post it in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2009/12/31/what-is-the-correct-order-to-watch-the-star-wars-films-in/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Freecycle and Freegle group location data as KML</title>
		<link>http://willj.net/2009/12/29/freecycle-and-freegle-group-location-data-as-kml/</link>
		<comments>http://willj.net/2009/12/29/freecycle-and-freegle-group-location-data-as-kml/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 17:19:10 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[finder]]></category>
		<category><![CDATA[overcycle]]></category>
		<category><![CDATA[Freecycle]]></category>
		<category><![CDATA[Freegle]]></category>
		<category><![CDATA[KML]]></category>

		<guid isPermaLink="false">http://willj.net/?p=636</guid>
		<description><![CDATA[If you&#8217;ve got Google Earth (or something else that can read KML data) you might want to play around with the new recycling group location kml file I&#8217;ve put live on the Recycling Group Finder. More information here.
]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve got <a title="Google Earth" href="http://earth.google.com/">Google Earth</a> (or something else that can read KML data) you might want to play around with the new <a title="Freecycle and Freegle location data" href="http://recyclinggroupfinder.com/group/all.kml">recycling group location kml file</a> I&#8217;ve put live on the<a title="Recycling Group Finder" href="http://recyclinggroupfinder.com/"> Recycling Group Finder</a>. <a title="Freecycle group data as KML" href="http://blog.recyclinggroupfinder.com/2009/12/group-data-available-as-kml.html">More information here</a>.</p>
<div id="attachment_637" class="wp-caption alignnone" style="width: 546px"><a href="http://willj.net/wp-content/uploads/2009/12/population_density.jpg"><img class="size-full wp-image-637 " title="Recycling group data with population density overlay" src="http://willj.net/wp-content/uploads/2009/12/population_density.jpg" alt="Recycling group data with population density overlay" width="536" height="587" /></a><p class="wp-caption-text">Recycling group data with population density overlay</p></div>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2009/12/29/freecycle-and-freegle-group-location-data-as-kml/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Optimising the Recycling Group Finder &#8211; Making a Ruby on Rails app faster</title>
		<link>http://willj.net/2009/10/17/optimising-the-recycling-group-finder-making-a-ruby-on-rails-app-faster/</link>
		<comments>http://willj.net/2009/10/17/optimising-the-recycling-group-finder-making-a-ruby-on-rails-app-faster/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 15:34:26 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[finder]]></category>

		<guid isPermaLink="false">http://willj.net/?p=608</guid>
		<description><![CDATA[This is really just the &#8217;story&#8217; of how I fixed a very slight performance issue with the Recycling Group Finder site that I run, but I figured it would be worth a post as an example or motivation to anyone else who needs to get started investigating their own Ruby on Rails app performance issues.
The [...]]]></description>
			<content:encoded><![CDATA[<p>This is really just the &#8217;story&#8217; of how I fixed a very slight performance issue with the <a title="Recycling Group Finder" href="http://recyclinggroupfinder.com/">Recycling Group Finder</a> site that I run, but I figured it would be worth a post as an example or motivation to anyone else who needs to get started investigating their own Ruby on Rails app performance issues.</p>
<h2>The performance problem</h2>
<p>I&#8217;ve been very happy with the responsiveness of the <a title="Recycling Group Finder" href="http://recyclinggroupfinder.com/">Recycling Group Finder</a>, so just out of interest, just to see what it would tell me, I installed the NewRelic RPM plugin and activated the free Bronze account available to EngineYard customers. The results were pretty satisfying as my average response time for the most popular page was 163ms maximum with the second most popular page at 90ms. Those are good response times and fall well within the <a title="37signals page responsiveness rule" href="http://37signals.com/svn/posts/1506-making-highrise-faster-with-memcached">37signals response time rule</a>:</p>
<blockquote><p>Our general rule of thumb is that most pages should render their HTML on the server in less than 200ms and almost all in less than 500ms.</p></blockquote>
<h2>Suspicious looking</h2>
<p><span>One of the great things about <a title="Flowing Data visualisations" href="http://flowingdata.com/category/visualization/">data visualisations</a> is it can make it really easy to spot patterns. Take this New Relic graph for example:</span></p>
<div id="attachment_610" class="wp-caption alignnone" style="width: 523px"><a href="http://willj.net/wp-content/uploads/2009/10/Recycling-Group-Finder-before-optimisation.jpg"><img class="size-full wp-image-610 " title="Recycling Group Finder - before optimisation" src="http://willj.net/wp-content/uploads/2009/10/Recycling-Group-Finder-before-optimisation.jpg" alt="Recycling Group Finder - graph, before optimisation" width="513" height="178" /></a><p class="wp-caption-text">Recycling Group Finder - before optimisation</p></div>
<p>The yellow on the graph represents time spent in the database, the blue is time spent in Ruby, ie. rendering, controllers etc. Memcached accesses are on there too but they&#8217;re so fast they hardly appear. This graph looked suspicious to me, I&#8217;d normally expect database time to be a much smaller proportion of the overall request time. So it looks like there may be some optimisation that can be done, but in order to optimise I first need to know <em>what</em> to optimise.</p>
<h2>The hunt</h2>
<p>Google for &#8220;<a title="Rules of optimisation" href="http://c2.com/cgi/wiki?RulesOfOptimization">rules</a> <a title="Rules of optimisation" href="http://www.cs.cmu.edu/~jch/java/rules.html">of</a> <a title="Rules of optimisation" href="http://perlbuzz.com/mechanix/2008/02/the-rules-of-optimization-club.html">optimisation</a>&#8220;. Most rules are something like this:</p>
<ol>
<li>Don&#8217;t optimise yet</li>
<li>If you <em>need</em> to optimise, profile first.</li>
</ol>
<p>I&#8217;m never going to be able to optimise my code unless I know what to optimise. If I trawl through looking for places that <em>might</em> be slow and trying to make them faster the chances are I&#8217;m going to spend hours changing code for no benefit. I might even make it slower. I need to know exactly where the bottleneck is, I need to profile my code.</p>
<p>There are a bunch of ways of finding out where your code is slow and I&#8217;ve personally used <a title="ruby-prof" href="http://ruby-prof.rubyforge.org/">ruby-prof</a> before with good results. However I know that the issue here is in the database, and I know that <a title="Rack::Bug" href="http://www.brynary.com/2009/4/22/rack-bug-debugging-toolbar-in-four-minutes">Rack::Bug</a> will show me SQL queries that have run for an action, and importantly how long they took, so that&#8217;s what I&#8217;m going to try first. I install the plugin, configure it and load it up. The issue is immediately obvious:</p>
<div id="attachment_619" class="wp-caption alignnone" style="width: 509px"><a href="http://willj.net/wp-content/uploads/2009/10/rack_bug.jpg"><img class="size-full wp-image-619  " title="Recycling Group Finder - Rack::Bug SQL queries" src="http://willj.net/wp-content/uploads/2009/10/rack_bug.jpg" alt="Recycling Group Finder - Rack::Bug SQL queries" width="499" height="200" /></a><p class="wp-caption-text">Recycling Group Finder - Rack::Bug SQL queries</p></div>
<p>Almost all of the SQL that is executed is under 0.5ms per query, there are a few queries at ~4ms but he one query that really stands out is the third one down. At 44.75ms it is more than half of the overall SQL time. Bingo! Now I know <em>what</em> is slow I need to know <em>why</em> it is slow. Time to break out the query analyser.</p>
<h2>Fixing it</h2>
<p>I needed to dig deeper into that SQL statement to see what it was doing, so I opened up a postgres shell and ran an <code>explain analyse</code> on the query:</p>
<p><script src="http://gist.github.com/212315.js"></script></p>
<p>The issue seems pretty clear. There is a Sequential scan on groups:</p>
<p><code>Seq Scan on groups  (cost=0.00..626.75 rows=4885 width=363) (actual time=0.038..26.495 rows=5126 loops=1)</code></p>
<p>A Sequential scan on a large table is going to sink performance. I can see that the sequential scan is definitely the issue in this case as the cost and time taken are significant proportions of the overall query time. I need to eliminate it. Here&#8217;s the code that generates that query:</p>
<p><code>@groups = Group.find(:all, :include =&gt; :group_page, :origin =&gt; [@location.lat, @location.lng], :limit =&gt; 30, :conditions =&gt; ["defunct = false AND lat is not null and lng is not null and full_address is not null and full_address != '' and country_code = ?", @location.country_code], :order =&gt; 'distance ASC, num_members DESC')</code></p>
<p>I wrote this code ages ago and re-reading it now I can see that although I am limiting the returned results to 30 rows the query will have to hit every row in the table to determine which rows are in the returned 30 as there are no conditions to the query. Whoops. Looking over the <a title="Geokit" href="http://geokit.rubyforge.org/">Geokit docs</a> I see there&#8217;s a <code>:within</code> condition so I added a <code>:within =&gt; 100 </code>to the find. Testing the resultant query in the postgres shell using <code>explain analyse</code> again and the query has dropped to 10ms. Not bad but it&#8217;s still using a sequential scan. Adding an index on the conditions speeds up the query further to ~1.2ms:</p>
<p><script src="http://gist.github.com/212319.js"></script></p>
<p>Not bad when it started out at nearly 45ms. Here is the result reflected in the New Relic graph:</p>
<div id="attachment_614" class="wp-caption alignnone" style="width: 529px"><a href="http://willj.net/wp-content/uploads/2009/10/Recycling-Group-Finder-after-optimisation.jpg"><img class="size-full wp-image-614 " title="Recycling Group Finder - After optimisation" src="http://willj.net/wp-content/uploads/2009/10/Recycling-Group-Finder-after-optimisation.jpg" alt="Recycling Group Finder - After optimisation" width="519" height="175" /></a><p class="wp-caption-text">Recycling Group Finder - after optimisation</p></div>
<p>I deployed the new code approximately in the middle of the graph, it should be pretty obvious where.</p>
<h2>Conclusion</h2>
<p>Before you can optimise your Ruby on Rails app (or your app in any other framework/language for that matter) you need to know know <em>where</em> to optimise. Tools like Rack::Bug and NewRelic allow you to do this effectively and easily allowing you to direct your attention only on those parts of your app that need the attention.</p>
<p>On the <a title="Recycling Group Finder" href="http://recyclinggroupfinder.com/">Recycling Group Finder</a> I cut response times drastically in about half an hour. Without knowing exactly where to make the change I would have been left guessing and may never have made the optimisation I did.</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2009/10/17/optimising-the-recycling-group-finder-making-a-ruby-on-rails-app-faster/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Call of Duty: World at War isn&#8217;t worth £29.99</title>
		<link>http://willj.net/2009/10/12/call-of-duty-world-at-war-isnt-worth-29-99/</link>
		<comments>http://willj.net/2009/10/12/call-of-duty-world-at-war-isnt-worth-29-99/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 22:44:33 +0000</pubDate>
		<dc:creator>Will</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[games]]></category>

		<guid isPermaLink="false">http://willj.net/?p=605</guid>
		<description><![CDATA[Don&#8217;t get me wrong, it was a really good game. It was beautifully done with really well thought out levels and an excellent story.
It was just rather short.
I was kind of hoping for it to be about twice as long. It cost more than renting a film for the same amount of gameplay time. What [...]]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t get me wrong, it was a really good game. It was beautifully done with really well thought out levels and an excellent story.</p>
<p>It was just rather short.</p>
<p>I was kind of hoping for it to be about twice as long. It cost more than renting a film for the same amount of gameplay time. What happened to games taking 40 hours to complete? *mutter* *grumble* it were all fields etc. It was the only thing that let down an otherwise excellent game, and a fairer price would have been £15 to £20 in my opinion, especially considering the tiny distribution cost as I downloaded the game using Steam.</p>
<p>Maybe I&#8217;ll buy it off eBay next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://willj.net/2009/10/12/call-of-duty-world-at-war-isnt-worth-29-99/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
