<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Fixie Consulting's Blog</title>
  <subtitle>We are smart and hot</subtitle>
  <id>tag:fixieconsulting.com,1992-10-15:/</id>
  <link rel="self" type="application/atom+xml" href="http://fixieconsulting.com/atom.xml"/>
  <link rel="alternate" type="text/html" href="http://fixieconsulting.com/"/>
  <updated>2011-10-13T15:16:12-07:00</updated>
  <author>
    <name>Fixie Consulting</name>
    <email>info@fixieconsulting.com</email>
    <uri>http://fixieconsulting.com</uri>
  </author>

  <entry>
    <title>Chef Rocks</title>
    <id>tag:fixieconsulting.com,2009-09-23:1253684321</id>
    <link href="http://fixieconsulting.com/articles/chef.html"/>
    <updated>2009-09-23T05:38:41Z</updated>
    <published>2009-09-23T05:38:41Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe</a></div>
<div class='timestamp'>Published: September 22, 2009</div>
<p>
  I've been spending some time on
  <a href="http://wiki.opscode.com/display/chef/Home">Chef</a>
  recently.  It's slick stuff.  It's worth looking in to if you have
  to manage servers.
</p>
<p>
  It's amazing to don a software hat for doing operations.
</p>
]]></content>
  </entry>

  <entry>
    <title>Compensation: No Pay</title>
    <id>tag:fixieconsulting.com,2009-02-15:1234657611</id>
    <link href="http://fixieconsulting.com/articles/compensation-no-pay.html"/>
    <updated>2009-02-15T00:26:51Z</updated>
    <published>2009-02-15T00:26:51Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Jordan Isip</a></div>
<div class='timestamp'>Published: February 14, 2009</div>
<blockquote>
  <p>
    Looking for someone to build website, I have everything needed from godaddy I just don't
    have time. Need done ASAP.
  </p>
  <p>
    <em>Compensation: no pay</em>
  </p>
  <cite>
    - By Anonymous Craigslister
  </cite>
</blockquote>
<blockquote>
  <p>
    We are [...] in need of assistance with our Internet exposure. For now, this is an
    internship/volunteer position; however, if it works out well, it could prove to be very lucrative
    in the future.
  </p>
  <p>
    <em>Compensation: no pay</em>
  </p>
  <cite>
    - By Anonymous Craigslister
  </cite>
</blockquote>
<blockquote>
  <p>
    Our innovative online company is looking to expand, and believes that some programing and web
    building, can increase the bottom line significantly. [...] There is the possibility of ownership shares.
  </p>
  <p>
    <em>Compensation: no pay</em>
  </p>
  <cite>
    - By Anonymous Craigslister
  </cite>
</blockquote>
<h3 class='fake-tag'>&lt;rant&gt;</h3>
<p>The <a href="http://seattle.craigslist.org/cpg">Craigslist computer gigs section</a> is notorious for amount of 'work' promising unimaginable fame and wealth for 'no pay'.  If you are looking to post an ad for finding design/development work for no pay, here are a few suggestions from a web designer/developer perspective:</p>
<ul>
  <li>Know that creating a profitable website business takes more than a domain name and $7/mo hosting package.</li>
  <li>Saying 'it will be great addition to your portfolio' and 'possibility for riches' is not as enticing as you think it sounds.  As designers/developers, we have an abundance of projects to choose from when it comes to giving away our time and skills for free.  These include non-profits, personal side projects, friend's side projects, and open-source projects that will gladly take free work in exchange for a portfolio placement. As for ownership, shares in a company that don't make any revenue is worthless.  Explain the short-term and long-term benefits for the designer/developer.  Don't just say that your company will make money, describe the approach.</li>
  <li>Explain what <strong>you</strong> bring to the table. What is your role on the project? Are you a successful entrepreneur, do you have 15 years of experience in the field of your idea, or just someone with a far-fetched idea?</li>
  <li>Quit trying to get free work.  This is probably the most important suggestion, so read carefully. If you are looking for free work, be prepared to <strong>offer</strong> free work in return. Instead of 'compensation: no pay', how about offering a trade of services? Help with design/development in exchange for business plan writing and marketing advice.</li>
  <li>Keep in mind that you get what you pay (or trade) for.  You aren't going to be the next Google by having your friend's cousin's nephew build your free website on top of Wordpress.</li>
</ul>
<p>Keep these suggestions in mind when writing your next help ad.  I won't guarantee that this will find you any sort of decent talent, but you will undoubtedly have a better chance.</p>
<h3 class='fake-tag'>&lt;/rant&gt;</h3>
]]></content>
  </entry>

  <entry>
    <title>Concurrency's a Bitch</title>
    <id>tag:fixieconsulting.com,2009-01-03:1230975365</id>
    <link href="http://fixieconsulting.com/articles/concurrencys-a-bitch.html"/>
    <updated>2009-01-03T09:36:05Z</updated>
    <published>2009-01-03T09:36:05Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: January 3, 2009</div>
<p>
  On this Rails application I’m writing, I have a Person model.  When People are displayed
  to the user, the sort order is more complicated than a &lt;name asc&gt;
</p>
<ol>
  <li>First are featured People with a picture</li>
  <li>Then are featured People without a picture</li>
  <li>Then People with pictures and bio</li>
  <li>Then People with a picture</li>
  <li>Then People with a description</li>
  <li>Then People with an address and phone number</li>
  <li>And so on</li>
</ol>
<p>
  What I ended up doing is adding a “priority” integer attribute to the Person model.  On a
  method that runs before the Person is saved, it figures out what attributes the Person has,
  and then assigns a priority number to the Person.  I gave a priority value of 10 to featured
  People with a picture, a priority value of 9 to a featured Person without a picture, and
  so on.  Indexed this column and whammo, the sorting works great, just add an
  "ORDER BY priority DESC" SQL clause to your search statements.
</p>
<p>
  Then it occurred to me when I was in the shower: "What happens if the rules change and
  People should be ordered differently?"  It’s happened twice so far, but it’s no problem since
  the application hasn’t launched yet.  I make the code change to the module (PersonRules,
  need a better name) and then run:
</p>
<pre class='ruby' name='code'>Person.find(:all).each do |Person|&#x000A;  Person.priority = PersonRules.generate_priority(Person)&#x000A;  Person.save!&#x000A;end&#x000A;</pre>
<p>And that works. <em>Almost.</em></p>
<p>
  What happens if after you have loaded the Person objects in the find call and a user changes
  the name of Person while you’re looping through the People?
</p>
<p>
  Prior to Rails 2.2, which I haven’t really upgraded to yet for most of my applications, that
  change would be overridden<sup><a href="#fn1">1</a></sup>.  Say they update the name of the
  Person. But the above code loop has already loaded the original Person object into memory
  and is going to be operating on that data—the priority for the original Person object (with
  the old name) will be updated and then saved.  So the user’s change to the Person name would
  be overwritten with the old name and new priority.
</p>
<p>
  Ok, so you load the Person with "select for update" (I think in postgresql, don’t know if
  this syntax is what mysql uses).  You do this like:
</p>
<pre class='ruby' name='code'>Person.find(:all).each do |Person|&#x000A;  transaction do&#x000A;    Person.lock!&#x000A;    # now this bit of code is guaranteed to have an exclusive lock on the Person&#x000A;    # if another bit of code is updating the Person at the same time, the database&#x000A;    # will hang until it's done&#x000A;    Person.priority = PersonRules.generate_priority(Person)&#x000A;    Person.save!&#x000A;  end&#x000A;end&#x000A;</pre>
<p>This should work, afaik.  I don’t like it though:</p>
<ul>
  <li>You have to remember to lock the Person object whenever you do something like this.</li>
  <li>If generating the priority took a while, the Person object would be locked for a while.</li>
  <li>It adds more code.</li>
  <li>How do you test this?</li>
</ul>
<p>
  There’s another way to do this, that’s using optimistic locking.  You add a lock_version
  column to your model.  That version number is updated every time the Person object is updated.
  So in the above example, the Person object would be loaded with a lock_version of 10, then
  when the Person’s name is updated by another user, the lock_version would increment to 11,
  and then when the priority is generated and the original Person object is saved, ActiveRecord
  would notice that the lock_version value for the Person has been modified and would throw a
  nasty exception.
</p>
<p>
  Now that works, except that you have to be aware of the possibility of the exception and
  rescue it if you don’t want the request to die a fiery death.  Now, in most circumstances,
  not rescuing it would work just fine, since this type of problem wouldn’t happen more often,
  and it’s better to crash and burn as opposed to have the possibility of bad data.  So there’s
  a case to be made for always adding a lock_version column to all of the models that have the
  remote possibility of concurrent updates.
</p>
<p>
  But say you wanted something that didn’t require locking the Person object, or rescuing
  lock_version exceptions all the time.  I can think of a couple of options that <em>might</em>
  work—I have not tried them out yet.
</p>
<ul>
  <li>
    Add a version column to the Person model.  When the Person is updated, instead of updating
    the existing Person database row, insert a new one with the Person data and update the
    version number.  Then when you select the Person, add a "order by version desc".  Problem
    with this approach is that any other objects that refer to the Person would need to be
    updated with the new Person id.  But it has the advantage of keeping old versions of
    People around, you could then easily rollback or provide "undo" functionality.
  </li>
  <li>
    Add a new model: PersonPriority.  This would have two columns: person_id and priority.
    When you want to update the priority of the Person, you don’t have to modify the Person
    itself, you can update this model.  Problem: extra table/model, and doing a sort on the
    Person would be more complex.  (Can you do this indexing with sphinx?)
  </li>
</ul>
<p>How do you handle concurrency in your applications?  Am I missing any approaches here?</p>
<p>
  <sup>1</sup> I believe in Rails 2.2, Rails only updates the parts of models that change.
  So if only the name field of a Person has been changed, when the object is saved, only the
  name field update is included in the generated SQL update statement.
</p>
]]></content>
  </entry>

  <entry>
    <title>Enterprise Rails</title>
    <id>tag:fixieconsulting.com,2008-11-09:1226223365</id>
    <link href="http://fixieconsulting.com/articles/enterprise-rails.html"/>
    <updated>2008-11-09T09:36:05Z</updated>
    <published>2008-11-09T09:36:05Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: November 9, 2008</div>
<p>
  I recently picked up the book Enterprise Rails by Dan Chak.  It’s an excellent book,
  and was sorely needed by me. The biggest thing for me was that it explains how to use
  a good (i.e. PostgreSQL) database effectively and shows how to use materialized views,
  triggers, and so forth in a Rails application.
</p>
<p>
  It also delves into how to organize a large Rails application, separating your models
  into modules and then into standalone services. Afaik, no other book shows how to do
  this sort of stuff.
</p>
<p>
  We’re looking to apply it to this site. (note: not all the tests are counted, since
  "rake stats" only shows the specs, not the “historical” tests in the tests directory)
</p>
<pre>+----------------------+-------+-------+---------+---------+-----+-------+&#x000A;| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |&#x000A;+----------------------+-------+-------+---------+---------+-----+-------+&#x000A;| Libraries            |  1301 |  1003 |      24 |     168 |   7 |     3 |&#x000A;| Models               |  6112 |  4927 |     110 |     757 |   6 |     4 |&#x000A;| Helpers              |  1836 |  1575 |       0 |     176 |   0 |     6 |&#x000A;| Controllers          |  4342 |  3696 |      90 |     478 |   5 |     5 |&#x000A;| Model specs          |  2915 |  2417 |       2 |       9 |   4 |   266 |&#x000A;| View specs           |   370 |   301 |       0 |       1 |   0 |   299 |&#x000A;| Controller specs     |  1307 |  1043 |       0 |       4 |   0 |   258 |&#x000A;| Helper specs         |   432 |   286 |       0 |       0 |   0 |     0 |&#x000A;+----------------------+-------+-------+---------+---------+-----+-------+&#x000A;| Total                | 18615 | 15248 |     226 |    1593 |   7 |     7 |&#x000A;+----------------------+-------+-------+---------+---------+-----+-------+&#x000A;  Code LOC: 11201     Test LOC: 4047     Code to Test Ratio: 1:0.4</pre>
]]></content>
  </entry>

  <entry>
    <title>Setting Up Ubuntu</title>
    <id>tag:fixieconsulting.com,2008-11-09:1226223365</id>
    <link href="http://fixieconsulting.com/articles/setting-up-ubuntu.html"/>
    <updated>2008-11-09T09:36:05Z</updated>
    <published>2008-11-09T09:36:05Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: November 9, 2008</div>
<p>
  Although my preferred platform is OS X for personal stuff, I use Ubuntu Linux for work.
  I do all my work in Ubuntu via VMware Fusion.
</p>
<p>
  Great thing about Ubuntu is apt. It makes setting up the machine for development really
  easy. OS X has Mac Ports, but imo apt is better. Plus, working in a VM allows you to
  have multiple OS installs, allows you to backup your setup easily, you can take
  snapshots, and work on the same OS that you deploy your software to.
</p>
<p>
  Read on to read my notes on how to setup Ubuntu for work.
</p>
<ol>
  <li>Download Ubuntu 8.04 Server ISO from from http://mirrors.kernel.org/ubuntu-releases/8.04/ubuntu-8.04.1-server-i386.iso.</li>
  <li>Purchase / install VMware Fusion 2</li>
  <li>Create the VM, point the install disc to the downloaded Ubuntu ISO.</li>
  <li>Configure the VM, give it a lot of hard drive space. It doesn’t use all the hard drive space, but you want it to think that it has access to as much space as it needs. I gave it 50GB.</li>
  <li>Start the VM, press enter a bunch of times. Install process should be pretty easy.</li>
  <li>I enter “localhost.com” as the hostname. Read on to find out why.</li>
  <li>When it asks you what software to install, pick OpenSSH, PostgreSQL, and Samba.</li>
  <li>Reboot, login.</li>
  <li>Type in: sudo apt-get update This will update the package information on your system.</li>
  <li>Type in: sudo apt-get dist-upgrade This will update all the software.</li>
  <li>
    Install the software you work with. For me, I type in the following:
    <pre class='ruby' name='code'>sudo apt-get install ruby irb ri postgresql postgresql-server-dev-8.3 build-essential devscripts git-core vim imagemagick subversion libruby libruby-extras ghostscript curl wget openssh-server samba ruby1.8-dev apache2-prefork-dev apache2-mpm-prefork</pre>
  </li>
  <li>Note the VM’s IP address by running ifconfig -a . For me, the IP address 192.168.206.128.</li>
  <li>Add this line to your “host” (i.e. the physical OS) /etc/hosts file: 192.168.206.128 localhost.com . This allows you you to use localhost.com as the name of the machine – you don’t have to remember the IP address.</li>
  <li>See if you can ssh into localhost.com from your host machine. Hopefully you can.</li>
  <li>
    Install rubygems:
    <pre class='ruby' name='code'>curl http://rubyforge-files.ruby-forum.com/rubygems/rubygems-1.3.1.tgz | tar zxv && cd rubygems-1.3.1 && sudo ruby setup.rb && sudo ln -s /usr/bin/gem1.8 /usr/bin/gem</pre>
  </li>
  <li>Install any rubygems you work with. I install haml, capistrano, hoe, mongrel, and webby.</li>
  <li>Add yourself as a postgers user: sudo su postgres -c “createuser YOUR_USER_NAME”</li>
  <li>Install the apache phusion gem: sudo gem install passenger</li>
  <li>Install the apache phusion software: sudo /usr/bin/passenger-install-apache2-module</li>
</ol>
]]></content>
  </entry>

  <entry>
    <title>How to Dynamically Create ActiveRecord Classes</title>
    <id>tag:fixieconsulting.com,2008-08-23:1219484165</id>
    <link href="http://fixieconsulting.com/articles/how-to-dynamically-create-activerecord-classes.html"/>
    <updated>2008-08-23T09:36:05Z</updated>
    <published>2008-08-23T09:36:05Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: August 23, 2008</div>
<p>
  A question came up on IRC on someone commenting on how it was a pain to have a file
  for each ActiveRecord class if they were all really simple and basically the same.
  I cooked up the following code for him.
</p>
<pre class='ruby' name='code'>def create_activerecord_class table_name&#x000A;  Class.new(ActiveRecord::Base) do&#x000A;     set_table_name table_name&#x000A;  end&#x000A;end&#x000A;&#x000A;# I already have a users db table&#x000A;# So in the console...&#x000A;>> AnotherUser = create_activerecord_class(:users)&#x000A;=> AnotherUser(id: integer, first_name: string, last_name: string, ...... )&#x000A;&#x000A;>> AnotherUser.count&#x000A;=> 29605&#x000A;</pre>
<p>
  So, in your environment file (or some other appropriate place), you can create these
  classes with just one line of code per class. Of course, the method that creates the
  class can get more complicated - you could pass in options if the classes needed to
  differ from each other. This is a really simple example of the power of
  metaprogramming - writing code that writes code.
</p>
<p>
  Quite helpful if you don’t want to repeat yourself all the time.
</p>
]]></content>
  </entry>

  <entry>
    <title>Free Advertising for Amazing Software</title>
    <id>tag:fixieconsulting.com,2008-08-11:1218447095</id>
    <link href="http://fixieconsulting.com/articles/amazing-software.html"/>
    <updated>2008-08-11T09:31:35Z</updated>
    <published>2008-08-11T09:31:35Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: July 31, 2008</div>
<p>Software that we as a small web consulting company can not live without:</p>
<ul>
  <li>For keeping track of our tasks, we use <a href="http://pivotaltracker.com">Pivotal Tracker</a>.  The estimation and prioritizing features are what makes it work well for us.  And it’s free for now!</li>
  <li>To make and share documents and spreadsheets, <a href="http://docs.google.com">Google Docs</a> does the trick.!</li>
  <li>For email, good old <a href="http://www.google.com/a/">Google Apps</a>.</li>
  <li><a href="http://tickspot.com">Tickspot</a> lets us keep track of time spent on each client.</li>
  <li><a href="http://highrisehq.com">Highrise</a> keeps track of people that we know and what’s new with them.</li>
  <li><a href="http://engineyard.com">Engine Yard</a> keeps our websites and software running.  I love how they handle so much of the system administration work that I would otherwise have to do.</li>
  <li>For remote communication, <a href="http://www.adiumx.com/">Adium</a> rocks.  It’s a perfect instant messaging client.  Well, not quite perfect.  It needs to do video.</li>
  <li>For editing/programming, Jordan uses <a href="http://macromates.com/">TextMate</a>, Joe uses <a href="http://www.vim.org/">vim</a>.</li>
</ul>
]]></content>
  </entry>

  <entry>
    <title>Starling and Facebooker</title>
    <id>tag:fixieconsulting.com,2008-07-30:1217410565</id>
    <link href="http://fixieconsulting.com/articles/starling-and-facebooker.html"/>
    <updated>2008-07-30T09:36:05Z</updated>
    <published>2008-07-30T09:36:05Z</published>
    <content type="html"><![CDATA[<div class='byline'>By <a href="/contact.html">Joe Van Dyk</a></div>
<div class='timestamp'>Published: July 30, 2008</div>
<p>
  It’s really important to make sure that your Rails controllers complete their actions quickly.
  If you have some code in their that takes a while to execute (say, a remote network call), you
  need to have that stuff done in a different process or thread.
</p>
<p>
  For <a href="http://apps.facebook.com/dailycaption">Daily Caption</a>, we use
  <a href="http://http://rubyforge.org/projects/starling/">Starling</a> to queue up messages that
  need to get sent to Facebook.  Another program, creatively called "facebook_daemon" watches the
  Starling queue.
</p>
<p>So, you’ll want to install starling and memcached in the usual fashion.</p>
<p>Then, in <tt>config/initializers/starling.rb</tt>, put</p>
<pre class='ruby' name='code'>ports = { 'production' => "memcache-server:22122", &#x000A;          'development' => "localhost:22122", &#x000A;          'test' => "localhost:22122" }&#x000A;    &#x000A;STARLING = MemCache.new(ports[RAILS_ENV])&#x000A;</pre>
<p>To add stuff to the Starling queue, you can do stuff like:</p>
<pre class='ruby' name='code'>STARLING.set "key-of-some-sort", "value" &#x000A;</pre>
<p>
  In our FacebookPublisher model, we have the following method:
</p>
<pre class='ruby' name='code'>class FacebookPublisher > Facebooker::Rails::Publisher&#x000A;  def self.queue action, args&#x000A;    STARLING.set "facebook_actions", [action, *args]&#x000A;  end&#x000A;  # and more&#x000A;end&#x000A;</pre>
<p>
  If we need to update Facebook, say, with a updated comment notification,
  the following code does the trick:
</p>
<pre class='ruby' name='code'>FacebookPublisher.queue(:deliver_notify_caption_comment, self.caption, self)</pre>
<p>
  This adds, to the key “facebook_actions”, an array that looks like this:
</p>
<pre class='ruby' name='code'>[:deliver_notify_caption_comment, [self.caption, self]]</pre>
<p>
  You following?  At this point, we have that array stored in Starling.
  Now, it’s up to another program to monitor Starling and pop messages off its queue.
</p>
<pre class='ruby' name='code'>#!/usr/bin/env ruby&#x000A;require 'rubygems'&#x000A;require 'daemons'&#x000A;require File.dirname(__FILE__) + "/../config/environment" &#x000A;&#x000A;class FacebookDaemon&#x000A;  TIMEOUT = 5&#x000A;&#x000A;  def self.do_publisher_things args&#x000A;    puts "Running FB publisher" &#x000A;    puts args.inspect&#x000A;    action = args.first&#x000A;    args = args[1..-1]&#x000A;    Timeout.timeout(TIMEOUT) { FacebookPublisher.send action, *args}&#x000A;  end&#x000A;&#x000A;  def self.do_profile_updates args&#x000A;    puts "Doing profile update" &#x000A;    puts args.inspect&#x000A;    user, fb_user, content = args&#x000A;    Timeout.timeout(TIMEOUT) { fb_user.profile_fbml = content }&#x000A;    Timeout.timeout(TIMEOUT) { user.update_friends! }&#x000A;  end&#x000A;&#x000A;  def self.update&#x000A;    begin&#x000A;      while fetch = STARLING.get("facebook_actions")         &#x000A;        do_publisher_things(fetch) &#x000A;      end&#x000A;      while fetch = STARLING.get("facebook_profile_update") &#x000A;        do_profile_updates(fetch)  &#x000A;      end&#x000A;    rescue StandardError => e&#x000A;      puts "**** EXCEPTION!!! "&#x000A;      puts e&#x000A;      puts e.backtrace.inspect&#x000A;    end&#x000A;  end&#x000A;&#x000A;end&#x000A;&#x000A;ActiveRecord::Base.logger = Logger.new STDOUT&#x000A;&#x000A;options = {&#x000A;  :app_name => "facebook_daemon",&#x000A;  :ARGV => ARGV,&#x000A;  :dir_mode => :normal,&#x000A;  :dir => File.expand_path(File.dirname(__FILE__) + '/../log'),&#x000A;  :multiple => false,&#x000A;  :backtrace => true,&#x000A;  :monitor => false&#x000A;}&#x000A;&#x000A;Daemons.run_proc("facebook_daemon", options) do&#x000A;  loop do&#x000A;    FacebookDaemon.update&#x000A;    sleep 1&#x000A;  end&#x000A;end&#x000A;</pre>
<p>
  It’s pretty straightforward stuff, <tt>FacebookDaemon.update</tt> is called once a second.
  The <tt>update</tt> method pops stuff off the Starling queue, and then calls
  <tt>do_publisher_things</tt> with whatever array was stored.  <tt>do_publisher_things</tt>
  knows that the method is the first thing in the array, so calls that method.  Hence,
  <tt>FacebookPublisher.deliver_notify_caption_comment</tt> (or whatever is on the queue to be
  called) is called, and Facebook gets sent the call.
</p>
<p>
  If you keep the slow code out of the Rails request cycle, everyone will be happy.
  I’ve outlined one strategy, but there are more.  We also use
  <a href="http://codeforpeople.rubyforge.org/svn/bj/trunk/README">BackgroundJob</a>
  to move slow stuff out of the cycle.
</p>
]]></content>
  </entry>
</feed>

