<?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.threebrothers.org/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title>Quod erat faciendum</title>
  <subtitle>A technical blog by Brendan Ribera</subtitle>
  
  <link href="http://threebrothers.org/brendan/" />
  <id>tag:threebrothers.org,2010-01-07:/brendan/blog</id>
  <updated>2012-01-18T22:24:20.402-08:00</updated>
  <author>
    <name>Brendan Ribera</name>
    <email>brendan.ribera+blogatom@gmail.com</email>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.threebrothers.org/threebrothers/brendan" /><feedburner:info uri="threebrothers/brendan" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title>Strange Loop 2011: Mirah for Android Development</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/hz8RJpmoayg/" />
    <id>tag:threebrothers.org,2012-01-02:/brendan/blog/strange-loop-2011-mirah-for-android-development</id>
    <updated>2012-01-02T15:15:32.143-08:00</updated>
    <summary><![CDATA[
Video of my Mirah/Android presentation from Strange Loop is available now. Here are a few extra resources: Mirah and Pindah on Github. My slides (pdf). The demo project I walk through at the end. I've written about Mirah in the past, too: Experimenting with Mirah for Android Implementing a Lazy Loading Android Gallery with...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;a href="http://www.infoq.com/presentations/Mirah-for-Android-Development;jsessionid=FF7166C2E741E1260D2E94EBCC48AAB1"&gt;Video of my Mirah/Android presentation&lt;/a&gt; from Strange Loop is available now.&lt;/p&gt;

&lt;p&gt;Here are a few extra resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mirah/mirah"&gt;Mirah&lt;/a&gt; and &lt;a href="https://github.com/mirah/pindah"&gt;Pindah&lt;/a&gt; on Github.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/strangeloop/2011-slides/raw/master/Ribera-MirahAndroidDevelopment.pdf"&gt;My slides&lt;/a&gt; (pdf).&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/abscondment/mirah-guide"&gt;demo project&lt;/a&gt; I walk through at the end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've written about Mirah in the past, too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/experimenting-with-mirah-for-android/"&gt;Experimenting with Mirah for Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/implementing-a-lazy-loading-android-gallery-with-mirah/"&gt;Implementing a Lazy Loading Android Gallery with Mirah&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/hz8RJpmoayg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/strange-loop-2011-mirah-for-android-development/</feedburner:origLink></entry><entry>
    <title>The Birth of Hazel Belle Ribera</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/2ni9ONOmHcE/" />
    <id>tag:threebrothers.org,2011-12-20:/brendan/blog/the-birth-of-hazel-belle-ribera</id>
    <updated>2011-12-20T22:40:29.275-08:00</updated>
    <summary><![CDATA[
On December 20, 2011, Hazel Belle Ribera was born! We had another great home birth with our wonderful midwives . Jessica was amazing, to say the least. Hazel is a great little girl, and so snuggly. At 7lbs 5oz and 21.25", she's the lightest and longest of the bunch. She takes after her mother in that way. I won't write qui...]]>
</summary>
    <content type="html">
&lt;p&gt;On December 20, 2011, Hazel Belle Ribera was born!&lt;/p&gt;

&lt;p&gt;&lt;img alt="Newborn" src="http://threebrothers.org/brendan/images/hazel-birth/01.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;We had another great home birth with our &lt;a href="http://www.midwifeseattle.com/"&gt;wonderful midwives&lt;/a&gt;. Jessica was amazing, to say the least.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Snuggling with Dad" src="http://threebrothers.org/brendan/images/hazel-birth/02.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Hazel is a great little girl, and so snuggly. At 7lbs 5oz and 21.25", she's the lightest and longest of the bunch. She takes after her mother in that way.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Blankets" src="http://threebrothers.org/brendan/images/hazel-birth/03.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;I won't write quite so much as I did &lt;a href="http://threebrothers.org/brendan/blog/the-birth-of-ivo-clark-ribera/"&gt;for Ivo's birth&lt;/a&gt;, but not because the experience was lesser. Labor was longer and less obvious this time, but we had good friends and a warm fire to keep us company.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Meeting her brothers" src="http://threebrothers.org/brendan/images/hazel-birth/04.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;The boys both love her, and love to hold her. They're so tender and sweet together; we feel really blessed.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Awake!" src="http://threebrothers.org/brendan/images/hazel-birth/05.jpg" /&gt;&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/2ni9ONOmHcE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/the-birth-of-hazel-belle-ribera/</feedburner:origLink></entry><entry>
    <title>An Appearance of the Strangest Kind </title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/61FzL7GvH6E/" />
    <id>tag:threebrothers.org,2011-06-21:/brendan/blog/an-appearance-of-the-strangest-kind</id>
    <updated>2011-06-21T13:30:35.570-07:00</updated>
    <summary><![CDATA[
Given my current time constraints, a single cogent blog post would constitute a strange enough appearance. But I have something rarer and more fascinating in store for you, Dear Reader: I'll be giving a talk at this year's StrangeLoop ! I'm incredibly excited about this. I'll be speaking on using Mirah for Android developm...]]>
</summary>
    <content type="html">
&lt;p&gt;Given my current time constraints, a single cogent blog post would
constitute a strange enough appearance. But I have something rarer and
more fascinating in store for you, Dear Reader:&lt;/p&gt;

&lt;p&gt;I'll be giving &lt;a href="https://thestrangeloop.com/sessions"&gt;a talk at this year's StrangeLoop&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I'm &lt;em&gt;incredibly&lt;/em&gt; excited about this. I'll be speaking on using Mirah
for Android development – something I've
&lt;a href="http://threebrothers.org/brendan/blog/implementing-a-lazy-loading-android-gallery-with-mirah/"&gt;written about&lt;/a&gt;
a little bit in &lt;a href="http://threebrothers.org/brendan/blog/experimenting-with-mirah-for-android/"&gt;the past&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I attended last year, and found the conference quite excellent. This
year promises to be even better, with keynotes from Rich Hickey
(creator of Clojure), &lt;a href="http://www-mitpress.mit.edu/sicp/"&gt;Gerald Sussman&lt;/a&gt; (!), and more. The caliber of
the other talks looks incredible, and I'm really honored to be
included.&lt;/p&gt;

&lt;p&gt;So, grab a ticket before the prices go up, and come watch me
fumble difficult questions about the JVM!&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/61FzL7GvH6E" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/an-appearance-of-the-strangest-kind/</feedburner:origLink></entry><entry>
    <title>Ruby 1.9.2 on Ubuntu 11.04 </title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/kTLj_PEwNp8/" />
    <id>tag:threebrothers.org,2011-05-06:/brendan/blog/ruby-1-9-2-on-ubuntu-11-04</id>
    <updated>2011-05-06T14:03:01.763-07:00</updated>
    <summary><![CDATA[
I've been building an application from scratch, and I want to go with the latest and greatest of the Ruby world. It's not yet clear to me which of Ruby 1.9.2, JRuby, and REE fit the bill, but I've picked 1.9.2. – at least for now. I'm building around Ubuntu server, and am automating this process with Chef. I've seen...]]>
</summary>
    <content type="html">
&lt;p&gt;I've been building an application from scratch, and I want to go with
the latest and greatest of the Ruby world. It's not yet clear to me
which of Ruby 1.9.2, JRuby, and REE fit the bill, but I've picked
1.9.2. – at least for now.&lt;/p&gt;

&lt;p&gt;I'm building around Ubuntu server, and am automating this process with
Chef. I've seen two different companies get stuck on outdated Ruby or
Rails versions due to lack of easy provisioning, and I don't want to
be in that boat. On the other hand, I want to devote as much time as
possible to user facing features; no one's going to use what I make
based on our future server maintenance paths.&lt;/p&gt;

&lt;h2&gt;Ubuntu packages&lt;/h2&gt;

&lt;p&gt;Ubuntu 11.04 provides a fake 1.9.2 package that is provided by
&lt;code&gt;ruby1.9.1&lt;/code&gt;. Installing &lt;code&gt;ruby1.9.1&lt;/code&gt; actually installs 1.9.2-p0, but
all of the binaries are suffixed with 1.9.1. I hate this false naming
on a purely conceptual level, but I'm sure there's some Debian-based
compatibility issue and I could get over it. However, there have been
three &lt;a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_9_2_136/ChangeLog"&gt;important&lt;/a&gt;
&lt;a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_9_2_180/ChangeLog"&gt;releases&lt;/a&gt;
&lt;a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_9_2_290/ChangeLog"&gt;since&lt;/a&gt;
1.9.2-p0 that contain significant bug fixes. The combination makes that
a show stopper for me.&lt;/p&gt;

&lt;h2&gt;RVM&lt;/h2&gt;

&lt;p&gt;RVM is a tempting option. It's PATH magic is a little too incomplete
for production use, in my opinion – RVM binaries are
conspicuously absent for cron jobs and other non-interactive
shells. This could probably be fixed, but that would feel like a hack
around a hack. And I really don't want to deal with the eventual and
inevitable breakage of all that magic &lt;em&gt;in a production environment&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Compile from source&lt;/h2&gt;

&lt;p&gt;I considered just compiling a binary on each machine, but this is a
quick path to upgrade/maintenance hell. Another downside (that RVM
shares) is the time cost – with a precompiled package, Ruby is
installed in a matter of seconds. Compiling for minutes could be a
minor problem when provisioning a bunch of extra instances in
&lt;em&gt;The Cloud&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Roll your own .deb&lt;/h2&gt;

&lt;p&gt;I decided to combine the source option with the packing option. This
allows me to quickly distribute and install a binary while retaining
control over patch level, executable names, &lt;em&gt;et cetera&lt;/em&gt;. However, it
made me appreciate the
&lt;a href="http://www.lucas-nussbaum.net/blog/?p=617"&gt;difficulties faced by Ruby package maintainers&lt;/a&gt;
– it's not exactly a straightforward process.&lt;/p&gt;

&lt;p&gt;Here are some things I learned the hard way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bugs.launchpad.net/ubuntu/+source/checkinstall/+bug/78455"&gt;checkinstall is broken on Ubuntu&lt;/a&gt;.
You have to pass in &lt;code&gt;--fstrans=no&lt;/code&gt; to get it to work properly.&lt;/li&gt;
&lt;li&gt;Ruby wants to install in &lt;code&gt;/usr/local&lt;/code&gt;, but Ubuntu/Debian would
prefer it to live in &lt;code&gt;/usr&lt;/code&gt;. I decided to stick with the host
system's default.&lt;/li&gt;
&lt;li&gt;PATH is tricky here, too. If you install in &lt;code&gt;/opt&lt;/code&gt;, your gem binaries
won't be on the PATH. You'll need to solve the same sort of PATH
issues RVM has if you want to add your &lt;code&gt;/opt&lt;/code&gt; bindir to everyone's
PATH.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update-alternatives&lt;/code&gt; is your friend; use it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the build process I settled on:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/bash
sudo apt-get -y install zlib1g-dev libssl-dev libreadline5-dev
libyaml-dev build-essential bison checkinstall
cd /tmp
wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p290.tar.gz
tar xvzf ruby-1.9.2-p290.tar.gz
cd ruby-1.9.2-p290
./configure --prefix=/usr\
            --program-suffix=1.9.2\
            --with-ruby-version=1.9.2\
            --disable-install-doc
make
sudo checkinstall -D -y\
                  --fstrans=no\
                  --nodoc\
                  --pkgname='ruby1.9.2'\
                  --pkgversion='1.9.2-p290'\
                  --provides='ruby'\
                  --requires='libc6,libffi5,libgdbm3,libncurses5,libreadline5,openssl,libyaml-0-2,zlib1g'\
                  --maintainer=brendan.ribera@gmail.com
sudo update-alternatives --install /usr/bin/ruby ruby /usr/bin/ruby1.9.2 500\
                        --slave   /usr/bin/ri   ri   /usr/bin/ri1.9.2\
                        --slave   /usr/bin/irb  irb  /usr/bin/irb1.9.2\
                        --slave   /usr/bin/gem  gem  /usr/bin/gem1.9.2\
                        --slave   /usr/bin/erb  erb  /usr/bin/erb1.9.2\
                        --slave   /usr/bin/rdoc rdoc /usr/bin/rdoc1.9.2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm not 100% confident in my checkinstall/deb-foo – namely, the
semantics of &lt;code&gt;--requires&lt;/code&gt; and &lt;code&gt;--provides&lt;/code&gt; are a little unclear to
me. Nor am I sure that the list of required binaries that I provided
is completely accurate. What I do know is that all of this works.&lt;/p&gt;

&lt;p&gt;I can now automate installation of this package on any machine I
provision and instantly have the latest Ruby patch level with properly
named binaries. Cool!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated 2011-09-01 15:12 to point this script at the &lt;strong&gt;1.9.2-p290&lt;/strong&gt; release.&lt;/em&gt;&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/kTLj_PEwNp8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/ruby-1-9-2-on-ubuntu-11-04/</feedburner:origLink></entry><entry>
    <title>On Flashing OCZ Vertex 2 Firmware </title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/puJoKnIlwF0/" />
    <id>tag:threebrothers.org,2011-04-26:/brendan/blog/on-flashing-ocz-vertex-firmware</id>
    <updated>2011-04-26T19:58:53.772-07:00</updated>
    <summary><![CDATA[
I recently bought a MacBook Pro (no, my opinions haven't changed) for iOS development. With it, I bought a shiny new SSD. As it shipped, I read nasty reports of a firmware bug that caused the drive to freeze or lose data when awaking from sleep/hibernate in OSX. Yikes! My drive arrived and did indeed have the affected firm...]]>
</summary>
    <content type="html">
&lt;p&gt;I recently bought a MacBook Pro (no, &lt;a href="http://threebrothers.org/brendan/blog/there-and-back-again-the-return-to-linux/"&gt;my opinions&lt;/a&gt; 
haven't changed) for iOS development. With it, I bought a shiny new
SSD. As it shipped, I read nasty reports of a firmware bug that caused
the drive to freeze &lt;em&gt;or lose data&lt;/em&gt; when awaking from sleep/hibernate
in OSX. Yikes!&lt;/p&gt;

&lt;p&gt;My drive arrived and did indeed have the affected firmware. There was
an updated version, but OCZ does not make a firmware upgrade tool for
OSX. And even outside of OSX, the process is not straightforward.&lt;/p&gt;

&lt;h3&gt;What didn't work:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Plugging the drive into a machine running Windows. The NVIDIA
nForce drivers that my motherboard use prevent the tool from
detecting the drives.&lt;/li&gt;
&lt;li&gt;Plugging the drive in and booting into Linux (at least
initially). The tool reports the drive as locked or frozen, and
asks for a power cycle. Reboot and retry as one might, the message
remains the same. Early investigations led me to believe this was
due to an old BIOS.&lt;/li&gt;
&lt;li&gt;Booting into an Ubuntu Live CD on a 2011 MacBook Pro and flashing
from there. Most Live CDs can't even detect the DVD drive and
boot. The ones that can don't detect either network interface, and
Internet access is required by the tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The solution:&lt;/h3&gt;

&lt;p&gt;Use Linux, either a Live CD or a full installation. When the drive
appears as locked/frozen, suspend the computer and wake it up
again. Or even plug the drive in after booting up, although this seems
marginally risky for drives that already contain data. Either of these
should trick the drive into unfreezing (I only verified the first).&lt;/p&gt;

&lt;p&gt;Simple, yet unintuitive.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/puJoKnIlwF0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/on-flashing-ocz-vertex-firmware/</feedburner:origLink></entry><entry>
    <title>Implementing a Lazy Loading Android Gallery with Mirah </title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/CjFnXOcPzEw/" />
    <id>tag:threebrothers.org,2011-03-31:/brendan/blog/implementing-a-lazy-loading-android-gallery-with-mirah</id>
    <updated>2011-03-31T20:20:01.134-07:00</updated>
    <summary><![CDATA[
Image Galleries The Gallery is a horizontal scrolling list commonly used for displaying a list of images. Unfortunately, the standard Android Developers Gallery tutorial focuses on displaying a small, static list of local images. An API-based list of remote images is much more useful, but more complex. Laziness Needing to...]]>
</summary>
    <content type="html">
&lt;h2&gt;Image Galleries&lt;/h2&gt;

&lt;p&gt;The Gallery is a horizontal scrolling list commonly used for displaying a list
of images. Unfortunately, the standard Android Developers
&lt;a href="http://developer.android.com/resources/tutorials/views/hello-gallery.html"&gt;Gallery tutorial&lt;/a&gt;
focuses on displaying a small, static list of local images. An API-based list
of remote images is much more useful, but more complex.&lt;/p&gt;

&lt;h3&gt;Laziness&lt;/h3&gt;

&lt;p&gt;Needing to fetch remote images is the cause of this complexity. A naïve approach
might download all of the images sequentially, but that quickly becomes
untenable as the number of images in question grows.&lt;/p&gt;

&lt;p&gt;The correct solution will build up a cache of images locally, fetching them only
as they need to be displayed. Images that have not yet loaded will be
represented by a placeholder.&lt;/p&gt;

&lt;h3&gt;Mirah&lt;/h3&gt;

&lt;p&gt;I've grown quite fond of Mirah since I wrote my
&lt;a href="http://threebrothers.org/brendan/blog/experimenting-with-mirah-for-android"&gt;initial reactions about Mirah-Android development&lt;/a&gt;.
Despite the bleeding edge kinks and snares, I find myself being &lt;em&gt;much&lt;/em&gt; more
productive than when using vanilla Java. Since the language is relatively new,
I thought it could be useful to walk through some real-world code and
demonstrate what it can do.&lt;/p&gt;

&lt;h2&gt;Designing a Lazy Gallery&lt;/h2&gt;

&lt;p&gt;We'll make three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An adapter to provide image/view information.&lt;/li&gt;
&lt;li&gt;A selection listener to load images when they enter the visible window.&lt;/li&gt;
&lt;li&gt;A mechanism for downloading the images in question and making them appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Implementation&lt;/h3&gt;

&lt;p&gt;This code is all available on Github; clone it and follow along:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git://github.com/abscondment/lazy-gallery.git
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;LazyGalleryAdapter.mirah&lt;/h4&gt;

&lt;p&gt;Android's list-like views are backed by an
&lt;em&gt;&lt;a href="http://developer.android.com/reference/android/widget/Adapter.html"&gt;Adapter&lt;/a&gt;&lt;/em&gt;,
which provides a standard interface for creating or updating Views to 
represent list items.&lt;/p&gt;

&lt;p&gt;This implementation accepts a JSON string and turns it into equivalent Java
objects.&lt;/p&gt;

&lt;script src="https://gist.github.com/898441.js?file=update_from_json.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
def update_from_json(json:String)
  begin
    data = JSONArray.new json
    data.length.times do |i|
      photo_json = data.getJSONObject(i)
      @photos.add {'caption' =&amp;gt; photo_json.getString('caption'), 'src' =&amp;gt; photo_json.getString('src')}
    end
  rescue JSONException =&amp;gt; e
    Log.e 'LazyGalleryAdapter', 'Could not load JSON', e
  end
  notifyDataSetChanged()
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;Using this list of caption/src pairs, it creates ImageViews for the gallery to
display. It employs a common adapter optimization and re-uses a few existing
views by updating them rather than repeatedly instantiating and discarding 
many objects.&lt;/p&gt;

&lt;script src="https://gist.github.com/898446.js?file=getView.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
def getView(pos:int, convertView:View, parent:ViewGroup)
  layout = RelativeLayout(convertView)
  image = LazyImageView(nil)
  url = String(Map(getItem pos).get('src'))

  if layout.nil?
    image = LazyImageView.new(@context, R.drawable.placeholder)
    image.setScaleType(ImageView.ScaleType.FIT_XY)
    image.setLayoutParams Gallery.LayoutParams.new(@oneeighty,@oneeighty)
    image.setBackgroundResource(R.drawable.gallery_background)
    image.setOnClickListener nil
    image.setClickable false

    layout = RelativeLayout.new @context
    layout.setLayoutParams Gallery.LayoutParams.new(@oneeighty,@oneeighty)
    layout.setGravity Gravity.CENTER
    layout.addView image
  else
    image = LazyImageView(layout.getChildAt 0)
  end

  # show changes
  image.setSrcUrl url
  image.refresh

  return View(layout)
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;Note that we're not using a standard ImageView – it has extra methods
(e.g. &lt;code&gt;refresh&lt;/code&gt;), which we'll talk about below.&lt;/p&gt;

&lt;p&gt;While I chose to build the layout by hand to demonstrate more, we could have
eliminated some of the creation lines by inflating an XML resource:&lt;/p&gt;

&lt;script src="https://gist.github.com/898447.js?file=inflate.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
if layout.nil?
  [...]
  inflater = LayoutInflater.from @context
  layout = inflater.inflate(R.layout.lazy_gallery_item, parent, false)
  layout.addView image
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;h4&gt;GallerySelectionListener.mirah&lt;/h4&gt;

&lt;p&gt;This listener handles selection changes. It figures out which views are
visible when a selection is made and initiates loading of the associated
images. By using &lt;code&gt;gallery.setCallbackDuringFling false&lt;/code&gt; when creating the
gallery, we disable the selection listener during flings so that it only
gets called when we actually want to load images.&lt;/p&gt;

&lt;script src="https://gist.github.com/898449.js?file=onItemSelected.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
def onItemSelected(parent:AdapterView, view:View, pos:int, id:long)
  unless @textView.nil?
    photo_map = Map(LazyGalleryAdapter(parent.getAdapter).getItem pos)
    if photo_map.containsKey('caption')
      @textView.setText String(photo_map.get('caption'))
      @textView.setVisibility View.VISIBLE
    else
      @textView.setVisibility View.INVISIBLE
    end
  end

  view.setSelected true

  # Preload children of the Gallery (i.e. those elements that are visible)
  unless parent.nil?
    parent.getChildCount.times do |i|
      v = RelativeLayout(parent.getChildAt(i))
      LazyImageView(v.getChildAt 0).load unless v.nil?
    end
  end
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;So, we use the LazyGalleryAdapter to get the caption/src map for our given
position. We update the caption and show it.&lt;/p&gt;

&lt;p&gt;Then we iterate over the parent's children – these are the &lt;em&gt;visible&lt;/em&gt;
children, mind you – and call &lt;code&gt;load&lt;/code&gt; on the LazyImageViews that they
house.&lt;/p&gt;

&lt;h4&gt;LazyImageView.mirah&lt;/h4&gt;

&lt;p&gt;The LazyImageView is an &lt;a href="http://developer.android.com/reference/android/widget/ImageView.html"&gt;ImageView&lt;/a&gt;
with plumbing for loading a remote image asynchronously (i.e. off the UI
thread). It attempts to display an image that is already on disk, but defers
fetching remote images until its &lt;code&gt;load&lt;/code&gt; method is called.&lt;/p&gt;

&lt;script src="https://gist.github.com/898450.js?file=image_display.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
def setSrcUrl(url:String):void
  @src_url = url
  @path = File.new(cache_dir, "" + @src_url.hashCode + ".jpg").getCanonicalPath
end

def load:void
  unless @loaded || @src_url.nil? || @path.nil?
    AsyncDownload.new(Handler.new(self), @src_url, @path)
  end
end

def refresh:void
  unless display_from_path()
    setImageResource @placeholder
  end
end

protected

def display_from_path
  d = safe_image_to_drawable(@path, 180)

  unless d.nil?
    setImageDrawable(d)
    @loaded = true
  else
    @resizing = false
    @loaded = false
  end
  return @loaded
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;LazyImageView also handles large images gracefully by asynchronously resizing
them on disk with &lt;a href="https://github.com/abscondment/lazy-gallery/blob/master/src/org/threebrothers/lazy_gallery/LazyImageView.mirah#L137"&gt;safe_image_to_drawable&lt;/a&gt;
and AsyncResize; otherwise, we will get killed for using too much memory.&lt;/p&gt;

&lt;p&gt;Finally, it can invalidate the disk-based cache of images based on image age.&lt;/p&gt;

&lt;script src="https://gist.github.com/898451.js?file=purgeDiskCache.mirah"&gt;&lt;/script&gt;

&lt;noscript&gt;
&lt;pre&gt;
  &lt;code&gt;
def self.cache_dir(c:Context):File
  @cache_dir ||= File.new(c.getCacheDir, "lazy_image_cache")
  @cache_dir.mkdirs unless @cache_dir.exists
  @cache_dir
end

def self.purgeDiskCache(c:Context):void
  thread = Thread.new do
    # 8 hours
    oldest_acceptable = System.currentTimeMillis - long(28800000)
    d = LazyImageView.cache_dir(c)

    files = d.listFiles unless d.nil?
    unless files.nil?
      files.each do |f|
        begin
          # Skip nils, directories, and current files.
          next if f.nil? || (!f.isFile) || f.lastModified &amp;gt;= oldest_acceptable
          Log.v "LazyImageView", "D " + f.getCanonicalPath
          f.delete
        rescue IOException =&amp;gt; e
          Log.e "LazyImageView", "purgeDiskCache: Error checking or deleting cache file:", e
        end
      end
    end
  end

  # Do this on a different thread
  LazyGalleryActivity.threadPoolExecutor.execute thread
end
  &lt;/code&gt;
&lt;/pre&gt;
&lt;/noscript&gt;

&lt;h5&gt;AsyncDownload.mirah&lt;/h5&gt;

&lt;p&gt;AsyncDownload is a fun little helper for downloading basically anything. It uses
some &lt;code&gt;java.util.concurrent&lt;/code&gt; goodies to ensure that a given URL is only fetched
once for a destination path. Imagine the scenario where a user goes back and
forth between two neighboring images before either loads – we don't want
the two selection events to trigger double downloads of the images.&lt;/p&gt;

&lt;p&gt;I won't post source here, but &lt;a href="https://github.com/abscondment/lazy-gallery/blob/master/src/org/threebrothers/lazy_gallery/AsyncDownload.mirah"&gt;it's worth a read&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Working Together&lt;/h2&gt;

&lt;p&gt;Using these components is fairly straightforward:&lt;/p&gt;

&lt;script src="https://gist.github.com/897860.js?file=gistfile1.rb"&gt;&lt;/script&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
gallery = Gallery(findViewById R.id.lazy_gallery)
# Make sure the GallerySelectionListener is only
# triggered when the gallery is stopped on an image.
gallery.setCallbackDuringFling false

# Create our adapter
gallery_adapter = LazyGalleryAdapter.new self

# When the current item is clicked, create a toast with its caption.
this = self
gallery.setOnItemClickListener do |parent, view, pos, id|
  if view.isSelected
    item = Map(gallery_adapter.getItem pos)
    c = String(item.get 'caption') || "Item #{pos} (no caption)"
    Toast.makeText(this, c, Toast.LENGTH_SHORT).show
  end
end

# Add the adapter and the selection listener
gallery.setAdapter gallery_adapter    
gallery.setOnItemSelectedListener GallerySelectionListener.new(TextView(findViewById R.id.lazy_gallery_text))

# Expire any old cached images
LazyImageView.purgeDiskCache(self)

# And finally, send the adapter its data.
# A real application will likely abstract away the JSON string details.
gallery_adapter.update_from_json json_string
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;h2&gt;Try it out&lt;/h2&gt;

&lt;p&gt;The full source is available on Github as a working application. Try it out!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/abscondment/lazy-gallery"&gt;https://github.com/abscondment/lazy-gallery&lt;/a&gt;&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/CjFnXOcPzEw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/implementing-a-lazy-loading-android-gallery-with-mirah/</feedburner:origLink></entry><entry>
    <title>Using memcached -k to prevent paging</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/GA1BIxvmgVc/" />
    <id>tag:threebrothers.org,2011-02-27:/brendan/blog/using-memcached-k-prevent-paging</id>
    <updated>2011-02-27T23:51:12.214-08:00</updated>
    <summary><![CDATA[
Memcached is a powerful brute. Since it's basically just a giant in-memory hash map, you can safely run it on just about any machine that has spare memory. But be sure to know the sort of memory profile your machine has. If something causes memcached to go to swap, performance degrades significantly. Paging can block all q...]]>
</summary>
    <content type="html">
&lt;p&gt;Memcached is a powerful brute. Since it's basically just a giant in-memory hash
map, you can safely run it on just about any machine that has spare memory. But
be sure to know the sort of memory profile your machine has.&lt;/p&gt;

&lt;p&gt;If something causes memcached to go to swap, performance degrades significantly. 
Paging can block all queries to the given server, which can in turn block all
rendering for every page of your site. The performance degradation I observed
was on the order of 30+ seconds, so this is enough for any number of layers in
your application stack to time out inscrutably.&lt;/p&gt;

&lt;p&gt;Fortunately, memcached provides the &lt;code&gt;-k&lt;/code&gt; switch to indicate that its memory should
be locked from paging. You'll wind up running like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brendan@ishmael:~$ sudo memcached -m 1024 -p 11211 -u memcache -l 127.0.0.1 -k
warning: -k invalid, mlockall() failed: Cannot allocate memory
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh, wait. Cannot allocate memory?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brendan@ishmael:~$ ulimit -l
64
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ah, I see. We're limited to 64k of locked memory by default. Fortunately, this
can be changed with per-user granularity by adding some lines to
/etc/security/limits.conf:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;root            -       memlock         1048576
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That takes the root user's limit up quite a bit. The memcached help output
indicates that you should up the limit for the user that &lt;em&gt;launches&lt;/em&gt; the program,
not for the user that memcached eventually runs under.&lt;/p&gt;

&lt;p&gt;Of course, even better than all this would be organizing the system architecture
in such a way that the memcached machine never needs to swap.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/GA1BIxvmgVc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/using-memcached-k-prevent-paging/</feedburner:origLink></entry><entry>
    <title>Benchmarking Ruby Enterprise Edition</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/xePtAqS5YNc/" />
    <id>tag:threebrothers.org,2011-01-31:/brendan/blog/benchmarking-ruby-enterprise-edition</id>
    <updated>2011-01-31T11:42:47.000-08:00</updated>
    <summary><![CDATA[
As part of a perpetual quest to make things run faster, I benchmarked various Ruby configurations using the Urbanspoon codebase. We have a smoke test that hits our key pages regularly to ensure things are running well, and I decided to use this for speed comparison as well. My methodology was simple. Run a local staging se...]]>
</summary>
    <content type="html">
&lt;p&gt;As part of a perpetual quest to make things run faster, I benchmarked various Ruby configurations using the Urbanspoon codebase. We have a smoke test that hits our key pages regularly to ensure things are running well, and I decided to use this for speed comparison as well. My methodology was simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run a local staging server with MySQL &amp;amp; memcache. Run smoke against it a lot to get the caches really hot – we want to test the variations in &lt;em&gt;Ruby&lt;/em&gt;, not in other layers.&lt;/li&gt;
&lt;li&gt;For each test configuration, start Unicorn and run smoke against that server 10 times &lt;sup&gt;[1]&lt;/sup&gt;. This basically tests how quickly Rails can load a few simple objects from the database and squish them together with a pre-rendered page from memcache.&lt;/li&gt;
&lt;li&gt;Repeat #2, but clear out memcache&lt;sup&gt;[2]&lt;/sup&gt; before the start of each run of the smoke test. This tests a lot more of the application's internals, since it makes each test run rebuild the important pages and repopulate memcache. The MySQL cache stays hot throughout both tests and it's not anywhere near breaking a sweat.&lt;/li&gt;
&lt;li&gt;Now that we have 2 views of speed recorded 10 times each for all of the configurations, we can crunch some numbers. Throw out the best and worst times, take the average, and learn.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I benchmarked four &lt;abbr title="Ruby Enterprise Edition"&gt;REE&lt;/abbr&gt; configs, and I used the standard MRI 1.8.7 version as a baseline. The results were gratifying.&lt;/p&gt;

&lt;fieldset&gt;
  &lt;legend&gt;Five Pairs of Ruby Benchmarks&lt;/legend&gt;
  &lt;table style="width:100%;"&gt;
    &lt;tr&gt;
      &lt;th style="width:40%;"&gt;Configuration&lt;/th&gt;
      &lt;th colspan="2"&gt;Cache hot&lt;/th&gt;
      &lt;th colspan="2"&gt;Cache cold&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;MRI 1.8.7&lt;/td&gt;
      &lt;td&gt;10.526875&lt;/td&gt;
      &lt;td&gt;0.0%&lt;/td&gt;
      &lt;td&gt;33.77225&lt;/td&gt;
      &lt;td&gt;0.0%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;REE (default)&lt;/td&gt;
      &lt;td&gt;7.90675&lt;/td&gt;
      &lt;td&gt;-24.89%&lt;/td&gt;
      &lt;td&gt;25.43275&lt;/td&gt;
      &lt;td&gt;-24.69%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;REE (tuned GC&lt;sup&gt;[3]&lt;/sup&gt;)&lt;/td&gt;
      &lt;td&gt;6.972&lt;/td&gt;
      &lt;td&gt;-33.76%&lt;/td&gt;
      &lt;td&gt;22.948875&lt;/td&gt;
      &lt;td&gt;-32.05%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;REE (copy-on-write&lt;sup&gt;[4]&lt;/sup&gt;)&lt;/td&gt;
      &lt;td&gt;9.0375&lt;/td&gt;
      &lt;td&gt;-14.14%&lt;/td&gt;
      &lt;td&gt;26.539625&lt;/td&gt;
      &lt;td&gt;-21.41%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;REE (tuned GC, copy-on-write)&lt;/td&gt;
      &lt;td&gt;7.117625&lt;/td&gt;
      &lt;td&gt;-32.4%&lt;/td&gt;
      &lt;td&gt;23.1595&lt;/td&gt;
      &lt;td&gt;-31.4%&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
  &lt;p style="margin:0.5em 0 0 0;padding;0;font-size:0.8em;"&gt;&lt;em&gt;Figures shown are total seconds elapsed and difference relative to MRI 1.8.7&lt;/em&gt;&lt;/p&gt;
&lt;/fieldset&gt;

&lt;p&gt;Hey, cool! There's some validation, all right. Garbage collection has a huge impact on the performance of web applications, and proper tuning can mean a world of difference. REE does better out of the box, and really flies with a little tuning. Copy-on-write, which reduces overall memory usage, definitely has some performance penalties. But when GC flags are set it really doesn't degrade things much at all. This could be a huge win.&lt;/p&gt;

&lt;p&gt;I'd love to test some other implementations when I get the time, but for now we're going to slowly migrate things to REE.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;sup&gt;[1]&lt;/sup&gt; I did that with &lt;code&gt;for s in {1..10}; do (time ../bin/smoke) 2&amp;gt;&amp;amp;1 | grep '^real'; done | cut -f 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;sup&gt;[2]&lt;/sup&gt; &lt;code&gt;echo -ne 'flush_all\r\nquit\r\n' | nc localhost 11211&lt;/code&gt; will do the trick.&lt;/li&gt;
&lt;li&gt;&lt;sup&gt;[3]&lt;/sup&gt; I used some settings &lt;a href="http://www.rubyenterpriseedition.com/documentation.html#_garbage_collector_performance_tuning"&gt;attributed to Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;sup&gt;[4]&lt;/sup&gt; This is supposed to reduce a &lt;a href="http://www.rubyenterpriseedition.com/documentation.html#_overview_of_ruby_enterprise_edition_ree"&gt;Rails application's memory footprint by 33%&lt;/a&gt;. It's obviously a little slower, but appears to be well worth it.&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/xePtAqS5YNc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/benchmarking-ruby-enterprise-edition/</feedburner:origLink></entry><entry>
    <title>Experimenting with Mirah for Android</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/A-jUa_Cii50/" />
    <id>tag:threebrothers.org,2011-01-21:/brendan/blog/experimenting-with-mirah-for-android</id>
    <updated>2011-01-21T09:42:06.000-08:00</updated>
    <summary><![CDATA[
A while ago I wrote about Closures in Duby . Duby is now called Mirah, and it's a promising way to write compiled code without the weight of Java syntax. I've been updating Urbanspoon's Android application, and I decided to use Mirah for portions our next release. Getting started Mirah is available as a JRuby gem. Hopefull...]]>
</summary>
    <content type="html">
&lt;p&gt;A while ago I wrote about &lt;a href="http://threebrothers.org/brendan/blog/closures-in-java-ruby-and-duby/"&gt;Closures in Duby&lt;/a&gt;. Duby is now called Mirah, and it's a promising way to write compiled code without the weight of Java syntax. I've been updating Urbanspoon's Android application, and I decided to use Mirah for portions our next release.&lt;/p&gt;

&lt;h2&gt;Getting started&lt;/h2&gt;

&lt;p&gt;Mirah is available as a JRuby gem. Hopefully you use RVM to &lt;a href="http://rvm.beginrescueend.com/"&gt;manage your Rubies&lt;/a&gt;, because chances are good that you'll want to switch between them for various purposes.&lt;/p&gt;

&lt;p&gt;Here's an install script that will probably be obsolete the second I finish writing it. Enjoy.&lt;/p&gt;

&lt;h3&gt;Installing mirah&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ rvm jruby
$ gem install mirah
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;miranhdroid - optional install for new project creation&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$ rvm jruby
$ cd ~/code &amp;amp;&amp;amp; git clone https://github.com/jackowayed/mirahndroid.git
$ cd mirahndroid &amp;amp;&amp;amp; rake gem
$ gem install pkg/mirahndroid-*.gem
$ cd ..
$ mirahndroid create -a NewProjectActivity -n NewProject -p new-project -k com.urbanspoon -t android-9
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Welcome to the Wild West&lt;/h2&gt;

&lt;p&gt;Now you can write Rubylike code that compiles to Java. Cool. There's really nothing different about &lt;em&gt;Android&lt;/em&gt; development, but it does showcase Mirah's &lt;em&gt;raison d'être&lt;/em&gt;. Alternate JVM languages that require a runtime are often too slow for writing real, interactive mobile applications. Compiled code is a must, and Mirah provides just that. But there are quite a few gotchas...&lt;/p&gt;

&lt;h3&gt;Not quite Ruby, not quite Java&lt;/h3&gt;

&lt;p&gt;There are a handful of things from both of these worlds that are &lt;a href="https://gist.github.com/704274"&gt;missing or different&lt;/a&gt;. Familiarize yourself with that list; it'll come in handy.&lt;/p&gt;

&lt;h3&gt;Mixed-language Source is Hard&lt;/h3&gt;

&lt;p&gt;Urbanspoon's application has a significant chunk of existing Java. It'd be a waste to rewrite it, since it already works well.&lt;/p&gt;

&lt;p&gt;Building a project with mixed source is complicated. The current mirahc can't do anything with .java sources — it infers types from classfiles and can't resolve them from the sources. So if you have an existing class that you want to reference from Mirah, you need to be able to compile it before you compile the Mirah code. Your Java code is conceptually just another .jar for the Mirah code to use.&lt;/p&gt;

&lt;p&gt;This places an unfortunate constraint on your application, however: your Java code can never explicitly refer to classes defined in Mirah. That'd result in a circular dependency.&lt;/p&gt;

&lt;p&gt;Ideally, mirahc would be able to infer types from both .class and .java files. Then the build process would be easy: mirahc -j to output .java into the gen folder, and javac to compile everything at once. But I think this would require a rudimentary Java parser, and the "Java code can't see Mirah classes" constraint seems easier.&lt;/p&gt;

&lt;h3&gt;Rough build tools&lt;/h3&gt;

&lt;p&gt;Android gives you a stock build.xml, but it'll need customization. The &lt;em&gt;mirahndroid&lt;/em&gt; project will give you an Ant task like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;target name="compile" depends="-resource-src, -aidl"
        description="Compiles project's .mirah files into .class files"&amp;gt;
  &amp;lt;exec executable="mirahc" dir="src"&amp;gt;
    &amp;lt;arg line="-c ${sdk.dir}/platforms/${target-version}/android.jar:gen/" /&amp;gt;
    &amp;lt;arg value="-d" /&amp;gt;
    &amp;lt;arg value="../bin/classes/" /&amp;gt;
    &amp;lt;arg value="." /&amp;gt;
  &amp;lt;/exec&amp;gt;
&amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's a fine start, but you'll need to customize it to compile the generated R.java class if you want to access your application's resources. To make my mixed Java/Mirah project work, I copied the "compile" task from &lt;code&gt;tools/ant/build.xml&lt;/code&gt; in the Android SDK and inserted the mirahc exec call at the end.&lt;/p&gt;

&lt;h3&gt;Return types in if statements&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; – this has been fixed in commit &lt;a href="https://github.com/mirah/mirah/commit/7fa9c6294695a391dccdd3364f01c5c2213959bf"&gt;7fa9c6294695a391dccd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're creating statically typed code. Mirah has some cool type inferencing going on, but your variables are typed nevertheless. Even things like if statements have return values, and you need to make sure they match up. You'll probably just start littering 'nil' around at the end of each branch:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if owed &amp;gt; 100
  message = "You owe a lot of money."
  owed += 1
  nil
else
  message = "All paid!"
  nil
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Nested interfaces&lt;/h3&gt;

&lt;p&gt;You can't easily implement a nested interface. For example, Android's &lt;code&gt;GpsStatus.Listener&lt;/code&gt; — &lt;a href="http://groups.google.com/group/mirah/browse_thread/thread/a86cf47e5f65619f"&gt;see this thread&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Odd scoping&lt;/h3&gt;

&lt;p&gt;The block syntax is cool, but scoping of self and instance variables is incomplete.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;this = self
grid.setOnItemClickListener do |parent, view, position, id|
  this.launch(int(id))
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's super easy to add anonymous listeners with this syntax. But you need to make sure to create &lt;em&gt;local variables&lt;/em&gt; to point to the values you'd like to acces inside the block. Inside "self", for example, refers to that anonymous class (you did read about &lt;a href="http://threebrothers.org/brendan/blog/closures-in-java-ruby-and-duby/"&gt;the cool blocks implementation&lt;/a&gt;, right? Likewise, instance variables don't exist inside the block. You need to pull them into the scope surrounding the block to access them inside the block.&lt;/p&gt;

&lt;h2&gt;Bleeding Edge&lt;/h2&gt;

&lt;p&gt;Some of the problems I encountered were resolved by using a development snapshot of the Mirah gem. If the idea of using bleeding edge technology in a production application makes your blood pressure rise, this might not be for you... yet. As it matures, Mirah will be a more and more attractive alternative to java. I, for one, enjoy running off of unstable branches.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/A-jUa_Cii50" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/experimenting-with-mirah-for-android/</feedburner:origLink></entry><entry>
    <title>Migrating salted md5sums to Bcrypt</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/be2r9kIG9Hs/" />
    <id>tag:threebrothers.org,2010-12-16:/brendan/blog/migrating-md5-plus-salt-to-bcrypt</id>
    <updated>2010-12-16T21:32:45.000-08:00</updated>
    <summary><![CDATA[
In light of recent events , I thought it prudent to change our password storage to use bcrypt hashes. Salting md5sums isn't the worst thing you could do, but it's really not as great as it might seem at first blush. Salted md5s are the leather jacket of bullet-stopping apparel: demonstrably stronger than your plaintext cot...]]>
</summary>
    <content type="html">
&lt;p&gt;In light of &lt;a href="http://www.codinghorror.com/blog/2010/12/the-dirty-truth-about-web-passwords.html"&gt;recent&lt;/a&gt;
&lt;a href="http://twitter.com/#!/abscondment/status/14525340114227201"&gt;events&lt;/a&gt;, I thought
it prudent to change our password storage to use bcrypt hashes. Salting md5sums
isn't the worst thing you could do, but it's really
&lt;a href="http://codahale.com/how-to-safely-store-a-password/"&gt;not as great as it might seem&lt;/a&gt;
at first blush. Salted md5s are the leather jacket of bullet-stopping apparel:
demonstrably stronger than your plaintext cotton T-shirt, but nevertheless
insufficient for the task at hand.&lt;/p&gt;

&lt;p&gt;Converting a production system to use bcrypt requires a few steps and some
sleight of hand. We can't encrypt the plain passwords because we no longer
have access to them. Instead, we could use the md5 with salt as a first pass
and apply bcrypt to that value.&lt;/p&gt;

&lt;p&gt;The process goes like so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a new column to store the bcrypt hash.&lt;/li&gt;
&lt;li&gt;Deploy code that saves all of the md5sum, salt, and bcrypt hash when setting
the password.&lt;/li&gt;
&lt;li&gt;Run a job that populates rows with an md5sum but no bcrypt hash. You'll hash
the existing md5. You'll need to ensure a given md5 hasn't been changed since you read it out of the database.&lt;/li&gt;
&lt;li&gt;Deploy code that authenticates using the bcrypt hash. You'll check the
bcrypt hash against md5sum(plaintext + salt).&lt;/li&gt;
&lt;li&gt;Once you're sure your bcrypt setup is working, deploy code to stop saving
the md5sum. You can either stop using a salt for updated passwords or use a
salt and store it. There's probably some deep cryptographic implication
embedded in that decision, but analyzing it is beyond me. This step is the
point of no return. Once your md5 column gets stale, you can't authenticate 
using it.&lt;/li&gt;
&lt;li&gt;Drop the md5 column. Keep the salt, since you'll need it for authentication.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That wasn't so bad, was it? Step 3 even gave you a little first-hand
demonstration of one chief bcrypt feature: it takes a long time to generate
all of those hashes. No one will be brute-forcing your user base any time soon.
Just don't forget to properly secure your old backups... which you have, right?&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/be2r9kIG9Hs" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/migrating-md5-plus-salt-to-bcrypt/</feedburner:origLink></entry><entry>
    <title>A simple redirect resolver</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/_NFG3MGyOWI/" />
    <id>tag:threebrothers.org,2010-12-15:/brendan/blog/simple-redirect-resolver</id>
    <updated>2010-12-15T20:53:07.000-08:00</updated>
    <summary><![CDATA[
Did you know that curl has an option to automatically follow HTTP redirects? Combined with the HEAD method, this can be used to quickly trace the end destination in a chain of redirecting URLs: #!/bin/sh (echo $1 &amp;&amp; curl -LIs "$1" | grep '^Location' | cut -d' ' -f2) | cat -n The meat of the work is in the curl opti...]]>
</summary>
    <content type="html">
&lt;p&gt;Did you know that curl has an option to automatically follow HTTP redirects?
Combined with the HEAD method, this can be used to quickly trace the end
destination in a chain of redirecting URLs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
(echo $1 &amp;amp;&amp;amp; curl -LIs "$1" | grep '^Location' | cut -d' ' -f2) | cat -n
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The meat of the work is in the curl options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;-L: if redirected, issue an identical request to the new location.&lt;/li&gt;
&lt;li&gt;-I: issues a HEAD command, which allows the server to omit the body.&lt;/li&gt;
&lt;li&gt;-s: no progress bar of failure indication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The subsequent grep/cut/cat combo serve to dice up the headers that are sent
back and turn them into a pretty list of redirect locations.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/_NFG3MGyOWI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/simple-redirect-resolver/</feedburner:origLink></entry><entry>
    <title>Stirling's approximation in Clojure</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/adTajXBp49Q/" />
    <id>tag:threebrothers.org,2010-11-24:/brendan/blog/stirlings-approximation-formula-clojure</id>
    <updated>2010-11-24T23:12:38.000-08:00</updated>
    <summary><![CDATA[
In my free time, I've been working through Probability Theory: A Concise Course by Y.A. Rozanov. The first chapter contains a great factorial approximation that anyone doing computer-based statistics or combinatorics ought to know: This is Stirling's Approximation . As n grows, the relative error of this function compared...]]>
</summary>
    <content type="html">
&lt;p&gt;In my free time, I've been working through &lt;a href="http://store.doverpublications.com/0486635449.html"&gt;Probability Theory: A Concise Course&lt;/a&gt; by Y.A. Rozanov.
The first chapter contains a great factorial approximation that anyone doing
computer-based statistics or combinatorics ought to know:&lt;/p&gt;

&lt;p&gt;&lt;img alt="n! ∼ √(2πn) * (n/e)^n" src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/stirlings-approximation.png" /&gt;&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;Stirling's Approximation&lt;/strong&gt;. As &lt;em&gt;n&lt;/em&gt; grows, the relative error of this
function compared to &lt;em&gt;n!&lt;/em&gt; gets smaller and smaller. More formally, the
&lt;strong&gt;∼&lt;/strong&gt; symbol expresses asypmtotic equivalence, meaning that when A(n)
∼ B(n),&lt;/p&gt;

&lt;p&gt;&lt;img alt="lim n-&amp;gt;&amp;amp;infinity; A(n)/B(n) = 1" src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/sim.png" /&gt;&lt;/p&gt;

&lt;p&gt;I was curious about the actual behavior of this formula, so I decided
to plot the expected convergence. To do this, I wrote up simple Clojure versions
of both functions and charted the expected convergence using Incanter.&lt;/p&gt;

&lt;script src="https://gist.github.com/715040.js?file=stirling-naive.clj"&gt;&lt;/script&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
(use '(incanter core charts io latex))

(defn stirling [#^Integer n]
  (* (Math/sqrt (* 2 n Math/PI))
     (Math/pow n n)
     (Math/pow Math/E (* -1 n))))

(defn fact [#^Integer n]
  (reduce * (range 2 (inc n))))

(let [n-vals (range 5 1000)]
  (view
   (xy-plot n-vals
            (map #(- (/ (fact %) (stirling %)) 1.0) n-vals)
            :x-label "n"
            :y-label "factorial(n)/stirling(n) - 1")))
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;The graph produced by this doesn't exactly pass muster.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Hmm, that doesn't look right." src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/chart-glitch.png" /&gt;&lt;/p&gt;

&lt;p&gt;We've been bit by one of the classic problems of numerical computing: the way
that a number is represented internally limits what can be done with it. In our
case, we've exceeded the range of values that a Java Double can handle. It has 8
bytes split into a 52-bit mantissa, an 11-bit exponent, and a single sign bit
(&lt;a rel="nofollow" href="http://www.mobilefish.com/tutorials/java/java_quickguide_double.html"&gt;in detail&lt;/a&gt;).
The max value it can hold is 1.7976931348623157×10&lt;sup&gt;308&lt;/sup&gt;. Once we
exceed that value, everything is simply "Infinity".&lt;/p&gt;

&lt;script src="https://gist.github.com/715041.js?file=overflow.clj"&gt;&lt;/script&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
user&amp;gt; (fact 200)
788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568660226031904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000
user&amp;gt; (class (fact 200))
java.math.BigInteger

user&amp;gt; (stirling 200)
Infinity
user&amp;gt; (class (stirling 200))
java.lang.Double
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;Clojure magically moves from Integer arithmetic to BigInteger arithmetic
when we overstep the Integer upper bound of 2&lt;sup&gt;31&lt;/sup&gt;-1. But we get no such
love from the functions in java.lang.Math.*, which quickly (at n=144) overflow
to Infinity.&lt;/p&gt;

&lt;p&gt;Now, the entire point of this function is to have a fast approximation of the
factorial &lt;strong&gt;for large &lt;em&gt;n&lt;/em&gt;&lt;/strong&gt;, so this is an issue that we need to overcome. The
naïve version is actually completely useless, since it only functions
for small &lt;em&gt;n&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So let's fix it.&lt;/p&gt;

&lt;p&gt;We need to convert our function to use an arbitrary precision decimal type.
As far as I can tell, Math.PI only comes in double precision. We'd need to have
an &lt;em&gt;n&lt;/em&gt; of, oh, 9,223,372,036,854,775,807 before we exceeded the Double range
and needed to change the way we compute first expression. I don't think anyone
is actually going to seriously try doing factorials that large, but if you are,
you can make use of this &lt;a href="http://www.merriampark.com/bigsqrt.htm"&gt;free BigSquareRoot class that uses BigDecimals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For my purposes, only the exponentiation, division, and multiplication in the
second expression need to be converted. Java has a handy BigDecimal class that
fits the arbitrary-precision bill:&lt;/p&gt;

&lt;script src="https://gist.github.com/715046.js?file=stirling-big.clj"&gt;&lt;/script&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
(defn stirling-big [#^Integer n]
  (.multiply
   (BigDecimal. (Math/sqrt (* 2 Math/PI n)))
   (.pow (.divide (BigDecimal. n)
                  (BigDecimal. Math/E)
                  java.math.MathContext/DECIMAL128)
         n java.math.MathContext/DECIMAL128)))
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;p&gt;We also need to use BigDecimal division in the comparison function, but I'll
leave that as an exercise for the reader. The outcome is quite pleasing from
the numerical error standpoint:&lt;/p&gt;

&lt;p&gt;&lt;img alt="That's better" src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/chart-good.png" /&gt;&lt;/p&gt;

&lt;p&gt;You can see that as &lt;em&gt;n&lt;/em&gt; gets larger, the ratio of the functions asymptotically
approaches 1. The relative error of Stirling's approximation shrinks with larger
&lt;em&gt;n&lt;/em&gt;, which is great for most applications. The absolute error grows, but the
rate at which it grows is smaller than the rate at which the actual value grows.&lt;/p&gt;

&lt;p&gt;And the performance is great, too! Check out the differences:&lt;/p&gt;

&lt;p&gt;&lt;img alt="Performance for the first 64 values of n" src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/time-short.png" /&gt;
&lt;img alt="Performance for all values of n" src="http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/time-full.png" /&gt;&lt;/p&gt;

&lt;p&gt;The raw factorial function is superior for small &lt;em&gt;n&lt;/em&gt;, which is to be expected.
The factorial function has noticeable performance perturbations in the local
view, but these mostly disappear in the full view. The factorial function seems
to perform in quadratic time relative to &lt;em&gt;n&lt;/em&gt;, while Stirling's formula has a
very low constant cost.&lt;/p&gt;

&lt;p&gt;So remember Stirling's formula if you find yourself computing large factorials.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated 2010-11-25 07:48 to clarify &lt;strong&gt;relative error&lt;/strong&gt; versus &lt;strong&gt;actual value&lt;/strong&gt;. Thanks to David Karapetyan for pointing out the discrepency.&lt;/em&gt;&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/adTajXBp49Q" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/</feedburner:origLink></entry><entry>
    <title>Facebook Connect, IE, and the Mysterious IFrame</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/a5YkAdtDrpM/" />
    <id>tag:threebrothers.org,2010-11-16:/brendan/blog/facebook-connect-ie-fb_xd_fragment-iframe</id>
    <updated>2010-11-16T22:36:45.000-08:00</updated>
    <summary><![CDATA[
The Facebook Connect JavaScript does some really neat things to function the way it does, but one of its behaviors is unexpected and downright buggy. When attempting to establish a cross-domain communication channel in Internet Explorer (IE8, at least – perhaps not the others), it loads a duplicate copy of the curren...]]>
</summary>
    <content type="html">
&lt;p&gt;The Facebook Connect JavaScript does some really neat things to
function the way it does, but one of its behaviors is unexpected and
downright buggy. When attempting to establish a cross-domain
communication channel in Internet Explorer (IE8, at least –
perhaps not the others), it loads a duplicate copy of the current page
in an IFrame. That's right – IE8 users attempt to make two hits
to the same page for a single view.&lt;/p&gt;

&lt;h2&gt;A tale of broken CAPTCHAs&lt;/h2&gt;

&lt;p&gt;This behaviour is entirely undocumented. I mean, go ahead – check
&lt;a rel="nofollow" href="http://developers.facebook.com/docs/reference/javascript/"&gt;the Javascript SDK&lt;/a&gt;
– you won't find any mention of it. It's a really bad
behavior, too. If you have Facebook Connect (or a Like button, for
that matter) on any page that has some transient state (say, a CAPTCHA
that gets invalidated and regenerated every time the page loads),
loading the page a second time can invalidate the version that the
user actually interacts with.&lt;/p&gt;

&lt;p&gt;This was the case for our production user registration flow for a long
time. The first hit displayed an image for one CAPTCHA, and the second
hit surreptitiously invalidated it so that there was no possible way
the user could solve the CAPTCHA. Thanks, guys.&lt;/p&gt;

&lt;p&gt;The reason for this double hit is straightforward. The &lt;a href="http://www.w3.org/Security/wiki/Same_Origin_Policy"&gt;same-origin policy&lt;/a&gt; 
restricts how scripts can communicate with different
domains. For the most part, interesting interactions are
restricted. The whole idea of Facebook Connect is predicated on the
idea that their JavaScript will run on your site and provide you with
functionality from a different domain, so they had to find a way to
bypass the restrictions. There are, quite naturally,
&lt;a href="http://softwareas.com/cross-domain-communication-with-iframes"&gt;some tricky ways to make things work using IFrames&lt;/a&gt;. But
following the ever-present JavaScript mantra, Not All Browsers Will
Behave the Same Way. I actually doubt whether browsers behave at all,
ever.&lt;/p&gt;

&lt;p&gt;It seems that Facebook's engineers found IE8 wouldn't do their bidding
unless the communication channel IFrame was hosted on the same domain
as the main site. Oh, and that IFrame needs to run their JavaScript,
too. So what better way to ensure this than, uh, reload the current
page (which we know has the Connect JavaScript) in a hidden
IFrame. No site is going to care if they rack up double hits from a
large percentage of their user base, right? As they helpfully append
&lt;code&gt;fb_xd_fragment&lt;/code&gt; as a query parameter, you can just make a special
case short-circuit in your routing based on that. Right? Right?&lt;/p&gt;

&lt;h2&gt;A solution emerges&lt;/h2&gt;

&lt;p&gt;Remember how I linked to those oh-so-helpful JavaScript SDK docs that
had nothing whatsoever to say about this problem? They are (shock of
all shocks) incomplete. Littered all over the Internet, you'll find
references to a mythical &lt;strong&gt;Cross Domain Communication Channel file&lt;/strong&gt;
that solves this
problem. Stale versions of &lt;a href="http://developers.facebook.com/search?q=Cross_Domain_Communication_Channel"&gt;Facebook's own documentation&lt;/a&gt;
and
&lt;a href="https://github.com/facebook/connect-js/wiki/custom-channel-url"&gt;connect-js Github page&lt;/a&gt;
hint at it, although the current versions of both are devoid of references.&lt;/p&gt;

&lt;p&gt;The channel file is a static chunk of HTML hosted on your domain that
does nothing but load the Facebook Connect JavaScript. Through a
now-undocumented configuration parameter, you can tell the Connect
JavaScript on your site to load &lt;em&gt;that file&lt;/em&gt; in the IFrame instead of
loading a copy of your current page. Problem solved!&lt;/p&gt;

&lt;p&gt;Why wouldn't Facebook document this? Oh, wait – they did... sort
of. It's listed as part of
&lt;a rel="nofollow" href="http://developers.facebook.com/docs/reference/oldjavascript/FB.Facebook.init"&gt;the old JavaScript API&lt;/a&gt;.
Oh, but wait. Apparently the API &lt;em&gt;has&lt;/em&gt; changed a little, and
&lt;code&gt;xdChannelUrl&lt;/code&gt; should just be &lt;code&gt;channelUrl&lt;/code&gt;. They're close enough,
right? That's like, hardly worth mentioning. Or documenting.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update 2010-11-26 09:05: It appears this&lt;/em&gt; is
&lt;em&gt;documented, or at least it is now. Peperone23 points out &lt;a href="http://developers.facebook.com/docs/reference/javascript/FB.init"&gt;the FB.init documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So now you do something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FB.init({
          apiKey: 'OMGWTFBBQ',
          status: true,
          cookie: true,
          xfbml: true,
          channelUrl: window.location.protocol + '//example.com/xd_receiver.html'
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And in xd_receiver.html, you do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt; 
&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;script src="//connect.facebook.net/en_US/all.js"&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Voilà! Facebook can use this static, lightweight, stateless
page to achieve their ends instead of loading the current page a
second time. Set some way-in-the-future cache headers on that sucker
and call it good.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/a5YkAdtDrpM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/facebook-connect-ie-fb_xd_fragment-iframe/</feedburner:origLink></entry><entry>
    <title>Rails 2 Upgrade Turbulence: a Series</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/Qd0QAjioJj8/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-turbulence</id>
    <updated>2010-10-21T07:39:56.700-07:00</updated>
    <summary><![CDATA[
Here are several posts on Rails 2 upgrade issues that I encountered at Urbanspoon: General Cleanup Disabling Sessions ActiveRecord Woes git-svn Workflow Warts Troubleshooting a Slow Production Deployment I've found it common for startups to get stuck on old versions of Rails because the incremental upgrade task is always l...]]>
</summary>
    <content type="html">
&lt;p&gt;Here are several posts on Rails 2 upgrade issues that I encountered at Urbanspoon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-general-cleanup"&gt;General Cleanup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-disabling-sessions"&gt;Disabling Sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-activerecord-woes"&gt;ActiveRecord Woes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-git-svn-workflow-warts"&gt;git-svn Workflow Warts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-troubleshooting-a-slow-production-deployment"&gt;Troubleshooting a Slow Production Deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've found it common for startups to get stuck on old versions of Rails because the incremental upgrade task is always lower priority than feature work (rightfully so). As time progresses, the task becomes more and more daunting. I bit the bullet and upgraded our site.&lt;/p&gt;

&lt;p&gt;Considering that Rails 3 is out now, we're still a touch behind the times. That said, there are still interesting things one could learn from the process of taking a real site (that serves quite a bit of traffic) from Rails 1.1.6 to 2.3.10.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/Qd0QAjioJj8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence/</feedburner:origLink></entry><entry>
    <title>Troubleshooting a Slow Production Deployment</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/VBWERE1dshc/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-troubleshooting-a-slow-production-deployment</id>
    <updated>2010-10-21T06:55:09.000-07:00</updated>
    <summary><![CDATA[
This is part of a series on Rails 2 Upgrade Turbulence . Staging and testing a big release is important, but there are some factors that can only be obsereved in the true production environment. Sure, I can replay the most interesting 80% of a yesterday's traffic against a test server without it failing – but I'm onl...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;em&gt;This is part of a series on &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence"&gt;Rails 2 Upgrade Turbulence&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Staging and testing a big release is important, but there are some factors that
can only be obsereved in the true production environment. Sure, I can replay the
most interesting 80% of a yesterday's traffic against a test server without it
failing – but I'm only &lt;em&gt;one user&lt;/em&gt; making &lt;em&gt;sequential&lt;/em&gt; requests. This
completely dodges the question of how the new code will work at scale.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-activerecord-woes/"&gt;ActiveRecord changes around association loading in Rails 2&lt;/a&gt;
made me particularly curious about the production behavior of Urbanspoon. We had
recently added two identical servers to our production rotation, so I took over
one and did a test deploy of the Rails 2 branch.&lt;/p&gt;

&lt;p&gt;Initial traffic (balanced to about 3% of our load) looked good – snappy
response times and no exceptions. But when I bumped it up to take a full share,
performance was substandard. The Rails 2 server was running at &lt;em&gt;nearly twice the load&lt;/em&gt;
of its counterpart, and was taking &lt;em&gt;on average twice as much time&lt;/em&gt; to serve
requests. Yech. We loaded up Rails 1, and performance improved... although
this test server was still slower than the control. What a quandary.&lt;/p&gt;

&lt;h2&gt;Monitoring works.&lt;/h2&gt;

&lt;p&gt;Since we run munin, we have easy access to historical performance. My debugging
tools/steps were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;top - get a quick, side-by-side eyeball of CPU, load, iowait, memory usage.&lt;/li&gt;
&lt;li&gt;munin
&lt;ul&gt;&lt;li&gt;Rails times: total, views, db
&lt;ul&gt;&lt;li&gt;total time and db time in Rails 2 was twice that in Rails 1&lt;/li&gt;
&lt;li&gt;Raised the question of whether these are even comparable across
different major Rails revisions.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Load/Memory graphs – same story as top.&lt;/li&gt;
&lt;li&gt;Interrupt graphs
&lt;ul&gt;&lt;li&gt;Wow – lots of "Rescheduling interrupts" on the slow server.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;cat /proc/cpuinfo, /proc/meminfo, /proc/interrupts, /proc/ioports (AHCI on
one, but not the other?), ifconfig, etc.
&lt;ul&gt;&lt;li&gt;Are these machines actually the same? Lots of subtle differences.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These were all useful, but they didn't give me a definitive answer. The machines
looked different, but the old code ran significantly faster than the new code.
Yet all reports easily reached by Google lead me to believe Rails 2 might even
give us a speed &lt;em&gt;boost&lt;/em&gt;. So was it really slower, was there a hardware issue, or
what?&lt;/p&gt;

&lt;h2&gt;Debugging works.&lt;/h2&gt;

&lt;p&gt;At this point, I switched into the :debug log-level to see if I could spot any
subtle issues. Was ActiveRecord sending a flood of extra association loads that
we should force into a join? Was memcache getting hit at all? Were our DB times
slow due to bad network performance?&lt;/p&gt;

&lt;p&gt;Very quickly, I noticed something suspicious: our memcache keys looked like
absolute urls. Ah, great. Looks like we were being bit yet again by the new
&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-general-cleanup/"&gt;Rails 2 named routes&lt;/a&gt; – nameley,
that *_url routes now produce an absoluter URL instead of a relative one. In
addition to this, Rails 2 changed the &lt;a href="http://github.com/rails/rails/blob/v2.3.10/actionpack/lib/action_controller/caching/fragments.rb#L33"&gt;fragment_cache_key method to include a
prefix&lt;/a&gt; – so no matter what, fragment caching in Rails 2
would have totally new keys.&lt;/p&gt;

&lt;p&gt;So on our most popular pages, we were using a completely different keyspace.
All of the Rails 1 servers were using an identical keyspace, and the one Rails 2
was in its own. This memcache filled quickly, but the new server's keys got
ejected at a &lt;em&gt;much&lt;/em&gt; higher rate. Its cache misses were through the roof, and
therefore so were its load and response times (although, isn't it nice when
averaging a 120ms response time is "through the roof"?).&lt;/p&gt;

&lt;p&gt;Neat. But fixing the keys didn't bring performance up to par with the other
server. We noticed two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Those pesky "Rescheduling interrupts" were still there – at three
orders of maginitude more per second from the slow server to the other.&lt;/li&gt;
&lt;li&gt;&lt;abbr title="Advanced Host Controller Interface"&gt;AHCI&lt;/abbr&gt; was disabled
on the slow server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even after enabling AHCI and doing an OS reload, the "identical" servers were
none too identical. So we took a leap of faith and  deployed Rails 2 to the
other, faster one, and performance was as expected. We're still working with
our hosting company to figure out what's wrong with the slow machine.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/VBWERE1dshc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-troubleshooting-a-slow-production-deployment/</feedburner:origLink></entry><entry>
    <title>git-svn workflow warts</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/8OqZz3YlbC4/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-git-svn-workflow-warts</id>
    <updated>2010-10-21T06:23:23.000-07:00</updated>
    <summary><![CDATA[
This is part of a series on Rails 2 Upgrade Turbulence . Now that I had confidence that the code was production-ready, it was time to merge changes back into trunk. We still have a main SVN repository, although most people use the git-svn bridge. This proved problematic in three ways which have nothing to do with Rails wha...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;em&gt;This is part of a series on &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence"&gt;Rails 2 Upgrade Turbulence&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that I had confidence that the code was production-ready, it was
time to merge changes back into trunk. We still have a main SVN
repository, although most people use the git-svn bridge. This proved
problematic in three ways which have &lt;em&gt;nothing to do with Rails&lt;/em&gt;
whatsoever, but could prove useful to know about.&lt;/p&gt;

&lt;h2&gt;git-svn rebase problems&lt;/h2&gt;

&lt;p&gt;I use a git-svn repository where the &lt;code&gt;master&lt;/code&gt; branch tracks the trunk
of SVN. I branched from &lt;code&gt;master&lt;/code&gt; to create the &lt;code&gt;dev_rails2&lt;/code&gt; topic
branch. This follows the canonical example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;          A---B---C dev_rails2
         /
    D---E---F---G master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I also pushed &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;dev_rails2&lt;/code&gt; to a remote Git repository. A
few co-workers and I worked in the &lt;code&gt;dev_rails2&lt;/code&gt; branch and checked in
to the remote repository, and I pulled all changes back into my local
branch.&lt;/p&gt;

&lt;p&gt;To prevent the gigantic merge that the Rails 2 upgrade would create, I
pulled trunk into the topic branch weekly. This involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;git checkout master&lt;/li&gt;
&lt;li&gt;git svn rebase&lt;/li&gt;
&lt;li&gt;git checkout dev_rails2&lt;/li&gt;
&lt;li&gt;git merge master&lt;/li&gt;
&lt;li&gt;(resolve conflicts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you do things this way, you have to use a more obscure git-svn
command to commit your changes – dcommit won't work. Can you
spot the reason from looking at my workflow? No? Well, don't feel
too bad; I didn't anticipate the problem either.&lt;/p&gt;

&lt;p&gt;If you merge &lt;code&gt;master&lt;/code&gt; into &lt;code&gt;dev_rails2&lt;/code&gt; as I did, you will eventually
want to merge &lt;code&gt;dev_rails2&lt;/code&gt; back into master to commit. This can happen
with no conflicts if you resolved everything in &lt;code&gt;master&lt;/code&gt; –&amp;gt;
&lt;code&gt;dev_rails2&lt;/code&gt; merges already.&lt;/p&gt;

&lt;p&gt;So I'd do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;git checkout master&lt;/li&gt;
&lt;li&gt;git svn rebase&lt;/li&gt;
&lt;li&gt;git merge dev_rails2 &lt;em&gt;(succeeded)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But then in order for &lt;code&gt;git svn dcommit&lt;/code&gt; to work, I'd need to do this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;git svn rebase &lt;em&gt;(failed spectacularly)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;git svn dcommit &lt;em&gt;(doesn't work without the prior succeeding)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last step will rewind all of your merged changesets (which now
include some of the existing commits in Subversion) and apply them
to the current state of subversion. This generates conflicts because
it's attempting to diff the already resolved state against Subversion,
and the resolution often would not apply cleanly.&lt;/p&gt;

&lt;p&gt;The correct solution is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git svn set-tree [first-hash]..[last-hash]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html" rel="external nofollow"&gt;&lt;abbr title="Quote the Effing Manual"&gt;QTFM&lt;/abbr&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;You should consider using dcommit instead of this command. Commit
specified commit or tree objects to SVN. This relies on your imported
fetch data being up-to-date. This makes absolutely no attempts to do
patching when committing to SVN, it simply overwrites files with those
specified in the tree or commit. All merging is assumed to have taken
place independently of git svn functions.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Huh? &lt;code&gt;set-tree&lt;/code&gt;? Yeah, I'd never heard of it either. And I fixed my problem
before I learned about it. In order to save revision history, I decided to
re-resolve all of the conflicts (sometimes badly, since there were too many
commits to remember every bit of minutiae) and fix the bad commits later.
This meant I'd have the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Changes made in &lt;code&gt;master&lt;/code&gt; (and therefore Subversion) that I wanted to keep.&lt;/li&gt;
&lt;li&gt;Changes made in &lt;code&gt;dev_rails2&lt;/code&gt; that I wanted to keep, but that also contained
random, badly-resolved conflicts.&lt;/li&gt;
&lt;li&gt;Changes to fix the bad resolutions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the &lt;code&gt;dev_rails2&lt;/code&gt; branch was in a good (i.e. a correctly merged view
of the final product that I wanted to commit) state, I managed to get #3 by
making a separate clone of it and copying files into the checkout in which I
had run (and resolved) &lt;code&gt;git svn rebase&lt;/code&gt;. This allowed me to preserve ~130
commit comments worth of Rails 2 upgrade knowledge. But man, I wish I had
known about &lt;code&gt;set-tree&lt;/code&gt; beforehand.&lt;/p&gt;

&lt;h2&gt;git-svn dcommit problems&lt;/h2&gt;

&lt;p&gt;After finally merging in &lt;code&gt;dev_rails2&lt;/code&gt; and getting a clean &lt;code&gt;git svn rebase&lt;/code&gt;, I
was ready to commit. Not so fast – &lt;code&gt;git svn dcommit&lt;/code&gt; failed rather
quickly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[hash] doesn't exist in the repository at /usr/lib/git-core/git-svn [...]
Failed to read object [hash] at /usr/lib/git-core/git-svn line [...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Who knows what &lt;code&gt;set-tree&lt;/code&gt; would have done here. Two of my changes had made it
into Subversion, but the process halted on the commit in which I had copied
the new mysql_replication_adapter plugin into vendor/plugins. After Googling
around, I discovered this &lt;a href="http://de-co-de.blogspot.com/2009/02/git-svn-and-submodules.html"&gt;great post about submodules&lt;/a&gt;
causing this of failure.&lt;/p&gt;

&lt;p&gt;Although I didn't have a git submodule, the basic issue turns out to be the
same. Something in my commit (I believe it was an empty directory) appeared
differently in the subversion changeset. When git-svn attempted to map this
back to the git objects it knew about, a mismatch occurred. The object existed
in one repository but not the other, so the system (wisely) errored out.&lt;/p&gt;

&lt;p&gt;Unfortunately, fixing this was not as simple as deleting the bad directory
in HEAD. git-svn has to commit your work sequentially, so I needed to rewrite
history.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git tag broken [hash that failed to commit]
$ git checkout broken
$ # remove the directory, re-add with correct name, cross fingers
$ git commit --amend
$ git rebase --onto HEAD broken master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After rewriting the svn-incompatible changes, &lt;code&gt;git svn dcommit&lt;/code&gt; worked! But &lt;em&gt;of course&lt;/em&gt; there was one more issue.&lt;/p&gt;

&lt;h2&gt;.svn directories in the tree&lt;/h2&gt;

&lt;p&gt;I had to update quite a few plugins, and I did this by checking out the source
code and copying it into place in vendor/plugins. This was a short-sighted way
of doing things, but using git-svn puts one in the unenviable position of being
able to use neither git submodules nor svn:externals. Unfortunately, git-svn is
more than happy to let you check full copies of Subversion repositories into
your own Subversion repository. Mind blowing, no?&lt;/p&gt;

&lt;p&gt;The affect of this is that when you &lt;code&gt;svn up&lt;/code&gt;, Subversion fails to update because
it can't actually add the .svn directories that are in the source tree –
it'd overwrite the ones that it truly needs! Also unfortunate is that you can't
delete them locally because &lt;em&gt;a)&lt;/em&gt; they don't exist yet and &lt;em&gt;b)&lt;/em&gt; even if they did,
the svn client helpfully ignores any attempts to operate on files named .svn. So
this is broken and will fail:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svn del -m 'Delete .svn checkin' path/to/bad/.svn
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instead, one must delete the checked-in .svn directory on the remote server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svn del -m 'Delete .svn checkin' svn+ssh://svn-server/trunk/path/to/bad/.svn
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whew!&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/8OqZz3YlbC4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-git-svn-workflow-warts/</feedburner:origLink></entry><entry>
    <title>ActiveRecord woes</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/6n-kzgIAx4k/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-activerecord-woes</id>
    <updated>2010-10-21T06:02:13.000-07:00</updated>
    <summary><![CDATA[
This is part of a series on Rails 2 Upgrade Turbulence . ActiveRecord associations have changed. There are some gotchas, at least compared to the Rails 1.1.6 frame of mind. Join v. Queries Instead of forcing a join against the tables for every incuded association, ActiveRecord is now smart enough to split things into separ...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;em&gt;This is part of a series on &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence"&gt;Rails 2 Upgrade Turbulence&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ActiveRecord associations have changed. There are some gotchas, at least compared to the Rails 1.1.6 frame of mind.&lt;/p&gt;

&lt;h2&gt;Join v. Queries&lt;/h2&gt;

&lt;p&gt;Instead of forcing a join against the tables for every incuded association, ActiveRecord is now smart enough to split things into separate, on-index loads of each model. It then slaps the correct assocations back together. If separate loading is not possible, it can fall back on the join model.&lt;/p&gt;

&lt;h3&gt;Broken SQL&lt;/h3&gt;

&lt;p&gt;The nature of programmatically generating SQL is that, well, things break. Specifically, if you find with both &lt;code&gt;:include&lt;/code&gt; and &lt;code&gt;:joins&lt;/code&gt; statements, you'll be in for a rude awakening. Whether single or multiple, every query will include the specified &lt;code&gt;:joins&lt;/code&gt;. If your application expected a single, joined query (as with Rails 1.x), and you now get multiple, this will break.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;:include&lt;/code&gt; and have &lt;code&gt;:conditions&lt;/code&gt; or &lt;code&gt;:order&lt;/code&gt; statements with unqualified column names. These also get applied to each of the queries, but since the columns don't exist in every table we're querying, things break. If you qualify the column names, ActiveRecord is smart enough to perform the join for you instead of executing separate queries.&lt;/p&gt;

&lt;h2&gt;Associations&lt;/h2&gt;

&lt;p&gt;As I hinted in code when writing about &lt;a href="http://threebrothers.org/brendan/blog/bulk-loading-associations-with-active-record/"&gt;Bulk-loading associations with ActiveRecord&lt;/a&gt;, you need to be careful when using normal Array operators on collection-like associations. You can easily add to an association without expecting an insert.&lt;/p&gt;

&lt;p&gt;E.g., &lt;code&gt;Restaurant.find(:first).cuisines &amp;lt;&amp;lt; Cuisine.find(:first)&lt;/code&gt; now generates an insert statement that establishes that relation instead of simply pushing the Cuisine object into an array.&lt;/p&gt;

&lt;p&gt;To manipulate the collection directly without doing anything in the database, you must use &lt;code&gt;association.target&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Restaurant.find(:first).cuisines.target &amp;lt;&amp;lt; Cuisine.find(:first)
&lt;/code&gt;&lt;/pre&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/6n-kzgIAx4k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-activerecord-woes/</feedburner:origLink></entry><entry>
    <title>Disabling Sessions</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/8I5CQLZzWTQ/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-disabling-sessions</id>
    <updated>2010-10-21T05:45:55.000-07:00</updated>
    <summary><![CDATA[
This is part of a series on Rails 2 Upgrade Turbulence . Urbanspoon uses sessions to store various bits of information in the database that users might want to see again. We have a neat hack that Adam wrote to turn off sessions for bots so that we don't need to touch that table unless necessary. Unfortunately, his trick de...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;em&gt;This is part of a series on &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence"&gt;Rails 2 Upgrade Turbulence&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Urbanspoon uses sessions to store various bits of information in the database that users might want to see again. We have a neat hack that Adam wrote to &lt;a href="http://gurge.com/blog/2007/01/08/turn-off-rails-sessions-for-robots/"&gt;turn off sessions for bots&lt;/a&gt; so that we don't need to touch that table unless necessary.&lt;/p&gt;

&lt;p&gt;Unfortunately, his trick depends on the Rails 1.x ability to toggle sessions progammatically. Rails 2 opted for lazy loading – if you don't access it, it never gets loaded. There is, in fact, no out-of-the-box way to disable the session progammatically at request time.&lt;/p&gt;

&lt;p&gt;The trick I used to make this work is simple: choose the session store for a given request in a &lt;code&gt;before_filter&lt;/code&gt;. I made a simple session that dumps all its data into a Hash, but never persists anything.&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
# NoSession acts like a session, but doesn't get stored anywhere. Sneaky.
class NoSession &amp;lt; AbstractSession
  class &amp;lt;&amp;lt; self
    def find_session(session_id); end
    def create_session(session_id, data={})
      new(session_id, data)
    end
    def delete_all(condition=nil); end
  end

  def update_session(data); end
  def destroy; end
end    
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script src="http://gist.github.com/653039.js?file=no_session.rb"&gt;&lt;/script&gt;

&lt;p&gt;I then created a subclass of our session store (SqlSessionStore, in our case) that has a class-level toggle ("disabled") which it uses to choose the backing session class when it is called.&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
class OptionalSessionStore &amp;lt; SqlSessionStore

  cattr_accessor :enabled_session_class  
  cattr_accessor :disabled

  class &amp;lt;&amp;lt; self
    def disabled=(v)
      if self.disabled != v
        @@disabled = v
        self.toggle_session_class
      end
    end

    def toggle_session_class
      if self.disabled
        SqlSessionStore.session_class = NoSession
      else
        SqlSessionStore.session_class = self.enabled_session_class
      end
    end  
  end

  def call(env)
    # Make sure our disabled state is current
    self.class.toggle_session_class
    super(env)
  end
end
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script src="http://gist.github.com/653053.js?file=optional_session_store.rb"&gt;&lt;/script&gt;

&lt;p&gt;I now use a before filter to enable or disable sessions even for code paths that attempt to access them.&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
before_filter :toggle_session

def toggle_session    
  # Disable the session if we spy a bot (or it was disabled elsewhere), enable otherwise.
  if @disable_session.nil?
    @disable_session = UrbanspoonUtil.is_megatron?(request.user_agent)
  end
  OptionalSessionStore.disabled = @disable_session
end
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script src="http://gist.github.com/653049.js?file=toggle_session.rb"&gt;&lt;/script&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/8I5CQLZzWTQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-disabling-sessions/</feedburner:origLink></entry><entry>
    <title>General Cleanup</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/pcmJLbYd2nQ/" />
    <id>tag:threebrothers.org,2010-10-21:/brendan/blog/rails2-upgrade-general-cleanup</id>
    <updated>2010-10-21T05:31:37.000-07:00</updated>
    <summary><![CDATA[
This is part of a series on Rails 2 Upgrade Turbulence . Some generic cleanup tasks: @request/@params/etc are deprecated, drop the '@' everywhere. application.rb becomes application_controller.rb start_form_tag and end_form_tag are deprecated; use form_for instead. ActiveRecord associations have changed . Named routing has...]]>
</summary>
    <content type="html">
&lt;p&gt;&lt;em&gt;This is part of a series on &lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-turbulence"&gt;Rails 2 Upgrade Turbulence&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some generic cleanup tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@request/@params/etc are deprecated, drop the '@' everywhere.&lt;/li&gt;
&lt;li&gt;application.rb becomes application_controller.rb&lt;/li&gt;
&lt;li&gt;start_form_tag and end_form_tag are deprecated; use form_for instead.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://threebrothers.org/brendan/blog/rails2-upgrade-activerecord-woes/"&gt;ActiveRecord associations have changed&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Named routing has changed. Previously, every route created a method of the form 'some_page_url', which generated a relative path to the related url. Now, both 'some_page_url' and 'some_page_path' are generated. The _url method now gives an absolute url, while _path is relative.&lt;/li&gt;
&lt;li&gt;Most gems/plugins need to be upgraded or replaced. Yay for more current versions!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found these &lt;a href="http://www.slashdotdash.net/2007/12/03/rails-2-upgrade-notes/"&gt;Rails 2 Upgrade Notes&lt;/a&gt; to be pretty helpful.&lt;/p&gt;

&lt;p&gt;Also, there's nothing like a little &lt;code&gt;grep&lt;/code&gt;/&lt;code&gt;cut&lt;/code&gt;/&lt;code&gt;sed&lt;/code&gt; to make short work of replacing &lt;em&gt;en masse&lt;/em&gt;:&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
ack @request . | cut -d ':' -f 1 | uniq | xargs sed -i 's/@request/request/g'
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script src="http://gist.github.com/653085.js?file=replace.sh"&gt;&lt;/script&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/pcmJLbYd2nQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/rails2-upgrade-general-cleanup/</feedburner:origLink></entry><entry>
    <title>Bulk-loading associations with ActiveRecord</title>
    <link type="text/html" rel="alternate" href="http://feeds.threebrothers.org/~r/threebrothers/brendan/~3/PFeSZtogxCk/" />
    <id>tag:threebrothers.org,2010-09-13:/brendan/blog/bulk-loading-associations-with-active-record</id>
    <updated>2010-09-13T10:55:22.000-07:00</updated>
    <summary><![CDATA[
Here's a fairly common problem I've encountered. Say you have two classes; for example, a Restaurant and a Cuisine. They exist in a many-to-many relationship, and have associations defined like so: class Restaurant :delete_all has_many :cuisines, :through =&gt; :restaurant_cuisines end class Cuisine :delete_all has_many :rest...]]>
</summary>
    <content type="html">
&lt;p&gt;Here's a fairly common problem I've encountered. Say you have two
classes; for example, a Restaurant and a Cuisine. They exist in a
many-to-many relationship, and have associations defined like so:&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    class Restaurant &amp;lt; ActiveRecord::Base
      has_many :restaurant_cuisines, :dependent =&amp;gt; :delete_all
      has_many :cuisines, :through =&amp;gt; :restaurant_cuisines
    end

    class Cuisine &amp;lt; ActiveRecord::Base
      has_many :restaurant_cuisines, :dependent =&amp;gt; :delete_all
      has_many :restaurants, :through =&amp;gt; :restaurant_cuisines
    end

    class RestaurantCuisine &amp;lt; ActiveRecord::Base
      belongs_to :restaurant
      belongs_to :cuisine  
    end
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578503.js"&gt;&lt;/script&gt;    

&lt;p&gt;This is basically the model we use at Urbanspoon. &lt;/p&gt;

&lt;p&gt;Now, there are two interesting aspects to the data we have in this
relationship. First, Urbanspoon know about approximately 40x more 
Restaurants than Cuisines. Second, Cuisine popularity follows
a Zipf distribution. That is, the vast majority of Cuisines are
associated with very few Restaurants. However, the converse is not
true: we enforce that there be ~3 cuisines associated with every
Restaurant in the system.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Restaurant counts by Cuisine" src="http://threebrothers.org/brendan/blog/bulk-loading-associations-with-active-record/zipf-cuisines.png" /&gt;&lt;/p&gt;

&lt;p&gt;So, it turns out that the top 1000 Restaurants in Seattle comprise
about 70 distinct cuisines. That fits well with our graph from above,
and provides a good premise for this issue. Let's say we load these
1000 Restaurants and we'd like to display the Cuisines associated with
all of them. What's the best way to do this?&lt;/p&gt;

&lt;h2&gt;Naïve Attempt&lt;/h2&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    10.times do
      r = Restaurant.find(:all, :conditions =&amp;gt; ['id IN (?)', ids])
      r.map(&amp;amp;:cuisines).flatten.map(&amp;amp;:id)
    end

    # benchmarked 10 times
         user     system      total        real
    10.170000   0.470000  10.640000 ( 11.809886)
     9.630000   0.410000  10.040000 ( 11.076710)
    11.220000   0.520000  11.740000 ( 12.819519)
    11.140000   0.530000  11.670000 ( 12.702499)
    10.040000   0.520000  10.560000 ( 11.654553)
    10.680000   0.470000  11.150000 ( 12.250775)
    10.050000   0.700000  10.750000 ( 11.763682)
    11.020000   0.480000  11.500000 ( 12.893516)
    10.410000   0.590000  11.000000 ( 12.181406)
    11.460000   0.740000  12.200000 ( 13.326383)

    # memory diff from baseline IRB for each run [1]
    8712, 15000, 15092, 15204, 15260, 15324, 15360, 15392, 15424, 15428
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578505.js"&gt;&lt;/script&gt;

&lt;p&gt;This takes an average of ~12.25 seconds to complete &lt;em&gt;with a hot query
cache&lt;/em&gt;. True to intuition, naïve loading of associations
is dog slow in this scenario. We're duplicating work left and right,
both in database loading and in ActiveRecord instantiation. If one
Cuisine is referenced by N Restaurants, we pull it from the database N
times and create N objects with identical information.&lt;/p&gt;

&lt;h2&gt;Improved Attempt&lt;/h2&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    10.times do
      r = Restaurant.find(:all, :include =&amp;gt; [:cuisines], :conditions =&amp;gt; ['id IN (?)', ids])
      r.map(&amp;amp;:cuisines).flatten.map(&amp;amp;:id)
    end

    # benchmarked 10 times
        user     system      total        real
    5.540000   0.010000   5.550000 (  5.553716)
    5.560000   0.000000   5.560000 (  5.566566)
    5.670000   0.010000   5.680000 (  5.687871)
    5.670000   0.000000   5.670000 (  5.674870)
    5.580000   0.000000   5.580000 (  5.581576)
    5.670000   0.000000   5.670000 (  5.678692)
    5.570000   0.000000   5.570000 (  5.578353)
    5.630000   0.000000   5.630000 (  5.629657)
    5.740000   0.000000   5.740000 (  5.745029)
    5.560000   0.000000   5.560000 (  5.568952)

    # memory diff from baseline IRB for each run [1]
    8896, 14608, 14800, 14932, 15024, 15152, 15248, 15300, 15300, 15300
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578508.js"&gt;&lt;/script&gt;

&lt;p&gt;Great! We achieved an average speed of almost exactly twice as fast
(~5.63 seconds) by using ActiveRecord's built-in association
loading. But there are two problems with this approach. Firstly, it's
not very flexible or composable. That is, you can't build a handful
of specialized Restaurant-finding functions that are agnostic about
the decision to load Cuisines or not. You can't cache a list of
Restaurants and load the Cuisines later. Basically, if you want to be
efficient, you have to do the Cuisine loading at query time.&lt;/p&gt;

&lt;p&gt;The second issue is &lt;em&gt;still&lt;/em&gt; one of performance. Even though we only
load 73 Cuisine rows from the database, ActiveRecord still allocates
over 2000 unique Cuisine objects. See?&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    r.map(&amp;amp;:cuisines).flatten.map(&amp;amp;:object_id).uniq.length
     =&amp;gt; 2001
    r.map(&amp;amp;:cuisines).flatten.map(&amp;amp;:id).uniq.length
     =&amp;gt; 73
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578511.js"&gt;&lt;/script&gt;

&lt;p&gt;Oy. That means we're consuming roughly 27.4 times the memory and clock
cycles required to instantiate and retain Cuisines. So, what's the
&lt;em&gt;really&lt;/em&gt; right way to do this?&lt;/p&gt;

&lt;h2&gt;Bulk Loading, For Real&lt;/h2&gt;

&lt;p&gt;The pattern I've used is pretty simple. You query the two associations
separately, and then use an id-to-record map to squash them back
together in code. I did this in a few places in the iLike codebase,
and I found this example waiting for me at Urbanspoon. This final
version combines and improves on my previous attempts, and I have a
few comments to share about it later. But first, the code!&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    def Restaurant.add_cuisines(restaurants)
      return [] if restaurants.empty?

      ids = []
      id_map = {}
      restaurants.each do |r|
        id_map[r[:id]] = r
        ids &amp;lt;&amp;lt; r[:id]
        # make sure ActiveRecord won't try to load cuisines again
        r.cuisines.loaded
      end

      # make sure we load each Cuisine once
      cuisine_map = Hash.new {|h,id| h[id] = Cuisine.find(id)}

      RestaurantCuisine.find(:all,
          :conditions =&amp;gt; ["restaurant_id in (?)", ids]).each do |row|
        # use the association target so we don't do an insert
        id_map[row[:restaurant_id]].cuisines.target &amp;lt;&amp;lt; cuisine_map[row[:cuisine_id]]
      end

      return restaurants
    end
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578513.js"&gt;&lt;/script&gt;  

&lt;p&gt;OK, that seems reasonable enough. What are the times like?&lt;/p&gt;

&lt;noscript&gt;
  &lt;pre&gt;
    &lt;code&gt;
    10.times do
      r = Restaurant.find(:all, :conditions =&amp;gt; ['id IN (?)', ids])
      Restaurant.add_cuisines(r)
      r.map(&amp;amp;:cuisines).flatten.map(&amp;amp;:id)
    end

    # benchmarked 10 times
        user     system      total        real
    3.070000   0.040000   3.110000 (  3.148139)
    3.040000   0.030000   3.070000 (  3.133394)
    3.060000   0.050000   3.110000 (  3.160772)
    3.050000   0.040000   3.090000 (  3.178049)
    3.100000   0.010000   3.110000 (  3.169859)
    3.070000   0.030000   3.100000 (  3.174384)
    3.120000   0.040000   3.160000 (  3.259299)
    3.120000   0.030000   3.150000 (  3.238029)
    3.100000   0.040000   3.140000 (  3.241258)
    3.060000   0.030000   3.090000 (  3.135886)

    # memory diff from baseline IRB for each run [1]
    4388, 10112, 10180, 10252, 10316, 10364, 10408, 10496, 10540, 10472
    &lt;/code&gt;
  &lt;/pre&gt;
&lt;/noscript&gt;

&lt;script type="text/javascript" src="http://gist.github.com/578514.js"&gt;&lt;/script&gt;  

&lt;p&gt;Wow, an average of 3.18s! That's significantly faster than the
association loading version. And it uses far less memory, too. In
fact, that's the reason it's so much faster – you can shave off
43.5% of the total time just by instantiating each database row only
once. This is a total time reduction of 74% over the naïve
method.&lt;/p&gt;

&lt;p&gt;Additionally, this function can be called as an afterthought. You
can compose various functions and have them still perform well.
You can load Restaurants from any cache or other non-DB resource
and still fetch their associated Cuisines efficiently. Fun times.&lt;/p&gt;

&lt;h3&gt;Caveats&lt;/h3&gt;

&lt;p&gt;I mentioned that I had a few comments about this technique. Most of
them pertain to changes in ActiveRecord from Rails 1.x to Rails
2.x.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;See, the companies I've been working at have all been stuck on
Rails 1.1.6 – deplorable, I know. So, previous versions had a
line like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;id_map[row[:restaurant_id]].cuisines &amp;lt;&amp;lt; cuisine_map[row[:cuisine_id]] # note, *not* a call to .cuisines.target&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I'm upgrading Urbanspoon, and I discovered (thanks to unique key
constraints in the database – don't ever let anyone tell you
they're worthless) that modern versions of Rails will treat this
as an &lt;em&gt;insert&lt;/em&gt; statement. Yikes. Calling &lt;code&gt;.cuisines.target&lt;/code&gt; lets you
modify the array directly, rather than be intercepted by the
associations codebase.&lt;/p&gt;

&lt;p&gt;My bungling first attempt at working around this was to use
&lt;code&gt;instance_eval&lt;/code&gt; to completely override the association during the
ids-to-restaurants map building phase:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;r.instance_eval {&lt;/code&gt;
&lt;code&gt;@cuisines = []&lt;/code&gt;
&lt;code&gt;...&lt;/code&gt;
&lt;code&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a bad idea, as it litters your codebase with instances of
Restaurants whose associations may or may not behave correctly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The fact that each Restaurant now points to a single instance
of the same cuisine could lead to unexpected things. That is, if
Restaurants A and B both have the 'Chinese' cuisine, you can modify
the Cuisines of A and see the change reflected in B without saving
and reloading. This different than the normal associations behavior,
but I think it's acceptable, and perhaps even preferable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, I think this technique could be generalized easily and
added to ActiveRecord. I haven't researched whether others have
gone down this path before, so it's entirely possible that one
can do this already with a hip plugin that I haven't seen.&lt;/p&gt;

&lt;p&gt;I also don't know if the cloned vs. referenced issue of the
previous bullet point would be a problem with inclusion in
ActiveRecord. It is the heart of the performance gain, howerever,
and it is personally how I'd like associations in general to 
behave.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;sup&gt;[1]&lt;/sup&gt; In kilobytes; based on &lt;a href="http://laurelfan.com/2008/1/15/ruby-memory-usage"&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/threebrothers/brendan/~4/PFeSZtogxCk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://threebrothers.org/brendan/blog/bulk-loading-associations-with-active-record/</feedburner:origLink></entry>

</feed>

