<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Ryan Tomayko</title>
  <link href="http://tomayko.com/feed/" rel="self" type="application/atom+xml"/>
  <link href="http://tomayko.com/" rel="alternate" type="text/html"/>
  <id>http://tomayko.com/feed</id>
  <updated>2012-04-02T17:47:58-07:00</updated>
  <author>
    <name>Ryan Tomayko</name>
    <uri>http://tomayko.com/</uri>
    <email>r@tomayko.com</email>
  </author>
  
  <entry>
    <title>Show How, Don't Tell What - A Management Style</title>
    <id>tag:naeblis.cx,2003:management-style</id>
    <published>2012-04-02T00:00:00-07:00</published>
    <updated>2012-04-02T00:00:00-07:00</updated>
    <link href="http://tomayko.com/writings/management-style" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;An Management Style&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;One of the things I'm most excited about working at GitHub is the opportunity to
take our time and think through organization and process problems from first
principle instead of blindly copying other companies or adopting status quo
approaches developed in the last century. We're beholden to no one except the
good people that pay us for our products and that gives us the freedom to build
a company optimized for delivering the best experience - whatever it takes.&lt;/p&gt;




&lt;p&gt;Last year, as GitHub began to grow rapidly, I was promoted to &lt;em&gt;Director of
Engineering&lt;/em&gt;. That makes me a manager of sorts. Gross, right? Actually, it's
turned out not to be very horrible at all. Like most things at GitHub, I was
given complete control and encouraged and expected to define the role in
whatever way made most sense to me. I want to share some of what I've come up
with.&lt;/p&gt;




&lt;h3&gt;Don't tell people what to do&lt;/h3&gt;




&lt;p&gt;I've never actually told anyone &lt;em&gt;what to do&lt;/em&gt; here. In fact, I vehemently
refuse to tell people what to do. Here are just a couple reasons why:&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I don't scale. If I tell someone what to do and they do it, then what? Do I
have to tell them another thing to do? What happens when I have to decide
what to do for 20 people?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Telling people what to do is lazy. Instead, try to convince them with
argument. This is how humans interact when there's no artificial authority
structure and it works great. If you can't convince people through argument
then maybe you shouldn't be doing it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;So if I don't tell people what to do, then what purpose do I serve and what
exactly do I do all day?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;I show people how to plan, build, and ship product together.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Essentially, I try to create little mini-managers, each responsible for managing
a single person: their self. At first this is mainly about teaching people how
to figure out what to work on right now (prioritization). Then it's more a
matter of building their confidence both in themselves and their team to a point
where they just do things they know is right without even talking to me
(autonomy).&lt;/p&gt;




&lt;h3&gt;Lead by example as loud as possible&lt;/h3&gt;




&lt;p&gt;I actually don't show people how to make decisions and ship product in any real
direct way. There's no How To Ship Product training class or anything like that.
Instead, I just do work.&lt;/p&gt;




&lt;p&gt;I write down ideas and then market them internally. I ask designers about their
comps and concept work. I write code with kick ass docs and tests, sometimes
while building out the backend for a feature and sometimes just to clean shit up
because it needs it. I deploy responsibly because site stability is job number
zero. I soft ship new features and try to get other employees to use them. I
write and review blog posts and ship features. I fix bugs. I work with
support.&lt;/p&gt;




&lt;p&gt;That's just how you ship software product in 2012.&lt;/p&gt;




&lt;p&gt;The only thing that may be unique and interesting about the way I do it is that
I insist on being extremely &lt;em&gt;visible&lt;/em&gt; throughout the entire process. That means
removing sidebar conversations, private meetings, face time, IM, private
pairing, and anything else that limits the visibility of work and process.&lt;/p&gt;




&lt;p&gt;Just forcing people to be open and electronic where I'm concerned goes a long
way in keeping things managed because work at every stage of the product cycle
is in everyones face all the time. For one, people tend to self manage when
everyone else can see what they're doing. Also, other people jump in when they
notice something amiss. Finally, everyone learns when anyone makes a mistake
or does something brilliant.&lt;/p&gt;




&lt;p&gt;If a &quot;management style&quot; is something I have, this openness doctrine would be the
cornerstone.&lt;/p&gt;




&lt;h3&gt;Get people contributing&lt;/h3&gt;




&lt;p&gt;When someone is new to the process at GitHub, I make a concious effort to
&lt;a href=&quot;https://github.com/blog/821&quot;&gt;@mention&lt;/a&gt; them on issues, comments, and commits to
bring them into a bunch of different projects and discussions.&lt;/p&gt;




&lt;p&gt;When they first have an idea or feedback on something, I turn it around on them
and use the oldest trick from the open source playbook:&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&quot;Where's your patch?&quot;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In other words, go build the thing in your head, show me how you got there, and
then sell it to me and all your peers.&lt;/p&gt;




&lt;p&gt;I review their pull requests and try to imagine how they must be perceiving the
process, our product, our customers. When I think their perception is off, I
&lt;em&gt;say things&lt;/em&gt; to correct it. When I think they're really getting it, I &lt;em&gt;say
things&lt;/em&gt; to let them know they're on the right track.&lt;/p&gt;




&lt;h3&gt;Make everyone a manager&lt;/h3&gt;




&lt;p&gt;It's often cited that &lt;em&gt;GitHub doesn't have managers&lt;/em&gt;. In my opinion, a better
way to describe the phenomenon would be to say that &lt;em&gt;everyone at GitHub is a
manager&lt;/em&gt;. Instead of assigning 100% management duties to individuals, the basic
role of management is spread between 1.) every single employee, and 2.) a set of
custom in-house tools that serve to keep everyone in the know with regards to
other projects.&lt;/p&gt;




&lt;p&gt;This approach to management has real tangible benefits. Imagine 100% of your
&quot;workforce&quot; being able to operate at maximum productivity / efficiency &lt;em&gt;without
oversight&lt;/em&gt;. The only real requirement for work to be done is for people to be
sober (something we're working on).&lt;/p&gt;




&lt;p&gt;Imagine 100% of your &quot;workforce&quot; understanding every part of the product
delivery cycle and being able to make critical path decisions on the spot.&lt;/p&gt;




&lt;p&gt;Imagine what would happen if 100% of your &quot;workforce&quot; were &quot;decision makers&quot;.&lt;/p&gt;




&lt;p&gt;These are my goals right now.&lt;/p&gt;




&lt;h3&gt;Take a vacation&lt;/h3&gt;




&lt;p&gt;Today, I start back at work after 10 days on family vacation. This is the first
substantial bit of time I've had away since I started with GitHub almost three
years ago.&lt;/p&gt;




&lt;p&gt;Guess how many meetings I scheduled to make sure projects stayed on track while
I was away? Zero.&lt;/p&gt;




&lt;p&gt;I sent a blanket email the day before I left and asked for last minute concerns.
I received a single reply:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;Subject: Re: Hawaii
From: Chris Wanstrath &amp;lt;chris@github.com&amp;gt;
To: Ryan Tomayko &amp;lt;ryan@github.com&amp;gt;
Date: Thu, 22 Mar 2012 17:22:20 -0700

On Thu, Mar 22, 2012 at 2:37 PM, Ryan Tomayko &amp;lt;ryan@github.com&amp;gt; wrote:
&amp;gt; Guys, I'm heading to Hawaii tomorrow. I'll be there for a week and
&amp;gt; plan to be as AFK as possible. If there's anything pressing I owe you
&amp;gt; right now or stuff that'd help in my absence please let me know ASAP
&amp;gt; so I can move it up my list of shit to get done before I peace out.

Have fun.
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;GitHub had one of its most productive weeks in recent memory. I relaxed and had
fun on the beach.&lt;/p&gt;




&lt;p&gt;The one downside I've found in all this is that I'm apparently extremely
dispensable at this point. &lt;em&gt;Shrug.&lt;/em&gt; Maybe I should take more vacations.&lt;/p&gt;




&lt;p&gt;(&lt;a href=&quot;http://news.ycombinator.com/item?id=3789324&quot;&gt;comment&lt;/a&gt;)&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>AWK-ward Ruby</title>
    <id>tag:naeblis.cx,2003:awkward-ruby</id>
    <published>2011-04-26T00:00:00-07:00</published>
    <updated>2011-04-26T00:00:00-07:00</updated>
    <link href="http://tomayko.com/writings/awkward-ruby" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;From AWK to Ruby&lt;/p&gt;
</summary>
    <content type="html">&lt;p class='intro'&gt;
This essay was to be published as a companion piece to &lt;a href='http://shellhaters.heroku.com/'&gt;The Shell Hater's Handbook&lt;/a&gt;, an introductory talk on UNIX shell programming for Ruby hackers given at &lt;a href='http://gogaruco.com/'&gt;GoGaRuCo 2010&lt;/a&gt;. Alas, the post-conference wrap up magazine will not be published this year and so I'm making the essay available here instead.
&lt;/p&gt;




&lt;p&gt;Ruby, like most successful languages, was assembled from pieces of things that
came before it: Smalltalk's consistent object system, Perl's practical syntax,
UNIX's sensibilities. Not that it didn't bring entirely new innovations (&lt;del&gt;block
syntax!&lt;/del&gt; Smalltalk had block syntax first!) of its own, but it's amazing to consider how much of Ruby's design
rests on the elegant packaging of old concepts into a new coherent whole.&lt;/p&gt;




&lt;p&gt;There's something less obvious but perhaps more essential that Ruby borrowed:
the very concept of blatant, unashamed borrowing. In his 1999 talk, &lt;a href=&quot;http://www.perl.com/pub/1999/03/pm.html&quot;&gt;&lt;em&gt;Perl, the
first postmodern computer language&lt;/em&gt;&lt;/a&gt;, Larry Wall states plainly that Perl was
built mostly from things that &quot;didn't suck&quot; in the languages that preceded it:&lt;/p&gt;




&lt;blockquote&gt;&lt;p&gt;When I started designing Perl, I explicitly set out to deconstruct all the
computer languages I knew and recombine or reconstruct them in a different way,
because there were many things I liked about other languages, and many things I
disliked. I lovingly reused features from many languages. (I suppose a Modernist
would say I stole the features, since Modernists are hung up about originality.)
Whatever the verb you choose, I've done it over the course of the years from C,
sh, csh, grep, sed, awk, Fortran, COBOL, PL/I, BASIC-PLUS, SNOBOL, Lisp, Ada,
C++, and Python. To name a few. To the extent that Perl rules rather than sucks,
it's because the various features of these languages ruled rather than sucked.&lt;/p&gt;&lt;/blockquote&gt;




&lt;p&gt;Ruby, the story goes, borrowed much from Perl: integral regular expressions,
statement modifiers (&lt;code&gt;do_this if that&lt;/code&gt;), array/hash literals, funny global
variable names, and of course the philosophy of having more than one way to do
the same thing (TMTOWTDI).&lt;/p&gt;




&lt;p&gt;Or did it?&lt;/p&gt;




&lt;p&gt;If these features didn't originate with Perl, as Wall seems to imply, then where
did they come from?&lt;/p&gt;




&lt;p&gt;One of the most important influences on Perl's design was AWK. So much so that
Perl was sometimes described as a semantic superset of AWK. Are the relics of
AWK still present in Ruby? Let's see.&lt;/p&gt;




&lt;p&gt;Today, AWK is probably best known as a versatile tool for extracting fields from
delimited flat files in a shell pipeline:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;cat /etc/passwd | awk -F: '{ print $1 }'
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;It's rare to see AWK used for more complex problems in modern systems, but
there's actually a full blown programming language lurking beneath the surface.
It was at one time used to solve a lot of the same problems people commonly use
Ruby, Perl, or Python to solve today.&lt;/p&gt;




&lt;p&gt;You might find some of AWK's language features familiar:&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;Associative array type.&lt;/li&gt;
&lt;li&gt;Automatic string, integer, and floating point value types.&lt;/li&gt;
&lt;li&gt;C-style &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, and &lt;code&gt;do&lt;/code&gt; constructs.&lt;/li&gt;
&lt;li&gt;For-each style &lt;code&gt;for&lt;/code&gt; construct for iterating over associative arrays.&lt;/li&gt;
&lt;li&gt;Arithmetic (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;), modulu-division (&lt;code&gt;%&lt;/code&gt;), exponentiation (&lt;code&gt;^&lt;/code&gt;),
increment/decrement (&lt;code&gt;++&lt;/code&gt;, &lt;code&gt;--&lt;/code&gt;), and assignment shorthand (&lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;*=&lt;/code&gt;, ...)
operators.&lt;/li&gt;
&lt;li&gt;Array membership operator (&lt;code&gt;expr in array&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Integral regular expression type and matching operators (&lt;code&gt;str ~ /pattern/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Comprehensive builtin function library (a small sample: &lt;code&gt;printf&lt;/code&gt;, &lt;code&gt;gsub&lt;/code&gt;,
&lt;code&gt;split&lt;/code&gt;, &lt;code&gt;substr&lt;/code&gt;, &lt;code&gt;cos&lt;/code&gt;, &lt;code&gt;sin&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;sqrt&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;User defined functions.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Not bad for 1977.&lt;/p&gt;




&lt;p&gt;It would seem that a large portion of Ruby's basic syntax and semantics were
present in AWK. So how did Perl come to dominate the problem space? There must
be something very &lt;em&gt;different&lt;/em&gt; about AWK.&lt;/p&gt;




&lt;p&gt;While AWK had much of the primitive syntax right, it also overcompensated for a
specific case: processing streams of delimited text. The top-level context is
used exclusively for declaring one or more matching statements:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;pattern { action }
...
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;Here, &lt;code&gt;pattern&lt;/code&gt; is a full blown expression and &lt;code&gt;action&lt;/code&gt; is a block of code
executed when &lt;code&gt;pattern&lt;/code&gt; evaluates truthfully. The &lt;code&gt;pattern&lt;/code&gt; is tested for each
line (or record) of input and &lt;code&gt;action&lt;/code&gt; is executed when &lt;code&gt;pattern&lt;/code&gt; returns
truthfully.  Omitting the &lt;code&gt;pattern&lt;/code&gt; causes the action to be executed for every
line.&lt;/p&gt;




&lt;p&gt;There's special patterns for setting actions up to run before the first line of
input is read and after all lines have been processed. Here's an example that
uses the special &lt;code&gt;BEGIN&lt;/code&gt; pattern along with a regular expression match. It
prints all the usernames from &lt;code&gt;/etc/passwd&lt;/code&gt; while avoiding comment lines:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;cat /etc/passwd |
awk '
    BEGIN     { FS = &quot;:&quot; }
    /^[a-z_]/ { print $1 }
'
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;(NOTE: You can paste bomb that into your shell on just about any UNIX system.)&lt;/p&gt;




&lt;p&gt;Here's a more complex example that shows off some of AWK's advanced features,
like associative arrays and for-in syntax. It calculates word frequencies from
the text of Jonathan Swift's, &lt;em&gt;A Modest Proposal&lt;/em&gt;:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;curl -s http://www.gutenberg.org/files/1080/1080.txt |
awk '
    BEGIN { FS=&quot;[^a-zA-Z]+&quot; }

    {
        for (i=1; i&amp;lt;=NF; i++) {
            word = tolower($i)
            words[word]++
        }
    }

    END {
        for (w in words)
             printf(&quot;%3d %s\n&quot;, words[w], w)
    }
' |
sort -rn
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;It may seem strange, but this style of programming was very common in UNIX's
hayday. Instead of programs being dominated by a single language like Perl or
Ruby, you'd build pipelines that combined standard utilities (like &lt;code&gt;sort&lt;/code&gt; shown
above), sprinkle in bits and pieces of AWK as needed, and drop down to C when
performance was critical.&lt;/p&gt;




&lt;p&gt;Perl took the guts of AWK and left behind the mandatory pattern matching at the
top-level. That simple design change turned what was a special purpose language
for processing delimited text streams into what we know today as a &lt;em&gt;general
purpose scripting language&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;But that's not the end of the story.&lt;/p&gt;




&lt;p&gt;It was important that Perl be able to act as a replacement for AWK in all its
capacities, including within shell pipelines. This meant having the ability to
run &lt;code&gt;perl&lt;/code&gt; in a kind of top-level AWK mode. Ruby borrowed this capability from
Perl, making it possible to use Ruby for the same style of programming
facilitated by AWK, complete with &lt;code&gt;BEGIN&lt;/code&gt; and &lt;code&gt;END&lt;/code&gt; blocks!&lt;/p&gt;




&lt;p&gt;Here's the word frequency script in AWK-ish Ruby:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;curl -s http://www.gutenberg.org/files/1080/1080.txt |
ruby -ne '
  BEGIN { $words = Hash.new(0) }

  $_.split(/[^a-zA-Z]+/).each { |word| $words[word.downcase] += 1 }

  END {
    $words.each { |word, i| printf &quot;%3d %s\n&quot;, i, word }
  }
' |
sort -rn
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; argument causes Ruby to assume a &lt;code&gt;while gets(); ... end&lt;/code&gt; loop around
the provided script. &lt;code&gt;$_&lt;/code&gt; is set to the last line read and the &lt;code&gt;BEGIN&lt;/code&gt; and &lt;code&gt;END&lt;/code&gt;
blocks function exactly as they did in AWK.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>I like Unicorn because it's Unix</title>
    <id>tag:naeblis.cx,2003:unicorn-is-unix</id>
    <published>2009-10-06T00:00:00-07:00</published>
    <updated>2009-10-06T00:00:00-07:00</updated>
    <link href="http://tomayko.com/writings/unicorn-is-unix" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;Eric Wong's mostly pure-Ruby HTTP backend, &lt;a href=&quot;http://unicorn.bogomips.org/&quot; title=&quot;Unicorn: Rack HTTP server for Unix and fast clients&quot;&gt;Unicorn&lt;/a&gt;, is an
inspiration. I've studied &lt;a href=&quot;http://github.com/rtomayko/unicorn/blob/master/lib/unicorn.rb&quot; title=&quot;lib/unicorn.rb - teh source, bitches.&quot;&gt;this file&lt;/a&gt; for a couple of days
now and it's undoubtedly one of the best, most densely packed
examples of Unix programming in Ruby I've come across.&lt;/p&gt;

&lt;p&gt;Unicorn is basically &lt;a href=&quot;http://mongrel.rubyforge.org/&quot;&gt;Mongrel&lt;/a&gt; (including the fast Ragel/C
HTTP parser), minus the threads, and with teh Unix turned up to
11. That means processes. And all the tricks and idioms required
to use them reliably.&lt;/p&gt;

&lt;p&gt;We're going to get into how Unicorn uses the OS kernel to balance
connections between backend processes using a shared socket,
&lt;code&gt;fork(2)&lt;/code&gt;, and &lt;code&gt;accept(2)&lt;/code&gt; -- the basic Unix prefork model in
100% pure Ruby.&lt;/p&gt;

&lt;p&gt;But first ...&lt;/p&gt;
</summary>
    <content type="html">&lt;div style='text-align:center;margin-top:-17px'&gt;
&lt;img border=&quot;0&quot; title=&quot;This isn't really the official Unicorn mascot, but it should be.&quot; src=&quot;http://images-2.redbubble.com/img/clothing/bodycolor:white/size:medium/style:mens/view:main/76841-16-the-wrong-unicorn-t-shirt.jpg&quot; width='300' height='300'&gt;
&lt;/div&gt;




&lt;p&gt;Eric Wong's mostly pure-Ruby HTTP backend, &lt;a href=&quot;http://unicorn.bogomips.org/&quot; title=&quot;Unicorn: Rack HTTP server for Unix and fast clients&quot;&gt;Unicorn&lt;/a&gt;, is an
inspiration. I've studied &lt;a href=&quot;http://github.com/rtomayko/unicorn/blob/master/lib/unicorn.rb&quot; title=&quot;lib/unicorn.rb - teh source, bitches.&quot;&gt;this file&lt;/a&gt; for a couple of days
now and it's undoubtedly one of the best, most densely packed
examples of Unix programming in Ruby I've come across.&lt;/p&gt;




&lt;p&gt;Unicorn is basically &lt;a href=&quot;http://mongrel.rubyforge.org/&quot;&gt;Mongrel&lt;/a&gt; (including the fast Ragel/C
HTTP parser), minus the threads, and with teh Unix turned up to
11. That means processes. And all the tricks and idioms required
to use them reliably.&lt;/p&gt;




&lt;p&gt;We're going to get into how Unicorn uses the OS kernel to balance
connections between backend processes using a shared socket,
&lt;code&gt;fork(2)&lt;/code&gt;, and &lt;code&gt;accept(2)&lt;/code&gt; -- the basic Unix prefork model in
100% pure Ruby.&lt;/p&gt;




&lt;p&gt;But first ...&lt;/p&gt;




&lt;h2&gt;A note about Unix programming in Ruby in general&lt;/h2&gt;




&lt;p&gt;We should be doing more of this. A lot more of this. I'm talking
about
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/fork.2.html&quot;&gt;&lt;code&gt;fork(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/execve.2.html&quot;&gt;&lt;code&gt;execve(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/pipe.2.html&quot;&gt;&lt;code&gt;pipe(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/socketpair.2.html&quot;&gt;&lt;code&gt;socketpair(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/select.2.html&quot;&gt;&lt;code&gt;select(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/kill.2.html&quot;&gt;&lt;code&gt;kill(2)&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html&quot;&gt;&lt;code&gt;sigaction(2)&lt;/code&gt;&lt;/a&gt;,
and &lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/syscalls.2.html&quot;&gt;so on and so forth&lt;/a&gt;. These are our friends.
They want so badly just to help us.&lt;/p&gt;




&lt;p class='note'&gt;
&lt;strong&gt;NOTE&lt;/strong&gt; The links above are to &lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/dir_section_2.html&quot;&gt;Linux section 2 manpages&lt;/a&gt;; in many cases, &lt;a href=&quot;http://www.freebsd.org/cgi/man.cgi?query=intro&amp;sektion=2&amp;apropos=0&amp;manpath=FreeBSD+7.2-RELEASE&quot;&gt;BSD manpages&lt;/a&gt; are vastly superior.
&lt;/p&gt;




&lt;p&gt;Ruby, Python, and Perl all have fairly complete interfaces to
common Unix system calls as part of their standard libraries.  In
most cases, the method names and signatures match the POSIX
definitions exactly. Yet, of the groups, only the Perl people
seem to regularly (and &lt;em&gt;happily&lt;/em&gt;) apply common Unix idioms to a
wide range of problem areas.&lt;/p&gt;




&lt;p&gt;Unix is not one of the &quot;perlisms&quot; Ruby should be trying to
distance itself from. Perl got that part right. And with
immediately recognizable Unix system calls spewed all over the
core library, Ruby feels like it was built for Unix hacking.
It's surprising to see how infrequently this stuff is used as
intended or even talked about.&lt;/p&gt;




&lt;h2&gt;man 2 intro&lt;/h2&gt;




&lt;p&gt;Documentation is likely part of the problem. Here's a small
sample of Ruby core docs on an assortment of Unix system calls --
the kind we don't use enough:&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ruby-doc.org/docs/rdoc/1.9/classes/Process.html#M001449&quot;&gt;&lt;code&gt;Process::fork&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; - oh, sorry, see &lt;a href=&quot;http://www.ruby-doc.org/docs/rdoc/1.9/classes/Kernel.html#M001603&quot;&gt;&lt;code&gt;Kernel::fork&lt;/code&gt;&lt;/a&gt; ... pitiful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ruby-doc.org/docs/rdoc/1.9/classes/Kernel.html#M001602&quot;&gt;&lt;code&gt;Kernel::exec&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; - really?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ruby-doc.org/docs/rdoc/1.9/classes/Process.html#M001453&quot;&gt;&lt;code&gt;Process::kill&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; - thanks!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ruby-doc.org/docs/rdoc/1.9/classes/IO.html#M001074&quot;&gt;&lt;code&gt;IO::pipe&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; - not bad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Socket::socketpair&lt;/code&gt;&lt;/strong&gt; - entirely undocumented, sorry.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That Ruby provides no useful documentation isn't actually a
problem &lt;em&gt;if&lt;/em&gt; you happen to have experience programming Unix.
Then you would of course just happen to know that there's a
secret manual section with extensive reference information on
each of these commands.&lt;/p&gt;




&lt;p&gt;Here's a snippet of the (BSD) manpage for &lt;code&gt;pipe(2)&lt;/code&gt; as shipped with
MacOS X (also: &lt;a href=&quot;http://www.kernel.org/doc/man-pages/online/pages/man2/pipe.2.html&quot;&gt;Linux version&lt;/a&gt;):&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;$ man 2 pipe
PIPE(2)                     BSD System Calls Manual                    PIPE(2)

NAME
     pipe -- create descriptor pair for interprocess communication

SYNOPSIS
     #include &amp;lt;unistd.h&amp;gt;

     int
     pipe(int fildes[2]);

DESCRIPTION
     The pipe() function creates a pipe (an object that allows unidirectional
     data flow) and allocates a pair of file descriptors.  The first descriptor
     connects to the read end of the pipe; the second connects to the write end.

     Data written to fildes[1] appears on (i.e., can be read from) fildes[0].
     This allows the output of one program to be sent to another program: the
     source's standard output is set up to be the write end of the pipe; the
     sink's standard input is set up to be the read end of the pipe.  The pipe
&amp;lt;snip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;Most Ruby developers probably don't have a background in Unix C
programming. How are they supposed to know that all those
undocumented parts of the standard library are undocumented
because -- &lt;em&gt;DUH!&lt;/em&gt; -- you just have to go enter &lt;code&gt;man 2 THING&lt;/code&gt; into
the console. Obviously.&lt;/p&gt;




&lt;h2&gt;Threads are out&lt;/h2&gt;




&lt;p&gt;There's another problem with Unix programming in Ruby that I'll
just touch on briefly: &lt;em&gt;Java people&lt;/em&gt; and &lt;em&gt;Windows people&lt;/em&gt;.
They're going to tell you that &lt;code&gt;fork(2)&lt;/code&gt; is bad because they
don't have it on their platform, or it sucks on their platform,
or whatever, but it's cool, you know, because they have native
threads, and threads are like, &lt;em&gt;way&lt;/em&gt; better anyways.&lt;/p&gt;




&lt;p&gt;Fuck that.&lt;/p&gt;




&lt;p&gt;Don't ever let anyone tell you that &lt;code&gt;fork(2)&lt;/code&gt; is bad. Thirty
years from now, there will still be a &lt;code&gt;fork(2)&lt;/code&gt; and a &lt;code&gt;pipe(2)&lt;/code&gt;
and a &lt;code&gt;exec(2)&lt;/code&gt; and smart people will still be using them to
solve hard problems reliably and predictably, just like they were
thirty years ago.&lt;/p&gt;




&lt;p&gt;MRI Ruby people need to accept, &lt;a href=&quot;http://mail.python.org/pipermail/python-3000/2007-May/007414.html&quot; title=&quot;Guido van Rossum: “Just because Java was once aimed at a set-top box OS that didn't support multiple address spaces, and just because process creation in Windows used to be slow as a dog, doesn't mean that multiple processes (with judicious use of IPC) aren't a much better approach to writing apps for multi-CPU boxes than threads.”&quot;&gt;like Python&lt;/a&gt; (you have seen
&lt;a href=&quot;http://docs.python.org/dev/library/multiprocessing.html#module-multiprocessing&quot; title=&quot;multiprocessing — Process-based “threading” interface&quot;&gt;multiprocessing&lt;/a&gt;, yes?), that Unix processes are one of two
techniques for achieving reliable concurrency and parallelism in
server applications. Threads are out. You can use processes, or
&lt;a href=&quot;http://eventmachine.rubyforge.org/&quot; title=&quot;EventMachine! (or roll your own select loop. whatever.)&quot;&gt;async/events&lt;/a&gt;, or both processes and async/events, but
&lt;a href=&quot;http://timetobleed.com/ruby-hoedown-slides/&quot;&gt;definitely not threads&lt;/a&gt;. Threads are out.&lt;/p&gt;




&lt;h2&gt;Anyway, Unicorn.&lt;/h2&gt;




&lt;p&gt;Unicorn, and preforking servers in general, create a listening
socket in a parent process and then fork off one or more child
processes, each of which calls &lt;code&gt;accept(2)&lt;/code&gt; on the same shared
listening socket. The kernel manages the task of distributing
connections between accepting processes.&lt;/p&gt;




&lt;p&gt;Let's start with a simplified example. A simple echo server that
balances connections between three child processes:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;# simple preforking echo server in Ruby
require 'socket'

# Create a socket, bind it to localhost:4242, and start listening.
# Runs once in the parent; all forked children inherit the socket's
# file descriptor.
acceptor = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
address = Socket.pack_sockaddr_in(4242, 'localhost')
acceptor.bind(address)
acceptor.listen(10)

# Close the socket when we exit the parent or any child process. This
# only closes the file descriptor in the calling process, it does not
# take the socket out of the listening state (until the last fd is
# closed).
#
# The trap is guaranteed to happen, and guaranteed to happen only
# once, right before the process exits for any reason (unless
# it's terminated with a SIGKILL).
trap('EXIT') { acceptor.close }

# Fork you some child processes. In the parent, the call to fork
# returns immediately with the pid of the child process; fork never
# returns in the child because we exit at the end of the block.
3.times do
  fork do
    # now we're in the child process; trap (Ctrl-C) interrupts and
    # exit immediately instead of dumping stack to stderr.
    trap('INT') { exit }

    puts &quot;child #$$ accepting on shared socket (localhost:4242)&quot;
    loop {
      # This is where the magic happens. accept(2) blocks until a
      # new connection is ready to be dequeued.
      socket, addr = acceptor.accept
      socket.write &quot;child #$$ echo&amp;gt; &quot;
      socket.flush
      message = socket.gets
      socket.write message
      socket.close
      puts &quot;child #$$ echo'd: '#{message.strip}'&quot;
    }
    exit
  end
end

# Trap (Ctrl-C) interrupts, write a note, and exit immediately
# in parent. This trap is not inherited by the forks because it
# runs after forking has commenced.
trap('INT') { puts &quot;\nbailing&quot; ; exit }

# Sit back and wait for all child processes to exit.
Process.waitall
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;Run that with &lt;code&gt;ruby echo.rb&lt;/code&gt; and then connect a few times with
&lt;a href=&quot;http://netcat.sourceforge.net/&quot;&gt;netcat&lt;/a&gt;:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;$ echo &quot;hello world&quot; | nc localhost 4242
child 86900 echo&amp;gt; hello world

$ echo &quot;hello world&quot; | nc localhost 4242
child 86901 echo&amp;gt; hello world

$ echo &quot;hello world&quot; | nc localhost 4242
child 86902 echo&amp;gt; hello world

...
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;Use &lt;code&gt;telnet&lt;/code&gt; if you don't have netcat:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;$ telnet localhost 4242
telnet localhost 4242
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
child 86902 echo&amp;gt; hello world
hello world

$ telnet localhost 4242
...
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;This isn't exactly what Unicorn does but it nicely illustrates
one of the basic concepts underlying the design. This technique
can be used for simple network servers as above, or it could be
used for general IPC-based balanced multiprocessing. For example,
you could connect directly to the shared socket in the parent
process to distribute work between a set of child processes.&lt;/p&gt;




&lt;h2&gt;Unicorns do it with &lt;code&gt;select(2)&lt;/code&gt;&lt;/h2&gt;




&lt;p&gt;Instead of a blocking &lt;code&gt;accept(2)&lt;/code&gt;, Unicorn uses a blocking
&lt;code&gt;select(2)&lt;/code&gt; with an error pipe and a timeout so that it can bust
out and do some other basic housekeeping, like reopening logs,
processing signals, and maintaining a heartbeat with the master
process.&lt;/p&gt;




&lt;p&gt;You can watch this play out in &lt;a href=&quot;http://github.com/rtomayko/unicorn/blob/eef8d4c4332078ce28959b4afc5870c71a820fdb/lib/unicorn.rb#L532-596&quot; title=&quot;Unicorn's forked worker select/accept loop&quot;&gt;&lt;code&gt;Unicorn::HttpServer#worker_loop&lt;/code&gt;&lt;/a&gt;,
the heart of each Unicorn child/worker process. Most notable is the
following call to &lt;code&gt;select(2)&lt;/code&gt;:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;ret = IO.select(LISTENERS, nil, SELF_PIPE, timeout) or redo
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;This blocks until one of three things happen:&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A connection is pending on the shared listening socket (passed
in the &lt;code&gt;LISTENERS&lt;/code&gt; array) and is ready to be dequeued by
&lt;code&gt;accept(2)&lt;/code&gt;, in which case the ready socket is returned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some notable error state occurs on the file descriptor in
&lt;code&gt;SELF_PIPE&lt;/code&gt; (like when it's closed), in which case the child's
side of the pipe is returned as an IO object. This really
deserves its own essay, but I'll take a quick shot: the IO object
in &lt;code&gt;SELF_PIPE&lt;/code&gt; is created in the parent process with &lt;code&gt;pipe(2)&lt;/code&gt;
(&lt;code&gt;IO.pipe&lt;/code&gt;) before the children are forked off. The children then
write on the pipe to achieve basic one-way IPC between child and
master. It's used here in the call to &lt;code&gt;select(2)&lt;/code&gt; to detect the
master going down unexpectedly - parent death causes the pipe to
close. Unicorn children go down fast when their master dies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The timeout elapses.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;If &lt;code&gt;select(2)&lt;/code&gt; returns due the first condition, the child process
calls &lt;code&gt;Socket#accept_nonblock&lt;/code&gt; on the shared listening socket,
which either returns a newly established connection or fails with
&lt;code&gt;Errno::EAGAIN&lt;/code&gt;, signaling that some other child process beat us
to the &lt;code&gt;accept(2)&lt;/code&gt;. In either case, accept returns immediately
and does not block.&lt;/p&gt;




&lt;p&gt;This is just &lt;a href=&quot;http://unicorn.bogomips.org/DESIGN.html&quot; title=&quot;Unicorn's DESIGN - 15 bullets of goodness&quot;&gt;one of many beautiful Unix idioms&lt;/a&gt; you'll find
in Unicorn. The &lt;a href=&quot;http://unicorn.bogomips.org/SIGNALS.html&quot;&gt;signal handling&lt;/a&gt;,
hot process replacement/reloading with rollback, the &lt;code&gt;SELF_PIPE&lt;/code&gt; IPC technique,
and the &lt;code&gt;fchmod(2)&lt;/code&gt; based heartbeat implementation are at least as
interesting. Check it out.&lt;/p&gt;




&lt;p class='note'&gt;
Comments will be broken here for a while. There's a discussion brewing on &lt;a href=&quot;http://news.ycombinator.com/item?id=865306&quot;&gt;Hacker News&lt;/a&gt;. Also, if you have examples of the prefork echo server in other languages, like &lt;a href=&quot;http://jacobian.org/writing/python-is-unix/&quot;&gt;Jacob's Python implementation&lt;/a&gt;, shoot me a link via &lt;a href=&quot;mailto:r@tomayko.com&quot;&gt;mail&lt;/a&gt; or &lt;a href=&quot;http://twitter.com/rtomayko&quot;&gt;twitter&lt;/a&gt; and I'll link to it here, from my &lt;a href=&quot;http://tomayko.com/linkings/&quot;&gt;linkings&lt;/a&gt;, and on Twitter.
&lt;/p&gt;



</content>
  </entry>
  
  <entry>
    <title>HTTP Caching Talk at RailsConf '09</title>
    <id>tag:naeblis.cx,2003:railsconf-caching-talk</id>
    <published>2009-04-27T00:00:00-07:00</published>
    <updated>2009-04-27T00:00:00-07:00</updated>
    <link href="http://tomayko.com/writings/railsconf-caching-talk" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;This will be my first talk at a major conference.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I'm doing &lt;a href=&quot;http://en.oreilly.com/rails2009/public/schedule/detail/8739&quot; title=&quot;HTTP's Best-Kept Secret: Caching&quot;&gt;a talk on HTTP caching&lt;/a&gt; at this year's RailsConf
in Vegas, bright and early (9:45 AM), on the last day of the
conference. I'm assuming you'll be tired after a week's worth of
hard nights and depressed having lost all your money, but come by
anyway.&lt;/p&gt;




&lt;div style='text-align:center'&gt;
&lt;img src=&quot;http://assets.en.oreilly.com/1/event/24/rails2009_728x90.jpg&quot; width=&quot;728&quot; height=&quot;90&quot;  border=&quot;0&quot;  alt=&quot;RailsConf 2009&quot; title=&quot;RailsConf 2009&quot;  /&gt;
&lt;/div&gt;




&lt;p&gt;I've had ideas for a killer general introduction to modern HTTP
caching for years but was hesitant to give it since the set of
available gateway caches (Squid, basically) were &lt;a href=&quot;http://tomayko.com/writings/rack-cache-announce#comment-103509&quot; title=&quot;To be absolutely clear on what I mean by 'practical' here.&quot;&gt;not what I'd
consider practical&lt;/a&gt; for the audience I wanted to target
(all ruby web developers). A lot has changed within the past
year: &lt;a href=&quot;http://tomayko.com/src/rack-cache/&quot; title=&quot;Rack::Cache - HTTP caching for Ruby web apps&quot;&gt;Rack::Cache&lt;/a&gt; was released, Heroku put a high
performance gateway cache / accelerator &lt;a href=&quot;http://docs.heroku.com/http-caching&quot;&gt;in front of every
app&lt;/a&gt;, most web frameworks provide utilities for basic HTTP
caching stuff, Apache's mod_cache is much improved, Varnish is
seeing a lot of adoption -- it's time to start talking about
this stuff.&lt;/p&gt;




&lt;p&gt;And even more has happened in the months since I submitted my
original proposal. I caught a recording of &lt;a href=&quot;http://aac2009.confreaks.com/06-feb-2009-09-00-innovation-in-rails-gregg-pollack-jason-seifer.html&quot; title=&quot;Innovation in Rails -- caching stuff starts at 24:00&quot;&gt;the RailsEnvy
guys's acts_as_conference 09 presentation&lt;/a&gt;, wherein Gregg
Pollack utterly nails a huge portion of what I'd hoped to speak
about. He followed that up with a highly polished screencast (if
you can call it a &quot;screencast&quot; -- he uses a goddam green screen)
on &lt;a href=&quot;http://railslab.newrelic.com/2009/02/26/episode-11-advanced-http-caching&quot; title=&quot;Advanced HTTP Caching (Ep. 11 in the RailsLab Screencast series)&quot;&gt;Advanced HTTP Caching&lt;/a&gt;, which is more or less the talk
I planned to give at RailsConf.&lt;/p&gt;




&lt;p&gt;So I've decided to take all of this as an opportunity and am shifting my talk around to explore some of the more advanced and experimental stuff people are doing with HTTP caching. Not everything is worked out yet but I'm happy with the direction and excited at the prospect of having an audience for some of these ideas sooner than later. I still plan to run through the basics but quickly, and only enough to set up the latter part of the presentation. I strongly recommended watching &lt;a href=&quot;http://railslab.newrelic.com/2009/02/26/episode-11-advanced-http-caching&quot; title=&quot;Advanced HTTP Caching (Ep. 11 in the RailsLab Screencast series)&quot;&gt;Gregg's piece&lt;/a&gt; if you plan on attending.&lt;/p&gt;




&lt;p&gt;Hope to see you there.&lt;/p&gt;




&lt;p class='note'&gt;
UPDATE: I wasn't able to deliver on the advanced stuff due to time constraints but I think the talk went okay. Huge thanks to everyone that attended and here's &lt;a href=&quot;http://www.slideshare.net/rtomayko/https-bestkept-secret-caching&quot;&gt;the slides&lt;/a&gt; for those that weren't able to make it.
&lt;/p&gt;



</content>
  </entry>
  
  <entry>
    <title>Why &quot;require 'rubygems'&quot; Is Wrong</title>
    <id>tag:naeblis.cx,2003:require-rubygems-antipattern</id>
    <published>2009-01-27T00:00:00-08:00</published>
    <updated>2009-01-27T00:00:00-08:00</updated>
    <link href="http://tomayko.com/writings/require-rubygems-antipattern" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;The following screed was originally published at &lt;a href=&quot;http://gist.github.com/54177&quot;&gt;gist.github.com/54177&lt;/a&gt; but has been copied here for posterity and because people keep asking me on IRC for the original link (it must be hard to find on gist for some reason).&lt;/p&gt;
</summary>
    <content type="html">&lt;p class='intro'&gt;
  The following was originally published at &lt;a href=&quot;http://gist.github.com/54177&quot;&gt;gist.github.com/54177&lt;/a&gt; but has been copied here for posterity and because people keep asking me on IRC for the original link; it must be hard to find on gist for some reason.
&lt;/p&gt;




&lt;p&gt;In response to all the &quot;huh?&quot; responses to &lt;a href=&quot;http://twitter.com/rtomayko/status/1155906157&quot;&gt;this tweet&lt;/a&gt;: &lt;em&gt;You should never do this in a source file included with your library, app, or tests&lt;/em&gt;:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;require 'rubygems'
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;The system I use to manage my &lt;code&gt;$LOAD_PATH&lt;/code&gt; is not your library / app / tests concern. Whether rubygems is used or not is an environment issue. Your library or app should have no say in the matter. Explicitly requiring rubygems is either not necessary or misguided.&lt;/p&gt;




&lt;p&gt;When you feel the urge to &lt;code&gt;&quot;require 'rubygems'&quot;&lt;/code&gt; because some shit isn't working, stop and consider whether one of these solutions is more appropriate:&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; RubyGems installs special wrapper versions of executables included with gems. Here's &lt;code&gt;/opt/local/bin/rake&lt;/code&gt; on my system as an example:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;$ cat /opt/local/bin/rake
#!/opt/local/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = &quot;&amp;gt;= 0&quot;
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end
gem 'rake', version
load 'rake'
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;In this case, rubygems is required when the executable is run. Explicitly
requiring rubygems in code loaded by these files doesn't make sense. The
whole point of these wrapper scripts is to push the rubygems loading
machinery into the environment and out of your app / library / tests.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; When running &lt;code&gt;ruby FOO.rb&lt;/code&gt; and a &lt;code&gt;LoadError&lt;/code&gt; occurs because rubygems
is not available, DO NOT add &lt;code&gt;require 'rubygems'&lt;/code&gt; to &lt;code&gt;FOO.rb&lt;/code&gt;. Instead,
run the command as &lt;code&gt;ruby -rubygems FOO.rb&lt;/code&gt;. This will require rubygems
before evaluating &lt;code&gt;FOO.rb&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; When running &lt;code&gt;ruby FOO.rb&lt;/code&gt; and a &lt;code&gt;LoadError&lt;/code&gt; occurs because rubygems
is not available, DO NOT add &lt;code&gt;require 'rubygems'&lt;/code&gt; to &lt;code&gt;FOO.rb&lt;/code&gt;. Instead,
set the &lt;code&gt;RUBYOPT&lt;/code&gt; environment variable:&lt;/p&gt;




&lt;pre&gt;&lt;code&gt;$ RUBYOPT=&quot;rubygems&quot;
$ export RUBYOPT
$ ruby FOO.rb
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;You can even put that in your &lt;code&gt;~/.{bash,zsh,sh}rc&lt;/code&gt; if you prefer to always
have rubygems loaded and available.&lt;/p&gt;




&lt;h3&gt;Why You Shouldn't Force Rubygems On People&lt;/h3&gt;




&lt;p&gt;When I use your library, deploy your app, or run your tests I may not want
to use rubygems. When you &lt;code&gt;require 'rubygems'&lt;/code&gt; in your code, you remove my
ability to make that decision. I cannot unrequire rubygems, but you can
not require it in the first place.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Things Caches Do</title>
    <id>tag:naeblis.cx,2003:things-caches-do</id>
    <published>2008-11-16T00:00:00-08:00</published>
    <updated>2008-11-16T00:00:00-08:00</updated>
    <link href="http://tomayko.com/writings/things-caches-do" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;An illustrated re-introduction to HTTP caching with a focus on gateway caches and their potential benefits within the context of modern, dynamic web applications.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;There are &lt;a href=&quot;http://www.mnot.net/cache_docs/#KINDS&quot;&gt;different kinds of HTTP caches&lt;/a&gt; that are useful for different kinds of things. I want to talk about &lt;a href=&quot;http://www.mnot.net/cache_docs/#GATEWAY&quot;&gt;&lt;em&gt;gateway caches&lt;/em&gt;&lt;/a&gt; -- or, &quot;reverse proxy caches&quot; -- and consider their effects on modern, dynamic web application design.&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src='http://farm4.static.flickr.com/3284/3035462771_052296ac86_o.png' alt='' height='385' width='636' border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin' style='text-align:center;padding-left:110px'&gt;
&lt;pre&gt;
Alice    -&gt; Cache:     &amp;#0160;&amp;#0160;&amp;#0160;&amp;#0160;GET /welcome&amp;#0160;&amp;#0160;&amp;#0160;&amp;#0160;
Cache    -&gt; Backend:   &amp;#0160;&amp;#0160;&amp;#0160;&amp;#0160;GET /welcome&amp;#0160;&amp;#0160;&amp;#0160;&amp;#0160;

note right of Backend: code to send back\n&quot;Hello World&quot; here

Backend  -&gt; Cache:     200 OK\nHello World
Cache    -&gt; Alice:     200 OK\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;Draw an imaginary vertical line, situated between &lt;em&gt;Alice&lt;/em&gt; and &lt;em&gt;Cache&lt;/em&gt;,
from the very top of the diagram to the very bottom. That line is your
public, internet facing interface. In other words, everything from
&lt;em&gt;Cache&lt;/em&gt; back is &quot;your site&quot; as far as &lt;em&gt;Alice&lt;/em&gt; is concerned.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Alice&lt;/em&gt; is actually Alice's web browser, or perhaps some other kind of
HTTP user-agent. There's also &lt;em&gt;Bob&lt;/em&gt; and &lt;em&gt;Carol&lt;/em&gt;. Gateway caches are
primarily interesting when you consider their effects across multiple
clients.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cache&lt;/em&gt; is an HTTP gateway cache, like &lt;a href=&quot;http://varnish.projects.linpro.no/&quot;&gt;Varnish&lt;/a&gt;, &lt;a href=&quot;http://wiki.squid-cache.org/SquidFaq/ReverseProxy&quot;&gt;Squid in reverse
proxy mode&lt;/a&gt;, &lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/cache/&quot;&gt;Django's cache framework&lt;/a&gt;, or my personal
favorite: &lt;a href=&quot;http://tomayko.com/src/rack-cache/&quot;&gt;rack-cache&lt;/a&gt;. In theory, this could also be a &lt;acronym title=&quot;Content
Delivery Network&quot;&gt;CDN&lt;/acronym&gt;, like &lt;a href=&quot;http://www.akamai.com/&quot;&gt;Akamai&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;And that brings us to &lt;em&gt;Backend&lt;/em&gt;, a dynamic web application built with
only the most modern and sophisticated web framework. Interpreted
language, convenient routing, an ORM, slick template language, and
various other crap -- all adding up to amazing developer productivity.
In other words, it's horribly slow and bloated... &lt;em&gt;and awesome&lt;/em&gt;!
There's probably many of these processes, possibly running on multiple
machines.&lt;/p&gt;




&lt;p class='note'&gt;
(One would typically have a separate &lt;em&gt;web server&lt;/em&gt; -- like Nginx,
Apache or lighttpd -- and maybe a load balancer sitting in here as well
but that's largely irrelevant to this discussion and has been omitted
from the diagrams.)
&lt;/p&gt;




&lt;h2&gt;Expiration&lt;/h2&gt;




&lt;p&gt;Most people understand &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.2&quot; title=&quot;RFC 2616 - Expiration Model&quot;&gt;the expiration model&lt;/a&gt; well enough. You
specify how long a response should be considered &quot;fresh&quot; by including
either or both of the &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.9&quot; title=&quot;RFC 2616 - The Cache-Control Header&quot;&gt;&lt;code&gt;Cache-Control: max-age=N&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.2&quot; title=&quot;RFC 2616 - Expiration Model&quot;&gt;&lt;code&gt;Expires&lt;/code&gt;&lt;/a&gt; headers. Caches that understand expiration will not make the same request until the cached version reaches its expiration time and becomes &quot;stale&quot;.&lt;/p&gt;




&lt;p&gt;A gateway cache dramatically increases the benefits of providing
expiration information in dynamically generated responses. To
illustrate, let's suppose &lt;em&gt;Alice&lt;/em&gt; requests a welcome page:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3050/3035498443_30c0215e59_o.png&quot; width=&quot;746&quot; height=&quot;431&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Alice     -&gt; Cache:      GET /welcome
Cache     -&gt; Backend:    GET /welcome

note right of Backend:   &quot;Hello World&quot;\n(with max-age header)

Backend   -&gt; Cache:      200 OK\nCache-Control: max-age=600\nHello World!
Cache     -&gt; Alice:      200 OK\nCache-Control: max-age=600\nHello World!
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;Since the cache has no previous knowledge of the welcome page, it
forwards the request to the backend. The backend generates the
response, including a &lt;code&gt;Cache-Control&lt;/code&gt; header that indicates the
response should be considered fresh for ten minutes. The cache then
shoots the response back to &lt;em&gt;Alice&lt;/em&gt; while storing a copy for itself.&lt;/p&gt;




&lt;p&gt;Thirty seconds later, &lt;em&gt;Bob&lt;/em&gt; comes along and requests the same welcome
page:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3169/3035498489_d33d8e8847_o.png&quot; width=&quot;558&quot; height=&quot;355&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Bob      -&gt; Cache:      GET /welcome
Cache  Backend:   This does not happen ...
Cache -&gt; Cache:         ... because the cache is fresh!
Cache    -&gt; Bob:        200 OK\nAge: 30\nCache-Control: max-age=600\nHello World!
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;The cache recognizes the request, pulls up the stored response, sees
that it's still fresh, and sends the cached response back to &lt;em&gt;Bob&lt;/em&gt;,
ignoring the backend entirely.&lt;/p&gt;




&lt;p&gt;Note that we've experienced no significant bandwidth savings here --
the entire response was delivered to both &lt;em&gt;Alice&lt;/em&gt; and &lt;em&gt;Bob&lt;/em&gt;. We see
savings in CPU usage, database round trips, and the various other
resources required to generate the response at the backend.&lt;/p&gt;




&lt;h2&gt;Validation&lt;/h2&gt;




&lt;p&gt;Expiration is ideal when you can get away with it. Unfortunately, there
are many situations where it doesn't make sense, and this is especially
true for heavily dynamic web apps where changes in resource state can
occur frequently and unpredictably. &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.2&quot;&gt;The validation model&lt;/a&gt; is
designed to support these cases.&lt;/p&gt;




&lt;p&gt;Again, we'll suppose &lt;em&gt;Alice&lt;/em&gt; makes the initial request for the welcome
page:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3009/3036333222_0db315592f_o.png&quot; width=&quot;742&quot; height=&quot;477&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Alice -&gt; Cache:           GET /welcome
Cache  -&gt; Backend:        GET /welcome
note right of Backend:    generate validators;\n&quot;Hello World&quot;
Backend-&gt;Cache:           200 OK\nLast-Modified: Tue, 28 Oct...\nETag: a3e455afd\nHello World
Cache-&gt;Alice:             200 OK\nLast-Modified: Tue, 28 Oct...\nETag: a3e455afd\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;The &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.29&quot; title=&quot;RFC 2616 - The Last-Modified Header&quot;&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.19&quot; title=&quot;RFC 2616 - The ETag Header&quot;&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/a&gt; header values are called &quot;cache validators&quot; because they can be used by the cache on subsequent
requests to &lt;em&gt;validate&lt;/em&gt; the freshness of the stored response without
requiring the backend to generate or transmit the response body. You
don't need both validators -- either one will do, though both have pros
and cons, the details of which are outside the scope of this document.&lt;/p&gt;




&lt;p&gt;So &lt;em&gt;Bob&lt;/em&gt; comes along at some point after &lt;em&gt;Alice&lt;/em&gt; and requests the
welcome page:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3188/3036333272_bfcd6fd62a_o.png&quot; width=&quot;817&quot; height=&quot;454&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Bob -&gt; Cache:             GET /welcome
Cache - -&gt; Backend:       GET /welcome\nIf-Modified-Since: Tue, 28 Oct...\nIf-None-Match: a3e455afd
note right of Backend:    generate validators;\nDO NOT generate response
Backend - -&gt; Cache:       304 Not Modified
Cache -&gt; Bob:             200 OK\nLast-Modified: Tue, 28 Oct...\nETag: a3e455afd\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;The cache sees that it has a copy of the welcome page but can't be sure
of its freshness so it needs to pass the request to the backend. &lt;em&gt;But&lt;/em&gt;,
before doing so, the cache adds the &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.25&quot; title=&quot;RFC 2616 - The If-Modified-Since Header&quot;&gt;&lt;code&gt;If-Modified-Since&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.26&quot; title=&quot;RFC 2616 - The If-None-Match Header&quot;&gt;&lt;code&gt;If-None-Match&lt;/code&gt;&lt;/a&gt; headers to the request, setting them to the original response's &lt;code&gt;Last-Modified&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt; values, respectively. These headers make the request conditional. Once the backend receives the request, it generates the current cache validators, checks them against the values provided in the request, and immediately shoots back a &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-10.3.5&quot; title=&quot;RFC 2616 - The 304 Not Modified Response&quot;&gt;&lt;code&gt;304 Not Modified&lt;/code&gt;&lt;/a&gt; response &lt;em&gt;without generating the response body&lt;/em&gt;. The cache, having validated the freshness of its copy, is now free to respond to &lt;em&gt;Bob&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;This requires a round-trip with the backend, but if the backend
generates cache validators up front and in an efficient manner, it can
avoid generating the response body. This can be extremely significant.
A backend that takes advantage of validation need not generate the same
response twice.&lt;/p&gt;




&lt;h2&gt;Combining Expiration and Validation&lt;/h2&gt;




&lt;p&gt;The expiration and validation models form the basic foundation of HTTP
caching. A response may include expiration information, validation
information, both, or neither. So far we've seen what each looks like
independently. It's also worth looking at how things work when they're
combined.&lt;/p&gt;




&lt;p&gt;Suppose, again, that &lt;em&gt;Alice&lt;/em&gt; makes the initial request:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3180/3036333336_521bd9ce7c_o.png&quot; width=&quot;742&quot; height=&quot;477&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Alice -&gt; Cache:           GET /welcome
Cache -&gt; Backend:         GET /welcome
note right of Backend:    generate validators;\n&quot;Hello World&quot;
Backend -&gt; Cache:         200 OK\nCache-Control: max-age=60\nLast-Modified: Tue, 28 Oct...\nHello World
Cache -&gt; Alice:           200 OK\nCache-Control: max-age=60\nLast-Modified: Tue, 28 Oct...\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;The backend specifies that the response should be considered fresh
for sixty seconds and also includes the &lt;code&gt;Last-Modified&lt;/code&gt; cache
validator.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bob&lt;/em&gt; comes along thirty seconds later. Since the response is still
fresh, validation is not required; he's served directly from cache:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3170/3035498713_eb51e8652e_o.png&quot; width=&quot;562&quot; height=&quot;378&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Bob -&gt; Cache:             GET /welcome
Cache - -&gt; Backend:       This does not happen ...
Cache -&gt; Cache:           ... because the cache is fresh!
Cache -&gt; Bob:             200 OK\nCache-Control: max-age=60\nAge: 30\nLast-Modified: Tue, 28 Oct...\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;But then &lt;em&gt;Carol&lt;/em&gt; makes the same request, thirty seconds after &lt;em&gt;Bob&lt;/em&gt;:&lt;/p&gt;




&lt;div style='margin:2em 0'&gt;
&lt;img src=&quot;http://farm4.static.flickr.com/3165/3036333458_9b165aa5d0_o.png&quot; width=&quot;823&quot; height=&quot;454&quot; alt=&quot;&quot; border='0' /&gt;
&lt;/div&gt;




&lt;!--
&lt;div class='wsd' wsd_style='napkin'&gt;
&lt;pre&gt;
Carol -&gt; Cache:           GET /welcome
Cache - -&gt; Backend:       GET /welcome\nIf-Modified-Since: Tue, 28 Oct...
note right of Backend:    generate validators;\nDO NOT generate response
Backend - -&gt; Cache:       304 Not Modified\nCache-Control: max-age=60
Cache -&gt; Carol:           200 OK\nCache-Control: max-age=60\nLast-Modified: Tue, 28 Oct...\nHello World
&lt;/pre&gt;
&lt;/div&gt;
--&gt;




&lt;p&gt;The cache relies on expiration if at all possible before falling back
on validation. Note also that the &lt;code&gt;304 Not Modified&lt;/code&gt; response includes
updated expiration information, so the cache knows that it has another
sixty seconds before it needs to perform another validation request.&lt;/p&gt;




&lt;h2&gt;More&lt;/h2&gt;




&lt;p&gt;The basic mechanisms shown here form the conceptual foundation of caching in HTTP -- not to mention the Cache architectural constraint &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_4&quot;&gt;as defined by REST&lt;/a&gt;. There's more to it, of course: a cache's behavior can be further constrained with additional &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.9&quot; title=&quot;RFC 2616 - The Cache-Control Header&quot;&gt;&lt;code&gt;Cache-Control&lt;/code&gt;&lt;/a&gt; directives, and the &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.44&quot; title=&quot;RFC 2616 - The Vary Header&quot;&gt;&lt;code&gt;Vary&lt;/code&gt;&lt;/a&gt; header narrows a response's cache suitability based on headers of subsequent requests.
For a more thorough look at HTTP caching, I suggest Mark Nottingham's excellent &lt;a href=&quot;http://www.mnot.net/cache_docs/&quot;&gt;Caching Tutorial for Web Authors and Webmasters&lt;/a&gt;. Paul James's &lt;a href=&quot;http://www.peej.co.uk/articles/http-caching.html&quot;&gt;HTTP Caching&lt;/a&gt; is also quite good and bit shorter. And, of course, the &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13&quot; title=&quot;RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1&quot;&gt;relevant sections of RFC 2616&lt;/a&gt; are highly recommended.&lt;/p&gt;




&lt;p class='note'&gt;
(Oh, and the diagrams were made using &lt;a
href=&quot;http://www.websequencediagrams.com/&quot;&gt;websequencediagrams.com&lt;/a&gt;,
a very simple, text-based sequence diagram generating web service
thingy.)
&lt;/p&gt;




&lt;!--
&lt;script type=&quot;text/javascript&quot; src=&quot;http://www.websequencediagrams.com/service.js&quot;&gt;&lt;/script&gt;
--&gt;



</content>
  </entry>
  
  <entry>
    <title>Introducing Rack::Cache</title>
    <id>tag:naeblis.cx,2003:rack-cache-announce</id>
    <published>2008-10-24T00:00:00-07:00</published>
    <updated>2008-10-24T00:00:00-07:00</updated>
    <link href="http://tomayko.com/writings/rack-cache-announce" rel="alternate" type="text/html"/>
    <author>
      <name>Ryan Tomayko</name>
      <uri>http://tomayko.com/</uri>
      <email>r@tomayko.com</email>
    </author>
    <summary type="html">&lt;p&gt;Real HTTP caching for Ruby web apps.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I'm pleased to finally release a side-project I've been whittling
away at for a few months: &lt;strong&gt;&lt;a href=&quot;http://tomayko.com/src/rack-cache/&quot; title=&quot;Rack::Cache Project Information and Documentation&quot;&gt;Rack::Cache&lt;/a&gt;&lt;/strong&gt; is a piece of
&lt;a href=&quot;http://rack.rubyforge.org/&quot; title=&quot;Rack: a Ruby Webserver Interface [rack.rubyforge.org]&quot;&gt;Rack&lt;/a&gt; middleware that implements most of &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13&quot; title=&quot;RFC 2616 Section 13 - Caching in HTTP [ietf.org]&quot;&gt;RFC 2616's caching
features&lt;/a&gt; with a basic set of &lt;a href=&quot;http://tomayko.com/src/rack-cache/configuration&quot; title=&quot;Rack::Cache Storage Documentation&quot;&gt;storage options&lt;/a&gt; (disk, heap,
and memcached) and a &lt;a href=&quot;http://tomayko.com/src/rack-cache/configuration&quot; title=&quot;Rack::Cache Configuration Language Documentation&quot;&gt;configuration system&lt;/a&gt; for tweaking cache
policy. It should work equally well with any Rack-enabled Ruby web
framework and is tested on Ruby 1.8.6 and 1.8.7.&lt;/p&gt;




&lt;p&gt;&lt;img src='http://tomayko.com/static/images/rack-cache.png' width='282' height='459' alt='high-level rack-cache diagram' style='float:right' /&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Rack::Cache&lt;/strong&gt; relies entirely on standard HTTP headers produced by
your application. It has no application level caching API.&lt;/p&gt;




&lt;p&gt;&lt;a href=&quot;http://www.xml.com/lpt/a/1642&quot; title=&quot;Joe Gregorio's 'Doing HTTP Caching Right'&quot;&gt;You need&lt;/a&gt; &lt;a href=&quot;http://www.mnot.net/cache_docs/#WORK&quot; title=&quot;Mark Nottingham's Caching Tutorial&quot;&gt;to understand&lt;/a&gt; &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13&quot; title=&quot;RFC 2616 Section 13 - Caching in HTTP [ietf.org]&quot;&gt;HTTP
caching&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;The middleware piece sits near the front of each backend process and acts like a gateway proxy cache (e.g, &lt;a href=&quot;http://varnish.projects.linpro.no/&quot; title=&quot;Varnish: High-performance HTTP accelerator&quot;&gt;Varnish&lt;/a&gt;, &lt;a href=&quot;http://wiki.squid-cache.org/SquidFaq/ReverseProxy&quot; title=&quot;Squid / Reverse Proxy Mode [wiki.squid-cache.org]&quot;&gt;Squid&lt;/a&gt;) but without requiring the infrastructure investment of a separate daemon process. This approach is quite different from the integrated caching systems built into most Ruby web frameworks. There are pros and cons which I plan to explore with some depth in future posts here.&lt;/p&gt;




&lt;p&gt;The basic goal is standards-based HTTP caching that scales down to
the early stages of a project, development environments, light to
medium trafficked sites, stuff like that. HTTP's caching model is
wildly under-appreciated in the Ruby web app community and my hope
is that making its benefits more accessible will lead to wider
understanding and acceptance.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Rack::Cache&lt;/strong&gt; is still very much a work in progress but is far
enough along to be useable (it's serving this site, in fact). The
following HTTP caching features are currently supported:&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.2&quot;&gt;Expiration-based caching&lt;/a&gt;.
Responses are served from cache while fresh without consulting
the backend application. The &lt;code&gt;Cache-Control: max-age=N&lt;/code&gt; and
&lt;code&gt;Expires&lt;/code&gt; response headers control a response's freshness lifetime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.3&quot;&gt;Validation&lt;/a&gt;. The
cache stores responses even if no freshness information is present
so long as there's a cache validator (&lt;code&gt;Last-Modified&lt;/code&gt; or &lt;code&gt;ETag&lt;/code&gt;).
Subsequent requests result in a conditional &lt;code&gt;GET&lt;/code&gt; request
to the application and if the stored response is unmodified, it's
served from cache. Your backend should never generate the same
response twice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-13.6&quot;&gt;Vary support&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;There are a few notable things still missing.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Explicit purge / manual cache invalidation. There is currently
no supported method for manually invalidating a cache entry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-thread. There's nothing fundamentally hard about this, I
just haven't got around to testing in a threaded environment and
working out the kinks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance. The current focus is on nailing down a solid
implementation of HTTP's basic caching features and providing
&lt;a href=&quot;http://tomayko.com/src/rack-cache/&quot;&gt;good documentation&lt;/a&gt;. I have
not profiled the system or performed any benchmarks. Anecdotal
evidence suggests that the performance situation is basically
swell.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Finally, I'd like to note that &lt;strong&gt;Rack::Cache&lt;/strong&gt; is based largely on
the work of the internet standards community and that portions of
its design were inspired by &lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/cache/&quot; title=&quot;Django's Cache Framework [djangoproject.com]&quot;&gt;Django's cache framework&lt;/a&gt; and
Varnish's &lt;a href=&quot;http://tomayko.com/man/vcl&quot; title=&quot;VCL(7) Varnish Configuration Language&quot;&gt;configuration language (VCL)&lt;/a&gt;. Huge thanks to
everyone involved with any of this stuff.&lt;/p&gt;

</content>
  </entry>
  
</feed>

