<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
    <title>geek!daily</title>
    <link rel="alternate" type="text/html" href="http://blog.geekdaily.org/" />
    <link rel="service.post" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602" title="geek!daily" />
    <id>tag:typepad.com,2003:weblog-318602</id>
    <updated>2013-04-12T16:00:00Z</updated>
    <subtitle>... it is by will alone i set my mind in motion ...</subtitle>

    <generator uri="http://www.typepad.com/">TypePad</generator>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/geekdailyblog" /><feedburner:info uri="geekdailyblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>37.769528</geo:lat><geo:long>-122.259378</geo:long><entry>
        <title>Setting Up A Minecraft Server For Kids, Part 1: Preparation</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/xM1sXadQaoE/setting-up-a-minecraft-server-for-kids-part-1-preparation.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e2017d42b8e4c5970c" title="Setting Up A Minecraft Server For Kids, Part 1: Preparation" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e2017d42b8e4c5970c</id>
        <published>2013-04-12T09:00:00-07:00</published>
        <updated>2013-04-12T16:00:00Z</updated>
        <summary type="html">I've got a little more time on my hands than usual at the moment, so I decided to set up a Minecraft server for my son and his friends. I figured it would force me to play around with cloud...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Fun!" />
        <category term="Games" />
        <category term="Hacking" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;I've got a little more time on my hands than usual at the moment, so I decided to set up a &lt;a href="https://minecraft.net/" target="_blank"&gt;Minecraft&lt;/a&gt; server for my son and his friends. I figured it would force me to play around with cloud APIs, some linux configuration that I haven't done for a long while, and other various bits of geekery that would just make me happy.&lt;/p&gt;&#xD;
&lt;p&gt;As I started to do some research on how to go about it, I found &lt;a href="https://www.google.com/search?q=how+to+setup+a+minecraft+server" target="_blank"&gt;about a gajillion posts on how to set up a server&lt;/a&gt; (including &lt;a href="http://warpedvisions.org/2012/02/howto-set-up-a-minecraft-server-in-10-minutes-using-amazon-ec2/" target="_blank"&gt;this slightly outdated gem&lt;/a&gt;), including a few from &lt;a href="http://www.ultrasaurus.com/sarahblog/2011/11/setting-up-ec2-minecraft-server/" target="_blank"&gt;smart friends&lt;/a&gt; &lt;a href="https://mobile.twitter.com/tom_enebo/status/300763304777891840" target="_blank"&gt;of mine&lt;/a&gt;. After a bit of reading, it became clear that this could be a much larger undertaking so I decided to chunk out the project into four steps: &lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;&lt;strong&gt;Preparation:&lt;/strong&gt; research and learning&lt;/li&gt;&#xD;
&lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; set up the instance and server&lt;/li&gt;&#xD;
&lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; tweak the server config and add plugins to get what you're looking for&lt;/li&gt;&#xD;
&lt;li&gt;&lt;strong&gt;Productionization:&lt;/strong&gt; make the installation reproducible and automatable; set up backups; etc. And yeah, that's not a real word. I'm okay with that.&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;&lt;strong&gt;This post will focus on the preparation&lt;/strong&gt; required to get as many bits sorted out as you can before installing. I'll write about the rest in the next few posts.&lt;/p&gt;&#xD;
&lt;h2&gt;&lt;strong&gt;&lt;span style="font-size: large;"&gt;So, Minecraft ...&lt;/span&gt;&lt;/strong&gt;&lt;/h2&gt;&#xD;
&lt;p&gt;If, like me, you came to this with little practical Minecraft experience, the first thing you should do is try playing a bit. There are a few free ways to do this — such as &lt;a href="https://minecraft.net/classic/" target="_blank"&gt;Minecraft Classic&lt;/a&gt; in your browser or &lt;a href="https://itunes.apple.com/us/app/minecraft-pocket-edition-lite/id479651754?mt=8" target="_blank"&gt;Minecraft Pocket Edition Lite&lt;/a&gt; on an iOS device — or you can just spend the ~$30  and jump in. I figured that to be an op I'd want my own account, so I went for the full experience.&lt;/p&gt;&#xD;
&lt;p&gt;I died a lot. I crafted a bit. I created a bunch in single player. I joined a few multiplayer servers. I died some more. Through all of it, I got a sense of the game and what my son and his friends would be in for. This helped a lot as I started to figure out what it would take to start up and run a server, as it identified some key questions, like, "How can we have a creative world as well as a survival world?" and "What's the difference between 'easy' and 'peaceful'?"&lt;/p&gt;&#xD;
&lt;p&gt;These led me to &lt;a href="http://www.minecraftwiki.net/" target="_blank"&gt;the Minecraft Wiki.&lt;/a&gt; Frankly, had I read much of it before playing I would have died less and crafted more. However, it helped me get clear on a few things that matter when you're considering running a server for others. &lt;/p&gt;&#xD;
&lt;h3&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;&lt;a href="http://www.minecraftwiki.net/wiki/Gameplay" target="_blank"&gt;Game Mode&lt;/a&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/h3&gt;&#xD;
&lt;p&gt;The default is survival mode, which means that, in order to survive and craft things, you have to walk around and collect block types required by recipes while avoiding being killed by monsters ("mobs" in the old MUD parlance). There's also creative mode, where you gain the power of flight, you have access to every block type instantly, and you can make anything your heart desires. My son is currently constructing a flush toilet in the hotel he's making. His heart desires strange things.&lt;/p&gt;&#xD;
&lt;h3&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;&lt;a href="http://www.minecraftwiki.net/wiki/Difficulty" target="_blank"&gt;Difficulty&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/h3&gt;&#xD;
&lt;p&gt;This ranges from Peaceful, where any aggressive mobs are removed or don't spawn, through Easy and Normal, right into Hard. The wiki does an excellent job explaining.&lt;/p&gt;&#xD;
&lt;h3&gt;&lt;span style="font-size: medium;"&gt;&lt;a href="http://www.minecraftwiki.net/wiki/World_types" target="_blank"&gt;World Types&lt;/a&gt;&lt;/span&gt;&lt;/h3&gt;&#xD;
&lt;p&gt;There are a few settings in there that weren't obvious on the face of it, such as what Large Biomes is or why Superflat would be interesting. It turns out that Superflat is a great canvas for Creative worlds, and Large Biomes is pretty much just like the default biome-based terrain generator but each biome takes up more real estate.&lt;/p&gt;&#xD;
&lt;p&gt;It was clear to me that we'd want a Superflat Creative world and an Easy Default Survival world.&lt;/p&gt;&#xD;
&lt;h2&gt;Servers, Servers Everywhere&lt;/h2&gt;&#xD;
&lt;p&gt;There are &lt;a href="https://www.google.com/search?q=minecraft+server+implementations" target="_blank"&gt;a lot of available servers out there&lt;/a&gt;. I could tell you that I did an exhaustive search and evaluation, but the truth is that I trusted my smart friend, Sarah, and chose &lt;a href="https://github.com/Bukkit/CraftBukkit" target="_blank"&gt;Craftbukkit&lt;/a&gt; (CB) for many of the same reasons she did: we both know and trust &lt;a href="http://confreaks.net/videos/696-rubyconf2011-be-a-minecraft-modman-with-purugin" target="_blank" title="Confreaks RubyConf 2011: Be A Minecraft ModMan with Purugin"&gt;Tom Enebo's opinion&lt;/a&gt;, it's &lt;a href="https://github.com/enebo/Purugin" target="_blank"&gt;easy to extend using JRuby&lt;/a&gt;, and it seems to be the leading server beyond vanilla Minecraft.&lt;/p&gt;&#xD;
&lt;p&gt;Another bit of validation comes from cheracc, who runs &lt;a href="http://www.sandlotminecraft.com/" target="_blank"&gt;Sandlot Minecraft server for kids and families&lt;/a&gt;, and who also uses CB with many plugins. More on that later, though you can read &lt;a href="http://www.reddit.com/r/admincraft/comments/17ri0h/help_advice_for_running_a_kidfriendly_server/" target="_blank"&gt;his excellent Reddit post on setting up a Minecraft server for kids&lt;/a&gt; now.&lt;/p&gt;&#xD;
&lt;p&gt;One other minor note: since CB is a third-party server, it takes them a bit of time to catch up when Mojang releases a new client version. This means you'll want to wait on client updates until there's a beta version of CB that handles the new client version. As of this writing, the current client requires a 1.5.x server which means craftbukkit-beta.jar&lt;/p&gt;&#xD;
&lt;h2&gt;Does Size Matter?&lt;/h2&gt;&#xD;
&lt;p&gt;Finally, I wanted to figure out how big an instance I'd need to host a decent server. I flailed my way through several posts trying to figure this out until I discovered &lt;a href="http://canihostaminecraftserver.com/" target="_blank"&gt;Can I Host A Minecraft Server&lt;/a&gt;, which makes it easy to take your bandwidth (both up and down) and the available RAM and figure out about how many people you can host. Remember to use the bandwidth figures for the cloud provider you're planning to use. For me, it turns out I can handle ~12 players in a 1GB instance with the usual cloud host network speeds of &amp;gt;5Mbps, which is what I was hoping to cover.&lt;/p&gt;&#xD;
&lt;p&gt;So that's it for prep. Now it's time to instantiate and install.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=xM1sXadQaoE:Ko9SbB3apkI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=xM1sXadQaoE:Ko9SbB3apkI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=xM1sXadQaoE:Ko9SbB3apkI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=xM1sXadQaoE:Ko9SbB3apkI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/xM1sXadQaoE" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2013/04/setting-up-a-minecraft-server-for-kids-part-1-preparation.html</feedburner:origLink></entry>
    <entry>
        <title>Bashing tcsh</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/OubPn4w4KBM/bashing-tcsh.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e2016764476101970b" title="Bashing tcsh" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e2016764476101970b</id>
        <published>2012-03-26T22:45:04-07:00</published>
        <updated>2012-03-27T05:45:04Z</updated>
        <summary type="html">After 15 years of non-stop tcsh action, I've finally made the jump to bash. It was painful and I miss all my lovely variable expansion (^X $), wildcard expansion (^X*) and term completion (ESC-/), but there are so many tools...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Hacking" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;After 15 years of non-stop tcsh action, I've finally made the jump to bash. It was painful and I miss all my lovely variable expansion (^X $), wildcard expansion (^X*) and term completion (ESC-/), but there are so many tools like &lt;a href="https://github.com/sstephenson/rbenv" target="_self"&gt;rbenv&lt;/a&gt; that expect that you're using bash with no tcsh-friendly alternatives.&lt;/p&gt;&#xD;
&lt;p&gt;On the upside, I've got functions now. I guess that's something.&lt;/p&gt;&#xD;
&lt;p&gt;Oh, and hi again.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=OubPn4w4KBM:Vb_IBKiOoU4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=OubPn4w4KBM:Vb_IBKiOoU4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=OubPn4w4KBM:Vb_IBKiOoU4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=OubPn4w4KBM:Vb_IBKiOoU4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/OubPn4w4KBM" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2012/03/bashing-tcsh.html</feedburner:origLink></entry>
    <entry>
        <title>Advanced YAML: Tricking Out Your database.yml</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/eJcH6Z_503c/advanced-yaml-tricking-out-your-databaseyml.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20133f30c8309970b" title="Advanced YAML: Tricking Out Your database.yml" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20133f30c8309970b</id>
        <published>2010-08-13T16:03:33-07:00</published>
        <updated>2010-08-13T23:03:33Z</updated>
        <summary type="html">I've been cultishly carrying this snippet around for years: login: &amp;amp;login adapter: mysql host: localhost username: myuser password: mypass encoding: utf8 For a couple of reasons around running DB migrations in differently configured environments, I wanted to factor this into...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Ruby/Rails" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;I've been &lt;a href="http://en.wikipedia.org/wiki/Cargo_cult_programming"&gt;cultishly&lt;/a&gt; carrying this snippet around for years:&lt;/p&gt;&#xD;
&#xD;
&lt;pre&gt;&lt;code&gt;login: &amp;amp;login&#xD;
 adapter: mysql&#xD;
 host: localhost&#xD;
 username: myuser&#xD;
 password: mypass&#xD;
 encoding: utf8&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;For a couple of reasons around running DB migrations in differently configured environments, I wanted to factor this into bits common to all environments and bits particular to the config on the local machine. I came up with something like:&lt;/p&gt;&#xD;
&#xD;
&lt;pre&gt;&lt;code&gt;# Provide default local block&#xD;
local: &amp;amp;local&#xD;
 socket: /var/run/mysqld/mysqld.sock&#xD;
 &#xD;
common: &amp;amp;common&#xD;
 adapter: mysql&#xD;
 encoding: utf8&#xD;
 reconnect: false&#xD;
 pool: 5&#xD;
 username: myuser&#xD;
 password: mypass&#xD;
 &amp;lt;&amp;lt;: *local&#xD;
&#xD;
development:&#xD;
 database: myproj_test&#xD;
 &amp;lt;&amp;lt;: *common&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;This works swimmingly, but I was tired of ritually mimicking and extending the original snippet without actually understanding it. I decided to dig deeper into what was actually going on and found, unsurprisingly, that I stand on the shoulders of giants like &lt;a href="http://blog.lathi.net/"&gt;Doug Alcorn&lt;/a&gt;, &lt;a href="http://blog.duncandavidson.com/"&gt;James Duncan Davidson&lt;/a&gt;, and &lt;a href="http://blog.bleything.net/"&gt;Ben Bleything&lt;/a&gt;. To render proper credit, &lt;a href="hhttp://blog.bleything.net/2006/6/27/dry-out-your-database-yml"&gt;Ben's post from June 2006&lt;/a&gt; builds on a missing post from James's blog, both of which were preceded by&lt;a href="http://blog.lathi.net/articles/2006/03/02/config-database-yml-goodness-for-teams"&gt; Doug's observations in March 2006&lt;/a&gt;, and all of which draw on tricks originally found in the &lt;a href="http://github.com/fdv/typo/blob/master/config/database.yml.example"&gt;Typo database config&lt;/a&gt;. None of them seems to have detailed what's going on with the &amp;amp;login/*login construct, so I thought I'd dive into that a bit for posterity.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://www.yaml.org/"&gt;YAML&lt;/a&gt; is nothing more than a human-readable way to serialize basic data structures like lists and associative arrays (aka hashes), which makes it ideal to represent the configuration values needed by Rails. It turns out that YAML provides anchors (&amp;amp;), references (*), and associative array merges (&amp;lt;&amp;lt;), all of which allow you to include by reference either by assignment or by merging a referenced array into another array. &lt;/p&gt;&lt;p&gt;Here's an example of each:&lt;/p&gt;&#xD;
&#xD;
&lt;pre&gt;&lt;code&gt;# Generate a reference&#xD;
mammal: &amp;amp;mammal_ref&#xD;
 warm_blooded: true&#xD;
 lays_eggs: false&#xD;
&#xD;
# Define via reference assignment&#xD;
beaver: *mammal_ref&#xD;
&#xD;
# Define including a hash merge&#xD;
otter:&#xD;
 cute: true&#xD;
 &amp;lt;&amp;lt;: *mammal_ref&#xD;
&#xD;
# Define including a hash merge, overriding a value in the reference&#xD;
platypus:&#xD;
 &amp;lt;&amp;lt;: *mammal_ref&#xD;
 lays_eggs: true&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;I found that the &lt;a href="http://en.wikipedia.org/wiki/YAML"&gt;Wikipedia entry on YAML&lt;/a&gt; was a good, quick overview; the &lt;a href="http://www.yaml.org/spec/1.2/spec.html"&gt;official YAML spec&lt;/a&gt; has all that and more, but it's not a quick read. Meanwhile, both Doug and Ben observed that bringing ERB into the mix let's you seriously customize things. I took a bit from both of them; here's my database.yml now:&lt;/p&gt;&#xD;
&#xD;
&lt;pre&gt;&lt;code&gt;# Provide default local block&#xD;
local: &amp;amp;local&#xD;
 username: myuser&#xD;
 password: mypass&#xD;
&amp;lt;% if File.exist? "/opt/local/var/run/mysql5/mysqld.sock" %&amp;gt;&#xD;
 socket: /opt/local/var/run/mysql5/mysqld.sock&#xD;
&amp;lt;% elsif File.exist? "/var/run/mysqld/mysqld.sock" %&amp;gt;&#xD;
 socket: /var/run/mysqld/mysqld.sock&#xD;
&amp;lt;% elsif File.exist? "/tmp/mysql.sock" %&amp;gt;&#xD;
 socket: /tmp/mysql.sock&#xD;
&amp;lt;% end %&amp;gt;&#xD;
 &#xD;
# Allow for local DB configuration&#xD;
&amp;lt;%= File.read(File.join(File.dirname(__FILE__), 'dblocal.yml')) if File.exist?(File.join(File.dirname(__FILE__), 'dblocal.yml')) %&amp;gt;&#xD;
&#xD;
common: &amp;amp;common&#xD;
 adapter: mysql&#xD;
 encoding: utf8&#xD;
 reconnect: false&#xD;
 pool: 5&#xD;
 &amp;lt;&amp;lt;: *local&#xD;
&#xD;
development:&#xD;
 database: myproj_development&#xD;
 &amp;lt;&amp;lt;: *common&#xD;
&#xD;
test:&#xD;
 database: myproj_test&#xD;
 &amp;lt;&amp;lt;: *common&#xD;
&#xD;
production:&#xD;
 database: myproj_production&#xD;
 &amp;lt;&amp;lt;: *common&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;Works a treat. Thanks, Doug, James, and Ben.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=eJcH6Z_503c:KuadIocKN4w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=eJcH6Z_503c:KuadIocKN4w:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=eJcH6Z_503c:KuadIocKN4w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=eJcH6Z_503c:KuadIocKN4w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/eJcH6Z_503c" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2010/08/advanced-yaml-tricking-out-your-databaseyml.html</feedburner:origLink></entry>
    <entry>
        <title>Live Blog: Comet &amp; Other Browser Stuff</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/PhsLbIvqUOE/live-blog-comet-other-browser-stuff.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20120a5e9f536970b" title="Live Blog: Comet &amp; Other Browser Stuff" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20120a5e9f536970b</id>
        <published>2009-10-15T13:27:25-07:00</published>
        <updated>2009-10-15T20:27:25Z</updated>
        <summary type="html">It's a big component of what we call "real-time" This is the kind of stuff that puts up a banner on a Twitter search ("# New Tweets Found") and makes things feel real time. List of what's being done to...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Metadata" />
        <category term="Social Networks" />
        <category term="UI" />
        <category term="Web 2.0" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">It's a big component of what we call "real-time"&lt;br&gt;&lt;br&gt;This is the kind of stuff that puts up a banner on a Twitter search ("# New Tweets Found") and makes things feel real time. &lt;br&gt;&lt;br&gt;List of what's being done to move notifications from server to browser:&lt;br&gt;* Ajax polling: Anybody using the JS set-timeout function, then refetch. Used by GMail, Campfire, et al&lt;br&gt;* Long polling (typically Comet): Used by FriendFeed, keeps an http connection open as long as possible (keep alive), reopen when timed-out. Keep a local thread pool.&lt;br&gt;* Flash sockets: Same as long polling, but from Flash. Don't have the same-origin policy. No limitaions on number of connections. Does gzipping.&lt;br&gt;* Reverse HTTP: hosting a little webserver inside a JS connection. Long pushing?&lt;br&gt;* Silverlight ("MS's version of Flash")&lt;br&gt;* HTML5 websockets: part of spec, doesn't exist and not implemented. Expected to be like flash sockets.&lt;br&gt;&lt;br&gt;(things discarded as too old/obscure/painful/absurd):&lt;br&gt;* Java applets (David Weekly is about to get himself kicked ;)&lt;br&gt;* Big ugly JS kludges (iframe tricks, etc)&lt;br&gt;* What's that Opera thing ... unite? ubiquity? Unite. Every browser is a webserver. Sounds like reverse HTTP.&lt;br&gt;* Using XMPP format, arbitrary JSON structure, Atom.&lt;br&gt;&lt;br&gt;Libraries:&lt;br&gt;* Orbited (?) tunnels TCP thru HTTP, treats each end like a socket. JS front-end, Python backend. Often paired with Twisted. Specifically meant to be Comet.&lt;br&gt;* stropheJS: javascript, can use flash sockets&lt;br&gt;* Tornado: python&lt;br&gt;* Cometd: Java, made by Dojo to work with dojo&lt;br&gt;* Dojo: javascript, can use flash sockets&lt;br&gt;* APE project (?)&lt;br&gt;&lt;br&gt;&lt;br&gt;What formats are people using to send data:&lt;br&gt;* JSON&lt;br&gt;* XMPP&lt;br&gt;&lt;br&gt;Apps and their libs/methodologies:&lt;br&gt;* Meebo: ??&lt;br&gt;* Google Wave/GTalk: GWT RPC, long-polling, their own JS&lt;br&gt;* FB Chat: ??&lt;br&gt;* FriendFeed: Tornado server with long-polling, their own JS&lt;br&gt;* Superfeedr: uses BOSH, stropheJS. BOSH is kinda long polling, bidirectional (two cs open all time). Very similar to comet, more friendly than strict proxies&lt;br&gt;* Collecta: uses BOSH&lt;br&gt;* Twingly: orbited&lt;br&gt;* PBWorks: long polling on network dashboard to see updates come in live; wrote their own libraries, also use stropheJS&lt;br&gt;* StatusNet - identi.ca and ??, orbited and cometd (you can do either)&lt;br&gt;&lt;br&gt;Flex and Air apps? The most interesting stuff is what used to be called Flash Media Server (been renamed). They've got their own P2P protocol. All sorts of funky stuff you can do. OpenSource version of FMS is Red Five.&lt;br&gt;&lt;br&gt;In what situations are these libraries breaking down?&lt;br&gt;* Transparent/Opaque proxies that give repeats/dupes/hangs. Keep buffer on server and check for these. Sometimes have to close connection to flush thru proxies.&lt;br&gt;* "Everyone focuses on the newest hottest event-based framework, but the hardest part is that HTTP wasn't designed for long-polling."&lt;br&gt;&lt;br&gt;Have to hold open request/response pairs. Connection setup and teardown is expensive&lt;br&gt;&lt;br&gt;Guy at UK telecom has only ~3K IP connections available in London area. Comet is going to force an upgrade of their hardware, which will be expensive. Real world constraints will always present.&lt;br&gt;&lt;br&gt;Real-time at UI can be distracting at best, horribly annoying at worst. Charts work great, but text moving too quickly becomes hard. UX is challenging. Would be nice to add items while autoscrolling relative to the focussed item&lt;br&gt;&lt;br&gt;When you want to add a pause button to your site, that's FAIL. But the hover-over-conversation to pause semantic is pretty good.&lt;br&gt;&lt;br&gt;Go to jschat.com to see a bad resize.&lt;br&gt;&lt;br&gt;FB pioneered notifications really well in UX. You get a "toaster popup" that doesn't disturb your screen and it fades after a few moments plus a bar at the bottom to persist the aggregated notifications/count. Really nice.&lt;br&gt;&lt;br&gt;Growl is also mentioned as a good model. Is there interest in a notification aggregator with contexts in the browser? Meebo wants to go that way as a notification aggregator. Adobe wants to do this on your desktop. BrowserPlus also hits Growl. Prowl == Pushed Growl.&lt;br&gt;&lt;br&gt;If everyone started using XMPP, it would increase the message load ("three bazillion individual messages"). No one is bundling XMPP updates; no reason you couldn't. ActivityStreams could also serve. &lt;br&gt;&lt;br&gt;Why are people using Atom/JSON for this? They're so extensible, but when you extend them so far they're just as verbose as XML. "But we just don't like XML."&lt;br&gt;&lt;br&gt;Would be nice if you could select things to pull out of the stream and hold onto.&lt;br&gt;&lt;br&gt;Seems to be consensus that chat belongs at the bottom of the browser, append at end. Everything with a permalink (blogs, tweets, etc) gets added to the top (?). Seems to be related to height issues.&lt;br&gt;&lt;br&gt;Infinite scroll vs. "More" button&lt;br&gt;&lt;br&gt;Titlebar flash (Gmail and GTalk)&lt;br&gt;&lt;br&gt;Some sites make a tiny flash widget to play a sound&lt;br&gt;&lt;br&gt;Haptic: twitter dmesg to cellphone buzz&lt;br&gt;&lt;br&gt;Notifications can become another form of info overload/noise&lt;br&gt;&lt;br&gt;(We flailed at making a 1D/2D chart to represent frequency and value ... FAIL)&lt;br&gt;&lt;br&gt;Phonetop apps are like desktop apps. Leah feels strongly that they're headed down-and-to-the-right and browser-ish apps are taking supremacy due to interoperability.&lt;br&gt;&lt;br&gt;Apple's surprise: phonetop apps took off. (?) vs. John Gruber: "The most used app on my iPhone is Safari."&lt;br&gt;&lt;p&gt;You can find the whiteboard pics in &lt;a href="http://flickr.com/photos/purp"&gt;my Flickr stream&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=PhsLbIvqUOE:g-kKjktS3Hc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=PhsLbIvqUOE:g-kKjktS3Hc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=PhsLbIvqUOE:g-kKjktS3Hc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=PhsLbIvqUOE:g-kKjktS3Hc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/PhsLbIvqUOE" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/10/live-blog-comet-other-browser-stuff.html</feedburner:origLink></entry>
    <entry>
        <title>Live Blog: Web Aggregation, What Works and What Doesn't</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/68BHwCcK_Gk/live-blog-web-aggregation-what-works-and-what-doesnt.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20120a6406ae1970c" title="Live Blog: Web Aggregation, What Works and What Doesn't" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20120a6406ae1970c</id>
        <published>2009-10-15T12:17:59-07:00</published>
        <updated>2009-10-19T21:06:53Z</updated>
        <summary type="html">[note: I originally scribbled this on paper thinking I could hand it off immediately, preventing the obligation of typing, posting, etc. Turns out I don't get off that lightly, so here's the spew in electrons.] Scraping isn't a scalable model.There...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Data Portability" />
        <category term="Identity" />
        <category term="Social Networks" />
        <category term="Web 2.0" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;p&gt;&lt;em&gt;[note: I originally scribbled this on paper thinking I could hand it off immediately, preventing the obligation of typing, posting, etc. Turns out I don't get off that lightly, so here's the spew in electrons.]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Scraping isn't a scalable model.&lt;/p&gt;There are biz issues around aggregating data: many businesses don't want you to get their data, though many are becoming more open.&lt;br&gt;&lt;br&gt;Doing aggregation right:&lt;br&gt;* minimize latency&lt;br&gt;* maximize engagement&lt;br&gt;&lt;br&gt;When latency is high, it causes confusion and takes you out of real-time&lt;br&gt;&lt;br&gt;Doing conditional gets can be somewhat useful.&lt;br&gt;&lt;br&gt;Plaxo had to shard their crawlers, which lands you in the shared state/sync problem of any stateful system you want to scale horizontally.&lt;br&gt;&lt;br&gt;Gnip integration has been good:&lt;br&gt;* Offload the long-running processes&lt;br&gt;* Gnip offers alerting or "fat ping" (ping includes update data)&lt;br&gt;&lt;br&gt;Plaxo likes using the alert to escalate the priority of the crawler which fetches the rich data related to the update. This approach allows you to use a consistent model for content ingestion vs. get info from fat ping, then augment later.&lt;br&gt;&lt;br&gt;Smarr: "Brad Fitzpatrick said, 'Make polling a special case of push.'" &lt;span style="text-decoration: line-through;"&gt;He attributed this to someone but I missed the attribution.&lt;/span&gt; &lt;br&gt;&lt;br&gt;(Don't try to keep up with Joseph Smarr on paper. He's thinks too many cogent thoughts too quickly to preserve legibility)&lt;br&gt;&lt;br&gt;Plaxo uses TripIt's RSS feed as alerting, grabs item ID, then uses their APIs to fetch rich data.&lt;br&gt;&lt;br&gt;There's a move to homogenize the info from sites, which may not be a good idea. It suppresses the distinctive look and feel/experience of the publishing site. Allowing for these differences means more labor spent on making one-off shims, which increases maintenance. Still, right choice in order to provide value to the user.&lt;br&gt;&lt;br&gt;Activity streams seek to provide more rich data in a somewhat normalized, extensible format.&lt;br&gt;&lt;br&gt;Many/most sites aren't yet perfectly architected for real-time's push, ping, etc.&lt;br&gt;&lt;br&gt;PubSubHubBub and Activity Streams are externally represented data shards&lt;br&gt;&lt;br&gt;Plaxo's Pulse started with known architecture issues (in order to ship) and hit the wall sooner than expected. Threw hardware/software optimizations at the problem to move the wall far enough to give time for rearchitecture, sharding, and working out how to propagate changes throughout the system properly.&lt;br&gt;&lt;br&gt;None of the NoSQL alternatives are quite ready for prime-time. Smarr: "It should be something that's just a primitive."&lt;br&gt;&lt;br&gt;Conversation platforms are slightly different sorts of aggregation platforms. There are UI diffs (e.g. pause the stream when indicating interest). Handling the transition from slightly-latent/passive real-time to synchronous real-time/active not yet well-developed (think: when a comment inspires a conversation)&lt;br&gt;&lt;br&gt;90-99% of the value of the real-time web is realized in not-real-time [unreal-time? ;] This is a big deal for discovery. Twitter and FB make this harder by obscuring history.&lt;br&gt;&lt;br&gt;Ideal scalability/performance would be an index per user. This would be grossly inefficient due to the number of duplicate entries.&lt;br&gt;&lt;br&gt;No one has nailed reader-controlled aggregation (Show me Joe's tweets and blogs but not his photos) quite yet.&lt;br&gt;&lt;br&gt;Smarr: "If we're all kinda [sharing], we're all making each other smarter"&lt;br&gt;&lt;br&gt;The firehose of info is a hard model to scale to. Ben Metcalfe proposes the garden hose -- a firehose filtered at the source according to your interests, which helps aggregators by allowing them to request the superset of all filters from a given publisher.&lt;br&gt;&lt;br&gt;We really want to push contexts to the publishers and let them determine which content fits that context. Context shifts over time: Joe doesn't normally read my tweets (and why would he?) but when we're at a conference together, he's much more interested (thus the popularity of hashtags). This is a geographic and purpose-driven context (the conference) as well as Joe's context on me (Jim knows where the good bars are).&lt;br&gt;&lt;br&gt;Folks like Twitter are so overloaded with info that they might not recognize non-immediate contexts that are interesting to me.&lt;br&gt;&lt;br&gt;There's also the risk of exposing users to the amount of correlatable public data they have. Many don't want you to apply a transitive closure to identify them in all spaces even though doing so allows you to present a much more convenient UX around what they want you to aggregate.&lt;br&gt;&lt;br&gt;Someone likened the real-time aggregation problem to a bar conversation: you get snippets here and there and follow your own thread of interestingness.&lt;br&gt;&lt;br&gt;Three fundamental themes:&lt;br&gt;* How to specify contexts to data provider/publisher&lt;br&gt;* How to control access to private data (and carry ACLs with that data)&lt;br&gt;* How to do all this efficiently&lt;br&gt;&lt;br&gt;Plaxo implemented polling-back-off (poll infrequently updated sources less frequently). Turns out this is a bad idea, as it introduces latency which makes it feel broken.&lt;br&gt;&lt;br&gt;There's also the issue of aggregating conversation about web objecs (like blog posts) and how not to divert the conversation from the publisher's site. However, sometimes you want a private discussion of a public object (cf. LinkedIn company groups discussing an article)&lt;br&gt;&lt;br&gt;Q: What's the state of open standards around this?&lt;br&gt;A: PubSubHubBub and Activity Streams are very exciting. OAuth as access delegation. There's still a lot of ground to cover.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=68BHwCcK_Gk:7YzEexYWe_s:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=68BHwCcK_Gk:7YzEexYWe_s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=68BHwCcK_Gk:7YzEexYWe_s:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=68BHwCcK_Gk:7YzEexYWe_s:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/68BHwCcK_Gk" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/10/live-blog-web-aggregation-what-works-and-what-doesnt.html</feedburner:origLink></entry>
    <entry>
        <title>Stepping Into BDD with Cucumber and WebRAT: Structuring the Work</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/nP8qPO2DCqI/stepping-into-bdd-with-cucumber-and-webrat-structuring-the-work.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20120a5c108cb970c" title="Stepping Into BDD with Cucumber and WebRAT: Structuring the Work" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20120a5c108cb970c</id>
        <published>2009-09-13T14:45:32-07:00</published>
        <updated>2009-09-14T06:59:48Z</updated>
        <summary type="html">This is the first of a series on my adventures in going BDD with Cucumber and WebRAT with a greenfield project. Watch for the next article coming soon. I'm working on a tiny project for the dads club at my...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&lt;em&gt;This is the first of a series on my adventures in going BDD with Cucumber and WebRAT with a greenfield project. Watch for the next article coming soon.&lt;/em&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;I'm working on a tiny project for the dads club at my son's school and using the opportunity to plunge fully into BDD with Cucumber. I've been tinkering with it a bit here and there, but this time I'm committing to fully specifying my acceptance criteria before I start writing specs for my implementation. I have to admit it feels a bit onerous right now, but I can see the value coming so I'm sticking to it.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;My usual working methodology is:&lt;/p&gt;&#xD;
&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;Write a quick set of use cases&lt;/li&gt;&#xD;
&lt;li&gt;Infer features from the use cases&lt;/li&gt;&#xD;
&lt;li&gt;Divide the features into logical delivery phases&lt;/li&gt;&#xD;
&lt;li&gt;Start spec'ing the implementation&lt;/li&gt;&#xD;
&lt;li&gt;Code to the specs&lt;/li&gt;&#xD;
&lt;li&gt;Profit!&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;... so really I'm just adding a "Specify features using Cucumber" step between 3 and 4. Sounds small (but it's not).&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;The use cases for this project are pretty easy:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="brush: plain; light: true;"&gt;&#xD;
Use Cases:&#xD;
&#xD;
NON-MEMBERS:&#xD;
* Join&#xD;
&#xD;
MEMBERS:&#xD;
* See news postings&#xD;
* See calendar events&#xD;
* Subscribe to a calendar feed&#xD;
* Read and send email to the group&#xD;
* Maintain a member profile (email, phone, location, kid info, etc.)&#xD;
* Browse and search a member directory (by grade, class, proximity/map, etc.)&#xD;
&#xD;
PREZ FOR LIFE:&#xD;
* Write news postings&#xD;
* Post new events&#xD;
* Send news/reminders to various publishers (group mailing list, school newsletter editor, etc.)&#xD;
&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;(Yeah, we have a President For Life. He's awesome.)&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Time to break these into features. I try to scope each delivery to be a useful increase in features and something I can delivery quickly (I don't get much geek time these days ;). Some of this is old hat (it's mostly just a CMS), but some of it calls for me to learn about things I've never played with (Google Maps APIs and Geolocation, for example). Additionally, it was important to get something up fast last week so the main URL could be included in some printed materials for back to school week.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Here's the feature rough divided into phases:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="brush: plain; light: true;"&gt;&#xD;
Phase 0: Site&#xD;
Non-Members can see front page&#xD;
&#xD;
Phase 1: Members&#xD;
Non-Members can join&#xD;
Members can sign in with email and password or OpenID&#xD;
PFL can manage news items&#xD;
PFL can manage events&#xD;
PFL can manage pages&#xD;
PFL can suspend accounts of non-PFLs&#xD;
Members can view news and events&#xD;
News snippets and event titles show on top page&#xD;
&#xD;
Phase 2: Admins&#xD;
Members can be made admin by PFL&#xD;
Admins can manage news items&#xD;
Admins can manage events&#xD;
Admins can manage pages&#xD;
&#xD;
Phase 3: Feeds and Mailings&#xD;
Members can subscribe to news and events feeds&#xD;
PFL can set reminders to be sent by email&#xD;
Members can recover passwords by email&#xD;
&#xD;
Phase 4: Profiles&#xD;
Members can add email, phone, address, availability, notes, profile pic&#xD;
Members can add kids: name, age, picture, teacher&#xD;
Members can mark info private, admin-only, or open&#xD;
&#xD;
Phase 5: Directory&#xD;
Members can browse directory info&#xD;
&#xD;
Phase 6: Maps&#xD;
Members can see people, events on map&#xD;
&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;Phase 0 was "get something up fast;" we made it a simple redirect to the existing Google group. Phase 1 is the biggest chunk of features, but they're very straightforward. Each phase after that introduces enough new functionality to be interesting for the members, but in small enough chunks that I should be able to knock 'em out in a weekend, plus-or-minus.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Okay, so now I'm ready to generate the app and cucumber-ify it. I'll cover that in the next article.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=nP8qPO2DCqI:1aGLt6vXTr0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=nP8qPO2DCqI:1aGLt6vXTr0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=nP8qPO2DCqI:1aGLt6vXTr0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=nP8qPO2DCqI:1aGLt6vXTr0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/nP8qPO2DCqI" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/09/stepping-into-bdd-with-cucumber-and-webrat-structuring-the-work.html</feedburner:origLink></entry>
    <entry>
        <title>Generate the regex for a TLD hostname from Perl</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/mPeL-ZDLi50/generate-the-regex-for-a-tld-hostname-from-perl.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20120a5030397970b" title="Generate the regex for a TLD hostname from Perl" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20120a5030397970b</id>
        <published>2009-08-18T19:05:19-07:00</published>
        <updated>2009-09-14T05:56:45Z</updated>
        <summary type="html">This was a quick, fun exercise to remind me that I can still write Perl. It fetches the list of TLDs from IANA, does a quick bit of munging, then renders a regex which should match any valid FQDN: #!/usr/bin/env...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>
        <category term="Hacking" />

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;This was a quick, fun exercise to remind me that I can still write Perl. It fetches the list of TLDs from IANA, does a quick bit of munging, then renders a regex which should match any valid FQDN:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="brush: perl"&gt;&#xD;
#!/usr/bin/env perl&#xD;
use strict;&#xD;
use warnings;&#xD;
&#xD;
use LWP::Simple;&#xD;
&#xD;
my $fqdn_regex;&#xD;
&#xD;
if (my $content = get('http://data.iana.org/TLD/tlds-alpha-by-domain.txt')) {&#xD;
  $fqdn_regex = '(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:';&#xD;
  $fqdn_regex .= join('|', grep (!/^(#|xn)/i, (split /\n/, lc($content))));&#xD;
  $fqdn_regex .= ')';&#xD;
}&#xD;
&#xD;
my $regex = $fqdn_regex . '(?:\s|\/|$)';&#xD;
print "$regex\n";&#xD;
&lt;/pre&gt;&lt;p&gt;&#xD;
&#xD;
Several caveats:&lt;/p&gt;&#xD;
&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;It doesn't match IPv4 dotted quad nor IPv6 ::-notation&lt;/li&gt;&#xD;
&lt;li&gt;It intentionally ignores Internationalized Domain Name in Applications (IDNA) domains&lt;/li&gt;&#xD;
&lt;li&gt;It borrows from my favorite reference for this, &lt;a href="http://www.regular-expressions.info/email.html"&gt;regular-expressions.info's page on email address regexes&lt;/a&gt;.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
Maybe I'll extend it for completeness and/or rewrite it in Ruby someday. Until then, it'll always be &lt;tt&gt;~/bin/tld_regex&lt;/tt&gt; for me.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=mPeL-ZDLi50:p7PPzYBIWJM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=mPeL-ZDLi50:p7PPzYBIWJM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=mPeL-ZDLi50:p7PPzYBIWJM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=mPeL-ZDLi50:p7PPzYBIWJM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/mPeL-ZDLi50" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/08/generate-the-regex-for-a-tld-hostname-from-perl.html</feedburner:origLink></entry>
    <entry>
        <title>Gmail no longer beta? True dat.</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/oc5izlVVxcY/gmail-no-longer-beta-true-dat.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e2011570df1509970c" title="Gmail no longer beta? True dat." />
        <id>tag:typepad.com,2003:post-6a00d83452448969e2011570df1509970c</id>
        <published>2009-07-07T10:12:31-07:00</published>
        <updated>2009-07-07T17:59:13Z</updated>
        <summary type="html">I guess it's no longer under construction, or so sayeth the GMail blog which also shows those who can't live without that ubiquitous beta tag how to bring back their old friend:</summary>
        <author>
            <name>Jim Meyer</name>
        </author>

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;p&gt;I guess it's no longer &lt;a href="http://blog.geekdaily.org/2007/07/beta-is-the-web.html"&gt;under construction&lt;/a&gt;, or so sayeth &lt;a href="http://gmailblog.blogspot.com/2009/07/gmail-leaves-beta-launches-back-to-beta.html"&gt;the GMail blog&lt;/a&gt; which also shows those who can't live without that ubiquitous beta tag &lt;a href="http://mail.google.com/mail/?shva=1#settings/labs"&gt;how to bring back their old friend&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="http://mail.google.com/mail/?shva=1#settings/labs" onclick="window.open(this.href,'_blank','scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" style="display: inline;"&gt;&lt;img alt="Back2beta" border="0" class="at-xid-6a00d83452448969e2011570df13e4970c " src="http://purp.typepad.com/.a/6a00d83452448969e2011570df13e4970c-pi" style="width: 600px;" title="Back2beta"&gt;&lt;/img&gt;&lt;/a&gt; &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=oc5izlVVxcY:QIGRwu_gMDI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=oc5izlVVxcY:QIGRwu_gMDI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=oc5izlVVxcY:QIGRwu_gMDI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=oc5izlVVxcY:QIGRwu_gMDI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/oc5izlVVxcY" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/07/gmail-no-longer-beta-true-dat.html</feedburner:origLink></entry>
    <entry>
        <title>Michael Jackson's Obit via Wordle</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/uxbxJV2GOI4/michael-jacksons-obit-via-wordle.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=6a00d83452448969e20115715bf46d970b" title="Michael Jackson's Obit via Wordle" />
        <id>tag:typepad.com,2003:post-6a00d83452448969e20115715bf46d970b</id>
        <published>2009-06-25T18:40:55-07:00</published>
        <updated>2009-06-26T01:42:22Z</updated>
        <summary type="html">Story by Yahoo!, picture by Wordle.net:</summary>
        <author>
            <name>Jim Meyer</name>
        </author>

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Story by &lt;a href="http://news.yahoo.com/s/ap/us_obit_michael_jackson"&gt;Yahoo!&lt;/a&gt;, picture by &lt;a href="http://www.wordle.net/gallery/wrdl/970425/Michael_Jackson_Died"&gt;Wordle.net&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.wordle.net/gallery/wrdl/970425/Michael_Jackson_Died" title="Wordle: Michael Jackson Died"&gt;&lt;img  alt="MJ Obit Wordle" class="at-xid-6a00d83452448969e20115715bf294970b image-full " src="http://purp.typepad.com/.a/6a00d83452448969e20115715bf294970b-800wi" title="MJ Obit Wordle" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/div&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=uxbxJV2GOI4:3_Any_yHwks:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=uxbxJV2GOI4:3_Any_yHwks:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=uxbxJV2GOI4:3_Any_yHwks:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=uxbxJV2GOI4:3_Any_yHwks:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/uxbxJV2GOI4" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/06/michael-jacksons-obit-via-wordle.html</feedburner:origLink></entry>
    <entry>
        <title>LiveBlog: 10+ Deploys A Day: Dev and Ops at Flickr</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/geekdailyblog/~3/FwBB8lNJSMU/liveblog-10-deploys-a-day-dev-and-ops-at-flickr.html" />
        <link rel="service.edit" type="application/x.atom+xml" href="http://www.typepad.com/t/atom/weblog/blog_id=318602/entry_id=68418755" title="LiveBlog: 10+ Deploys A Day: Dev and Ops at Flickr" />
        <id>tag:typepad.com,2003:post-68418755</id>
        <published>2009-06-23T13:47:46-07:00</published>
        <updated>2009-06-26T00:06:49Z</updated>
        <summary type="html">Update 1: Slides are now on SlideShare. Update 2: Video now available on blip.tv John Allspaw (Ops) &amp;amp; Paul Hammond (Eng), Twitter “Actually work together and aren’t huge assholes to each other.” (omitted: photo stats … that’s a lot of...</summary>
        <author>
            <name>Jim Meyer</name>
        </author>

    <content type="html" xml:lang="en-us" xml:base="http://blog.geekdaily.org/">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&lt;br&gt;Update 1: &lt;a href="http://www.slideshare.net/jallspaw/10-deploys-per-day-dev-and-ops-cooperation-at-flickr"&gt;Slides are now on SlideShare.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Update 2: &lt;a href="http://velocityconference.blip.tv/file/2284377"&gt;Video now available on blip.tv&lt;/a&gt;&lt;/p&gt;&lt;p&gt;John Allspaw (Ops) &amp;amp; Paul Hammond (Eng), Twitter&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;“Actually work together and aren’t huge assholes to each other.”&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;(omitted: photo stats … that’s a lot of kittens)&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
Dev vs. Ops&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;It’s not my {machines,code} it’s your {code,machines}&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Spock v. Scottie analogy&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Ops as grumpy old man, says no all the time, cycle of “no all the time because no one tells them anything because they say no all the time”&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;CW: dev job to add features, ops job to keep site stable and fast&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Flickr: Ops job is to enable the business (Dev’s, too)&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Business requires change, otherwise you’ll be overtaken by the new guy … but change is the root cause of most outages.&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Discourage change vs. Allow it to happen as often as it needs to (via tools and culture)&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
Lowering the risk of change via tools and culture.&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Increase confidence in change goodness&lt;/li&gt;&#xD;
		&lt;li&gt;Increase ability to react to those changes&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;You need {ops,devs} who think like {dev,ops}&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;1. Role and Config Mgmt&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
2. Shared Version Control: everyone looks in the same place for everything&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Code and config in same place&lt;/li&gt;&#xD;
		&lt;li&gt;Everyone has access—transparency&lt;/li&gt;&#xD;
		&lt;li&gt;Everyone knows how to use it&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
3a. One-step build&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Everything you need to do to convert svn co’d code into what goes to the site—one command&lt;/li&gt;&#xD;
		&lt;li&gt;They have “Perform Staging” button at bottom of a page with stats on latest commit&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
3b. One-step deploy&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Top of page is deploy log with notes: who, when, what (link to changes)&lt;/li&gt;&#xD;
		&lt;li&gt;Bottom has “I’m feeling lucky!” button to deploy&lt;/li&gt;&#xD;
		&lt;li&gt;Continuous deployment&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;You can’t pretend to deploy 10 times a day if you go down 10 times a day. That’s not being agile, that’s being retarded.&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;They use Hudson to generate packages which can be deployed by ops&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Small frequent changes make it easier to see what went wrong and recover when needed&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
4. [missed that tag]&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Branching is all about managing bugfixes&lt;/li&gt;&#xD;
		&lt;li&gt;Always ship trunk&lt;/li&gt;&#xD;
		&lt;li&gt;Branch in code instead: use conditionals to block out pre-release features and configure off/invis—provides an operational lever for adjustment&lt;/li&gt;&#xD;
		&lt;li&gt;Makes these open for private beta in production on production hdwe, etc.&lt;/li&gt;&#xD;
		&lt;li&gt;Allows dark launches, which allows you to size appropriately, fix major oversights, take the fear out of major new launches&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;They have a couple hundred “free contingency switches” to turn things off/throttle things down. Gives broad operational control to minimize effects on the site.&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Tend to fail forward using these and fix the problem.&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
5. Shared metrics&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;You can see mine, I can see yours&lt;/li&gt;&#xD;
		&lt;li&gt;Use ganglia as console&lt;/li&gt;&#xD;
		&lt;li&gt;Devs know where dashboard is, and watch as obsessively as ops&lt;/li&gt;&#xD;
		&lt;li&gt;Includes app-level metrics (which exposes them to Ops)&lt;/li&gt;&#xD;
		&lt;li&gt;(helps drive accountability in both directions in the org—both can see and feel ownership)&lt;/li&gt;&#xD;
		&lt;li&gt;This begins to create opportunity to gracefully collaborate to back off an oversub’d resource/degrade/throttle as needed&lt;/li&gt;&#xD;
		&lt;li&gt;Show last site deploy info on every page/graph; you can corellate a change in the graph&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
6. &lt;span class="caps"&gt;IRC&lt;/span&gt; and IM bots&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Heavy &lt;span class="caps"&gt;IRC&lt;/span&gt; users for ongoing dialog between dev/ops, remote/local&lt;/li&gt;&#xD;
		&lt;li&gt;Last.fm wrote a tool to inject events into &lt;span class="caps"&gt;IRC&lt;/span&gt; (monitoring, events, deployments, builds)&lt;/li&gt;&#xD;
		&lt;li&gt;Log it all and put it in a search engine&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Culture&lt;/p&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;All the tools in the world won’t help if you have a contentious culture&lt;/p&gt;&lt;p&gt;&#xD;
&#xD;
&#xD;
1. Respect&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;No stereotypes: not all devs are lazy/cowboys, not all ops are obstructive&lt;/li&gt;&#xD;
		&lt;li&gt;respect their expertise and opinions &lt;strong&gt;and&lt;/strong&gt; responsibilities (they influence priorities)&lt;/li&gt;&#xD;
		&lt;li&gt;Don’t just say “no”—it’s like saying “I don’t care about your problem/perspective” &lt;/li&gt;&#xD;
		&lt;li&gt;Best solutions are collaborative. Memcache is an excellent example; written to solve the problem of DB overheat, which impacted both&lt;/li&gt;&#xD;
		&lt;li&gt;Don’t hide things: share your solution even if you think they’ll say no; you deny their expertise and input&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
Talk about the impact of your code push&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;What metrics change&lt;/li&gt;&#xD;
		&lt;li&gt;what are the risks&lt;/li&gt;&#xD;
		&lt;li&gt;what are the symptoms of somethign going wrong&lt;/li&gt;&#xD;
		&lt;li&gt;what are the contingencies (rollback)&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
2. Trust&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;When you walk up with all the above on hand, you demonstrate that you care enough about them and the business&lt;/li&gt;&#xD;
		&lt;li&gt;“I don’t want to tell X …” == you’re a cowboy, and “cowboys are losers” &lt;/li&gt;&#xD;
		&lt;li&gt;Have shared playbooks and contingency plans so all understand.&lt;/li&gt;&#xD;
		&lt;li&gt;Provide as many knobs and levers as you can so Ops can tweak to match the env&lt;/li&gt;&#xD;
		&lt;li&gt;Ops: be transparent, give devs insight and access to the systems. Playing telephone around shell commands is dumb.&lt;/li&gt;&#xD;
		&lt;li&gt;It’s hard to help if you can’t directly see&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
3. Have a healthy attitude around failure—it’s going to happen.&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;Think about how you’ll respond more than you think about how you’ll prevent it&lt;/li&gt;&#xD;
		&lt;li&gt;Would you rather be treated by a GP who deals with heart attacks infrequently or an &lt;span class="caps"&gt;EMT&lt;/span&gt; who handles them weekly?&lt;/li&gt;&#xD;
		&lt;li&gt;Fire drills: when ops and sr engineers are fixing a problem, have others diagnose live in parallel (but make no changes!)&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&lt;p&gt;&#xD;
&#xD;
&#xD;
4. Avoiding blame&#xD;
	&lt;/p&gt;&lt;ul&gt;&#xD;
	&lt;li&gt;they have a rule of no-finger-pointing; it doesn’t need enforcement, folks step up&lt;/li&gt;&#xD;
		&lt;li&gt;fixing blame wastes a ton of time, why not skip it? Feel guilty afterwards if you must.&lt;/li&gt;&#xD;
		&lt;li&gt;They’ve got a bit of a potlatch culture as people try to assert responsibility in order to fix things.&lt;/li&gt;&#xD;
		&lt;li&gt;Remember that when your code breaks, someone’s going to have to wake up to fix it. Own it and apologize, at least. Otherwise, you’re back to not respecting each other (“Screw you … aren’t you getting paid to do that?”)&lt;/li&gt;&#xD;
	&lt;/ul&gt;&#xD;
&#xD;
&#xD;
	&lt;p&gt;Ops should provide constructive, continual feedback on how it’s going. Point out interesting things before they’re critical&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=FwBB8lNJSMU:zGxPIjYxa9w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=FwBB8lNJSMU:zGxPIjYxa9w:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/geekdailyblog?a=FwBB8lNJSMU:zGxPIjYxa9w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/geekdailyblog?i=FwBB8lNJSMU:zGxPIjYxa9w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/geekdailyblog/~4/FwBB8lNJSMU" height="1" width="1"/&gt;</content>



    <feedburner:origLink>http://blog.geekdaily.org/2009/06/liveblog-10-deploys-a-day-dev-and-ops-at-flickr.html</feedburner:origLink></entry>

</feed><!-- ph=1 -->
