<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Overactive Vocabulary]]></title>
  <link href="http://nathaniel.talbott.ws/atom.xml" rel="self"/>
  <link href="http://nathaniel.talbott.ws/"/>
  <updated>2022-05-16T14:04:51-04:00</updated>
  <id>http://nathaniel.talbott.ws/</id>
  <author>
    <name><![CDATA[Nathaniel]]></name>
    <email><![CDATA[nathaniel@talbott.ws]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[The Third Decade]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2019/01/14/the-third-decade/"/>
    <updated>2019-01-14T09:00:00-05:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2019/01/14/the-third-decade</id>
    <content type="html"><![CDATA[<p>Or, <em>I’m Stepping Back from Daily Operations at Spreedly</em></p>

<p>My professional life has run roughly in decades: a first decade of getting into the software industry, doing lots of consulting and contracting, and observing businesses being run. The second decade grew out of the first decade and was spent founding a product company and figuring out - alongside a lot of really smart people - how to grow Spreedly into something successful. The boundaries between these vocational periods are of course fuzzy, but over the course of 2018 I’ve unknowingly been wrapping up my second decade, and the end of 2018 has become a clear break from my time working on Spreedly on a day-to-day basis.</p>

<p>Here’s the thing: Spreedly’s in a fantastic spot to win. I feel really good about stepping away right now with the company profitable, compounding sales growth, a great leadership team, and a product that has one of the lowest tech debt loads of any production system I’ve ever worked on. And I’m not disappearing into a black hole: I’ll remain a shareholder, continue to advise the company via my position on the board, and be cheering the team on from the sidelines every step of the way.</p>

<p>Why am I leaving? As these things usually are, it’s complicated. Here’s the short version: there were differences of opinion on my role as Spreedly grows past 50 employees. And I mean “opinion” sincerely - I haven’t even been present at a product company as it went from 50 to 100 employees before, much less been an executive working on it at that stage, so my perspective shouldn’t weigh more. And since I wasn’t able to get on the same page about my role going forward, I didn’t want to get in Spreedly’s way as it continues to grow.</p>

<p>What’s next for me? I ask rather, “What better time for a mid-life crisis?” and I’m only half-joking: while I’m not in crisis, I have about a million ideas for what I might want to work on next, but 2019 is all about getting back to the basics of creation: writing consistently and programming consistently. These two skills have formed the bedrock of my career to date, and I’m excited (and terrified) to pull my creative focus away from Spreedly and put it into a series of smaller projects designed to hone these two fundamental skills while exploring a series of hypotheses about what my next major endeavor might be.</p>

<p>Alongside the fundamentals, I also expect to do a lot of networking in 2019, so do drop me an email if you want to grab coffee or even just video chat. This goes double if you’re a CEO, CTO, or VP of Engineering in a company in the 10-50 employee range trying to figure out how to wrangle engineers and the software they build - that’s where all my scars are from and I feel like I can speak with some confidence about what works and what doesn’t.</p>

<p>Weep not for me! I’m super excited to dig into the third decade of my career. And worry not for Spreedly: it’s set up to win, top to bottom, with an amazing team building an amazing product. Instead, grab some sunglasses: the future is bright everywhere you look. 😎</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Warcraft, DOSBox, IPX, and Tomato Shibby, Oh My!]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2015/11/28/warcraft-dosbox-ipx-tomato-shibby-oh-my/"/>
    <updated>2015-11-28T17:38:00-05:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2015/11/28/warcraft-dosbox-ipx-tomato-shibby-oh-my</id>
    <content type="html"><![CDATA[<p>I&#8217;m a nerd. A total, unadulterated, no-holds-barred, nerd. Let this post serve as proof for posterity&#8230;</p>

<p>This little vignette starts with Warcraft. See, I have kids. Quite a few kids. And they&#8217;re getting old enough it&#8217;s fun to play games with them. Now, if I was a normal father, I&#8217;d buy them modern computers and we could play modern multiplayer video games like normal people. I am not a normal father; rather, if you&#8217;ll recall, I&#8217;m a nerd, which makes me a nerd father. Which means, when I think, &#8220;it&#8217;d be fun to play a multi-player video game with the kids,&#8221; my mind harkens back to some of the most fun I had playing multiplayer as a kid: Warcraft.</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/warcraft2-cd.jpg" title="Warcraft 2 CD" class="right" /></p>

<p>More specifically: <a href="http://wowwiki.wikia.com/wiki/Warcraft_II:_Tides_of_Darkness">Warcraft II: Tides of Darkness</a>.</p>

<p>OK, first step is, can we even play it on a computer made in the last decade? Turns out we can - and quite easily - using <a href="http://www.dosbox.com/">DOSBox</a>. DOSBox is a nerdy dad&#8217;s best friend when it comes time to introduce his kids to the classic experience of a LAN party. Since around here even our &#8220;old computers&#8221; run OS X, I&#8217;m a big fan of <a href="http://boxerapp.com/">Boxer</a> for making DOSBox a cinch to setup and manage.</p>

<p>So far things aren&#8217;t <em>too</em> nerdy, but we&#8217;re nowhere near done yet. The next step is networking, and this is where it gets interesting. Old games mostly use <a href="https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange">IPX</a>, and IPX is pretty much a dead protocol on modern networks. DOSBox has a cool trick up its sleeve, though: <a href="http://www.dosbox.com/wiki/Connectivity">it translates IPX to UDP, and it works without a hitch</a>.</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/dosbox-network-dialog.jpg" title="DOSBox Networking Setup Dialog" class="left"/></p>

<p>While hitchless, this IPX-over-UDP setup is kind of a pain; one player has to set up their DOSBox to be the server, and the other players have to know and enter the IP address of that player to connect. Kind of a pain in the tuckus to do every single time we want to play, so surely we can do better, right? Wouldn&#8217;t it be awesome if the network at the Talbott house had an always-on IPX server on tap? Why yes it would!</p>

<p>Since we&#8217;re not the first ones on the internet to wish for such a thing (is it possible to be the first at anything on the internet these days?), some searching around turns up <a href="http://www.vogons.org/viewtopic.php?t=27361">ipxrelay</a>, which is such a beautiful, dependency-less, single-purpose tool it makes me want to weep for joy. A quick:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>git clone git://git.zytor.com/games/dosbox/ipxrelay.git
</span><span class='line'><span class="nb">cd </span>ipxrelay
</span><span class='line'>make
</span><span class='line'>./ipxrelay
</span></code></pre></td></tr></table></div></figure>


<p>And we have a working standalone IPX server. Now, I wouldn&#8217;t be comfortable running this on the big bad internet without a deeper understanding of its operation and security, but for internal LAN parties? Sign me up!</p>

<p>But that brings us to our next challenge: where do we run it? I don&#8217;t maintain an always-on server on our home network, nor do I really want to. But actually that&#8217;s not true, since I have three routers running <a href="http://tomato.groov.pl/">Tomato Shibby</a>, and they&#8217;re nothing but mini-servers that have lots of idle capacity that could be put to good use. So I decided to get <code>ipxrelay</code> running on my biggest/fastest Tomato router. No sweat, right?</p>

<p>No sweat, except that running a program written in C on a device like an Asus router means cross-compiling that program. <a href="https://www.asus.com/us/Networking/RTAC66U/">My highest-powered router</a> is a <a href="https://en.wikipedia.org/wiki/MIPS_instruction_set">MIPS device</a>, and Tomato itself has a very distinct and limited set of libraries available, all of which must be taken into account. But people do this all the time, so should be easy, right?</p>

<p>I&#8217;ll save you the multiple weekends and evenings of futzing, hair-pulling, puzzling deadends, and searching in circles. For some reason, nowhere on the internet could I find: &#8220;To cross-compile a program for a Tomato Shibby target do A, B, and C.&#8221; Until now, since that&#8217;s exactly what I&#8217;m going to do in as clear a terms as I can for the sake of future searchers.</p>

<h2>Tomato Shibby Cross-Compiling for Dummies</h2>

<p>It&#8217;s pretty simple really:</p>

<ol>
<li>Be on a Linux box</li>
<li>Checkout a copy of the Tomato Shibby code</li>
<li>Use the included, pre-built compiler to build your application</li>
</ol>


<p>Well, it&#8217;s simple now that I know what to do. Follow these steps to avoid great pain!</p>

<h3>1. Be on a Linux box</h3>

<p>So first I need a Linux box to do the building on since I&#8217;m on OS X and I don&#8217;t need or want the pain of getting cross-compiling working in an environment different than what&#8217;s already used by the Tomato Shibby developers. In real life I built a VM from scratch, but with time for reflection and a blog post to write I&#8217;ve remembered I have Vagrant set up and ready to go here already. Here&#8217;s a little &#8216;cast of me setting up a Debian Vagrant box:</p>

<script type="text/javascript" src="https://asciinema.org/a/30820.js" id="asciicast-30820" async></script>


<h3>2. Checkout Tomato Shibby</h3>

<p>Now that I have a Linux environment to build in, I need to clone the Tomato repo and checkout the tag my router is at:</p>

<script type="text/javascript" src="https://asciinema.org/a/30823.js" id="asciicast-30823" async></script>


<p>Using <code>--branch</code> and <code>--depth</code> reduces the size of the checkout somewhat.</p>

<h3>3. Use the Cross-Compiler</h3>

<p>One rule of step-wise recipes is that one step will always be more complicated than the rest. This is that step. We need to take the program we want to compile, tweak its <code>Makefile</code> to use our cross-compiler, and build the program:</p>

<script type="text/javascript" src="https://asciinema.org/a/30825.js" id="asciicast-30825" async></script>


<p>Wow, it looks easy now that I know exactly what to do. <em>sigh</em></p>

<p>You can copy and paste from the screen cast above - slick, right? - but just in case, the patch referenced is available here: <a href="https://gist.github.com/ntalbott/75a8aa269b2d310bf02f">https://gist.github.com/ntalbott/75a8aa269b2d310bf02f</a>, and the <code>ipxrelay</code> repository is here: <a href="http://git.zytor.com/games/dosbox/ipxrelay.git/">http://git.zytor.com/games/dosbox/ipxrelay.git/</a>.</p>

<h2>Running <code>ipxrelay</code> on the Router</h2>

<p>Now that we have a cross-compiled <code>ipxrelay</code>, we need to get it saved somewhere safe on the router, and ensure it&#8217;s running with the right options. I&#8217;m running mine from a USB flash drive I have plugged in, but I&#8217;ll leave the setup of that as an exercise to the reader. Once it&#8217;s somewhere safe - your options are <code>/jffs</code> (wiped each time you restart the router), some kind of added storage like a my USB drive, or a memory card mounted at <code>/mmc</code> if your router supports it - the next step is to get it fired up. Here&#8217;s the <code>Firewall</code> script I have in the Administration->Scripts area of Tomato to start it up:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>/mnt/ROUTER/bin/ipxrelay --port 2130 --address 192.168.1.1 --pidfile /var/run/ipxrelay.pid
</span></code></pre></td></tr></table></div></figure>


<p>My IPX relay is going to run on port 2130, only bind to my internal IP, and put out a pidfile. The shutdown script then uses the pidfile to properly clean up:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'><span class="k">if</span> <span class="o">[[</span> -e /var/run/ipxrelay.pid <span class="o">]]</span>; <span class="k">then </span><span class="nb">kill</span> <span class="sb">`</span>cat /var/run/ipxrelay.pid<span class="sb">`</span>; rm /var/run/ipxrelay.pid; <span class="k">fi</span>
</span></code></pre></td></tr></table></div></figure>


<p>And there you have it, an always persistent IPX relay on your internal network! You might think we&#8217;re done, but we can go even deeper!</p>

<h2>DOSBox Automation</h2>

<p>What&#8217;s better than having IPX networking consistently available? Using that fact to make our DOSBox games auto-networked, of course! The final thing I did was to create a couple of batch files to auto-configure the IPX setup so that when we launch the game, it Just Works&trade;. We need to put three files in our DOSBox <code>C:</code> to make this work: first, <a href="http://www.freedos.org/software/?prog=find"><code>FIND.COM</code> from FreeDOS</a> since DOSBox doesn&#8217;t come with a <code>FIND</code> built-in. Second, <code>START.BAT</code>, which tries to start IPX networking, and fails out if it can&#8217;t:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>@echo off
</span><span class='line'>
</span><span class='line'>del ipxnets &gt;nul
</span><span class='line'>
</span><span class='line'>ipxnet disconnect &gt;nul
</span><span class='line'>ipxnet connect 192.168.1.1 2130 &gt;nul
</span><span class='line'>ipxnet status &gt;ipxnets
</span><span class='line'>find <span class="s2">&quot;Client status: CONNECTED&quot;</span> ipxnets &gt;nul
</span><span class='line'><span class="k">if </span>errorlevel 1 goto neterror
</span><span class='line'>
</span><span class='line'>call game
</span><span class='line'>goto end
</span><span class='line'>
</span><span class='line'>:neterror
</span><span class='line'><span class="nb">echo </span>Error starting networking...
</span><span class='line'><span class="nb">echo </span>Is ipxrelay started on the router?
</span><span class='line'>goto end
</span><span class='line'>
</span><span class='line'>:end
</span><span class='line'>del ipxnets &gt;nul
</span></code></pre></td></tr></table></div></figure>


<p>And finally, the super-simple <code>GAME.BAT</code>, which just makes <code>START.BAT</code> generic:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>launch war2
</span></code></pre></td></tr></table></div></figure>


<p>DOSBox can be configured to launch <code>START.BAT</code> when it starts, and voila! You&#8217;re all set to crush your offspring - or siblings, or whoever you can convince to have a LAN party with you - at Warcraft 2!</p>

<p>The conclusion of this little piece is the same as the beginning: I am a total nerd. And as aggravating as it sometimes is, it&#8217;s a lot of fun, too!</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/warcraft2-gameplay.jpg" alt="Warcraft 2 Screenshot" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Racing]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/25/racing/"/>
    <updated>2013-03-25T09:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/25/racing</id>
    <content type="html"><![CDATA[<p>Racing is so different than anything else I&#8217;ve ever done. I guess you could call me a primitive racer - I enjoy that most ancient of races, the kind where you put one foot in front of the other as fast as you can - and I can&#8217;t deny it, there&#8217;s something that fascinates me about how my body&#8217;s able to not only run, but to run like it was made from the beginning to do so. There&#8217;s a cathartic joy in just walking out the front door and following wherever your feet take you, even if it is over a well-trodden course. When I started running, I imagined it as a habit to build for my own good, like eating my greens. Now it&#8217;s an activity that I return to whenever I can, like eating my greens, since it turns out greens are delicious both in reality and metaphorically.</p>

<p>But racing is such an odd thing. Running in and of itself isn&#8217;t odd; it&#8217;s just another activity that I undertake on a regular basis. I train, and I push myself, I try to get better, and I return to it as an enjoyable process for its own sake. I can run socially, carrying on a solid conversation while maintaining a pretty good clip, though I&#8217;m generally alone listening to an audio book. And I run at my own convenience: I pick the time, the place, the distance, the pace, etc.</p>

<p>When I line up to start a race, though - then it gets weird. For one thing, I&#8217;ve chosen to get up and run at a crazy hour on a Saturday morning, when I could&#8217;ve just as easily waited a few hours and run out my front door. Or it might be a Sunday afternoon when I&#8217;d normally be enjoying a quiet nap. Or maybe I&#8217;m at a programming conference, dragging myself out of bed after a late night of talking tech to wander through a strange city and try to find the starting line.</p>

<p>And it&#8217;s not like I&#8217;m actually going to run socially in a race - ha! When I race, I like to actually race, so I&#8217;m spending all of my breath and focus on pushing my body to the limits of what it can do, and I can&#8217;t spare an iota of it on the people around me. Racing is super self-centered: it&#8217;s you, the road, and an ever-ticking clock. I don&#8217;t even try to listen to anything while I race, since the necessary apparatus is too much of a distraction. And if I go to a race with a friend, I&#8217;ll wish them luck right before the gun and not see them again until one or the other of us is cheering the other across the finish line.</p>

<p>Then there&#8217;s the fact that in any race large enough to have an official course and chipped time tracking, there&#8217;s no way I&#8217;ll come in first. I go out and run a race knowing that I&#8217;ll make a good showing, but also knowing I&#8217;ll get trounced by some 23 year old that was smart enough to take up running 5k&#8217;s before he turned 30. I&#8217;m not even really a risk to the other guys in my age bracket since, while I love running, I love coding even more and so I won&#8217;t be spending those extra hours training that I&#8217;d need to in order to place even bronze for 30-35.</p>

<p>But here&#8217;s the thing: I love to race. Every time I get out there I think, &#8220;What in the world am I doing here?&#8221; and then the gun fires and I&#8217;m off and I&#8217;m loving it. Someone else has laid down a very specific set of constraints - run this route, start at this time - and now I get to push myself to do the absolute best that I can within those constraints. I&#8217;m not being social, and yet I have this whole host of humanity in so many (admittedly all very fit) varieties, and I get to run beside and behind and around them. And while I&#8217;ll never come in first, I get to race myself on the course, seeing if I can best my own best and show that I have continued to improve and grow since the last time I crossed the line.</p>

<p>Racing is so bizarre, and I love every minute of it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Monitoring Hotness]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/22/segment-io-and-librato/"/>
    <updated>2013-03-22T10:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/22/segment-io-and-librato</id>
    <content type="html"><![CDATA[<p>I&#8217;ve spent the last couple of weeks hooking up a bunch of monitoring and analytics to our systems at <a href="https://spreedly.com/">Spreedly</a>. It&#8217;s long overdue, but with the big launch of our new messaging we needed more data so we weren&#8217;t flying blind and could make decisions going forward based on hard numbers. The work has encompassed both business metrics (page views, signups, subscriptions, &#8230;) and devops metrics (response times, request counts, &#8230;).</p>

<p>I&#8217;ll admit, we&#8217;ve tried to do this a couple of times before, and every time I&#8217;ve been stymied by two things: first, the overwhelmingness of both trying to choose between a lot of well regarded options, and at the same time trying to figure out what we should be tracking. Second, hooking up metrics is not a trivial task, and when there are other things I can be doing that at least appear to add more value to the bottom line, I tend to quickly get distracted and pulled back into &#8220;regular work&#8221;.</p>

<p>The big difference this time around was that I found a couple of tools that cut <em>way</em> down on the difficulty of getting started, and I&#8217;m super excited to tell you about them.</p>

<h2>Biz Metrics - <a href="https://segment.io/">Segment.io</a></h2>

<p><img src="http://nathaniel.talbott.ws/images/posts/segmentio_homepage.png" alt="segment.io" /></p>

<p>Remember how I mentioned having lots of interesting choices, but being overwhelmed trying to pick? Using <a href="https://segment.io/">Segment</a> goes a long way towards solving that problem. To put it in the terms of my day-to-day world, Segment is basically the &#8220;Spreedly of Business Analytics&#8221; - you hook up one time to Segment&#8217;s API, and then you can turn on dozens of different services in your site with just a quick configuration change in their dashboard.</p>

<p>This had two huge advantages for me: first, it simplified the API that I had to implement against, since by looking at a whole pile of API&#8217;s and building a solid over-arching API, Segment has come up with something incredibly simple and easy to use. They also have a library for just about any language, making the implementation even easier.</p>

<p>The second big advantage with Segment is that it makes it a cinch to trial multiple analytics services simultaneously and see which one(s) are the best fit. Tools like <a href="https://www.kissmetrics.com/">KISSmetrics</a> and <a href="https://mixpanel.com/">Mixpanel</a> aren&#8217;t cheap, and yet they take a fair amount of effort to integrate from scratch. Using Segment in front means I can trial them in parallel without biting off two significant integration efforts.</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/segmentio_dashboard.png" alt="segment.io" /></p>

<p>And speaking of KISSmetrics and Mixpanel: both tools are pretty awesome. <a href="http://jmlite.tumblr.com/">Justin</a> is like a kid in a candy store, taking the raw information and events filtering in and building out all kinds of interesting funnels, counters, and segments. And I can tell he&#8217;s deep in the numbers, since he keeps finding places where I&#8217;m counting things wrong!</p>

<h2>Devops Metrics - <a href="https://metrics.librato.com/">Librato</a></h2>

<p><img src="http://nathaniel.talbott.ws/images/posts/librato_homepage.png" alt="Librato Metrics" /></p>

<p>The biggest stumbling block to me with devops metrics has always been how many moving pieces there are. You have to figure out what to collect, collect it somehow, get it into some kind of data store, then hook up something to consume that data and eventually expose it in some kind of useful format. It&#8217;s all a bit overwhelming when you&#8217;re just getting started, and at the local <a href="http://www.meetup.com/Triangle-DevOps/">Devops Meetup</a> I was explaining some of my frustration to a few sympathetic ears from Github and Heroku, which both have excellent internal devops metrics.</p>

<p>One of them suggested I get started with <a href="https://metrics.librato.com/">Librato</a>, and boy am I glad they did. Leveraging Librato&#8217;s awesome <a href="https://github.com/librato/librato-rails">librato-rails</a> gem, I had some basic metrics showing up in a dashboard within a few hours of getting started. And since Librato is taking care of the infrastructure, I&#8217;m in a great place to add more metrics and incrementally increase our visibility into the health of our infrastructure.</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/librato_dashboard.png" alt="Performance Dashboard" /></p>

<p>We&#8217;ve always had some visibility into our business metrics and our infrastructure, but like so many things when you&#8217;re in startup mode, it was one kludge after another. It&#8217;s so exciting to feel like we&#8217;re on a solid footing now, both in terms of having better metrics today and in being able to iteratively expand what we&#8217;re monitoring going forward.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Relix 2.0.0]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/19/relix-2-0-0/"/>
    <updated>2013-03-19T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/19/relix-2-0-0</id>
    <content type="html"><![CDATA[<p>Relix is a Ruby library that makes it easy to build and use various types of secondary indexes backed by <a href="http://redis.io/">Redis</a>. We use it heavily at <a href="https://spreedly.com">Spreedly</a> to give us fast access to our <a href="http://basho.com/riak/">Riak-backed</a> models (we didn&#8217;t use Riak&#8217;s secondary indexing since it didn&#8217;t exist when we started building Spreedly Core). <a href="https://github.com/ntalbott/relix">Relix&#8217;s README is full of details on it&#8217;s philosophy and usage</a>, and I&#8217;ll be doing a post eventually about why and how we use it at Spreedly.</p>

<p><a href="https://github.com/ntalbott/relix/blob/v2.0.0/HISTORY.md#200">Relix 2.0.0</a> brings a major version bump, due to the fact that it now requires Redis 2.6. This allows us to leverage <a href="http://redis.io/commands/eval">Lua scripting</a>, which is a big win for some use cases, especially since Relix does all it can to pipeline Redis requests.</p>

<p>The new feature driving the usage of Lua scripting is the ability to index and retrieve the list of values being indexed by a <code>multi</code> index:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">User</span>
</span><span class='line'>  <span class="n">relix</span><span class="o">.</span><span class="n">multi</span> <span class="ss">:account_id</span><span class="p">,</span> <span class="n">index_values</span><span class="p">:</span> <span class="kp">true</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># Enables this call</span>
</span><span class='line'><span class="no">User</span><span class="o">.</span><span class="n">lookup_values</span><span class="p">(</span><span class="ss">:account_id</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>So whereas normally you&#8217;d look up all the users with a given <code>account_id</code>, <code>lookup_values</code> allows you to look up all the account id&#8217;s that are indexed. This is super handy for doing aggregate lookups by a multi index:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">User</span><span class="o">.</span><span class="n">lookup_values</span><span class="p">(</span><span class="ss">:account_id</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">account_id</span><span class="o">|</span>
</span><span class='line'>  <span class="n">users_for_account</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">lookup</span><span class="p">{</span><span class="o">|</span><span class="n">q</span><span class="o">|</span> <span class="n">q</span><span class="o">[</span><span class="ss">:account_id</span><span class="o">].</span><span class="n">eq</span><span class="p">(</span><span class="n">account_id</span><span class="p">)}</span>
</span><span class='line'>  <span class="c1"># Aggregate processing for the users in the account</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>2.0.0 also adds a deprecation mechanism and uses it to deprecate direct access to <code>IndexSet#indexes</code> in favor of <code>IndexSet#[]</code>.</p>

<p>You can grab 2.0.0 hot off of <a href="https://rubygems.org/gems/relix">Rubygems</a>, <a href="https://github.com/ntalbott/relix/issues">report any issues you encounter on Github</a>, and <a href="https://github.com/ntalbott">contact me via the details on my Github profile</a> if there&#8217;s anything I can help with.</p>

<p>And let me know if you&#8217;re using Relix - I&#8217;d love to hear about anything and everything it&#8217;s being used for!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Do Things, Tell People]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/18/do-things-tell-people/"/>
    <updated>2013-03-18T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/18/do-things-tell-people</id>
    <content type="html"><![CDATA[<p>I&#8217;m not sure where I first heard this little ditty, but I guarantee it&#8217;s <a href="https://twitter.com/tobi">tobi&#8217;s</a> fault. They have this saying right at the entrance to the <a href="http://shopify.com/">Shopify</a> offices, and while I haven&#8217;t made the pilgrimage to Ottawa yet, <a href="https://twitter.com/tobi/status/207457289286844416/photo/1">I have seen pictures</a>.</p>

<p>For me, the &#8220;do things&#8221; part is easy. Well, easy is grossly oversimplifying my relationship with creating, but suffice it to say that if I&#8217;m not regularly making something I start getting depressed. I am wired to derive satisfaction from the act of creation, and so I have inbuilt feedback loops that ensure I return to &#8220;doing things&#8221; with regularity. I still struggle to make sure the things I&#8217;m doing are on the whole worthwhile - the occasional diversion into writing a <a href="http://www.lua.org/">Lua</a> script to run a <a href="http://computercraft.info/wiki/Turtle">Minecraft bot</a> are fun but can easily be overdone - but accumulating a list of things I&#8217;ve done isn&#8217;t hard.</p>

<p>It&#8217;s the &#8220;tell people&#8221; that I so easily neglect. As I&#8217;ve worked on <a href="https://spreedly.com/">Spreedly</a> over the years, not talking enough about what we&#8217;re up to is far and away my greatest failing. Thankfully <a href="http://jmlite.tumblr.com/">Justin</a> now does an awesome job of <a href="http://blog.spreedly.com/">getting the word out</a>, but that doesn&#8217;t mean I can slack off, just that I can focus in on talking about the technical side of what I (and Spreedly) are up to, which is the part I&#8217;m best equipped to talk about anyhow.</p>

<p>And so after we got <a href="http://blog.spreedly.com/2013/03/04/spreedly-funding-expanding-our-horizons-pivoting/">the new spreedly.com</a> out the door and I needed some time to decompress, I decided to spend the next week taking all the cool things I and the team had done over the preceding weeks and start writing about them. It actually beats taking time off in a lot of ways since it actively calms the brain down by taking all the stuff it&#8217;s full of and putting it down in words.</p>

<p>And with a week of posts under my belt, and dozens of topics queued up (it&#8217;s been too long!), I&#8217;m getting the &#8220;tell people&#8221; ball rolling again. I hope if you&#8217;re reading along you&#8217;re enjoying the posts, and I&#8217;d love your feedback on <a href="http://alpha.app.net/ntalbott">app.net</a>, via <a href="mailto:nathaniel@talbott.ws">email</a>, or any other way you can get to me (there are quite a few). And <a href="http://news.ycombinator.com/submit">a submission or upvote on Hacker News</a> is always welcome; much as it can be a distraction, I still love participating in the HN community.</p>

<p>For now my plan is to keep the weekdays pretty technical, and publish less technical posts (such as this one) on Saturdays. Of course, my goal is that it doesn&#8217;t stop with the posts I already have written and waiting to publish; while I don&#8217;t plan to keep up daily posts, I&#8217;m doing my best to build a habit such that &#8220;tell people&#8221; is one of the &#8220;things I do&#8221;. Writing is an act of creation I enjoy, and the more consistently I do it the more I enjoy it and the better I am at it. So expect to hear a lot more from me in the coming days!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Refactoring to Services: Payoff]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/15/refactoring-to-services-payoff/"/>
    <updated>2013-03-15T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/15/refactoring-to-services-payoff</id>
    <content type="html"><![CDATA[<p>One of the most exciting things I&#8217;ve done in my professional life to date is recently deploying the first big piece of the ongoing process to break <a href="https://spreedly.com">Spreedly</a> up into a series of services. We took user account management and billing and split them out into their own service, and we did it gently, with no &#8220;big rewrite&#8221; or &#8220;stop the world switchover&#8221; putting the business into jeopardy.</p>

<p>Why add the overhead of extra services? And yes, they do have overhead - adding more moving parts always adds complexity. I want to talk a lot more in the coming days about what we did, how we did it, and what compelled us to go down this path, but today I&#8217;m just going to tease with the bottom line payoff of getting this first piece deployed:</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/strip_out_dead_code.jpg" alt="4,328 Deletions" /></p>

<p>I just stripped over 4,000 lines of code from this app. That code doesn&#8217;t have to be loaded, supported, or secured any longer in this context. That&#8217;s what I call a win!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Post-Deploy Smoke Tests]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/14/post-deploy-smoke-tests/"/>
    <updated>2013-03-14T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/14/post-deploy-smoke-tests</id>
    <content type="html"><![CDATA[<p>Ever find yourself loading your application in a browser after a deploy just to make sure you didn&#8217;t break it? Ever forget to do that and have a panicked coworker call you a few minutes later wondering if you know you took the whole site down?</p>

<p>Thing is, you can have the best automated test suite ever, and you can have a great set of passive monitoring tools, but nothing beats an active check of the application after a deploy. After yet another time of making an insignificant tweak that turned out to work just ever so slightly differently in production in such a way as to take one of our apps down post-deploy, I finally said, &#8220;Enough!&#8221; and made Duff code us up a solution.</p>

<p>That&#8217;s right folks, this one isn&#8217;t about tooting my own horn, but rather about tooting the horn of fellow Spreedly developer <a href="http://duffomelia.com/">Duff&#8217;s</a> since he doesn&#8217;t do it nearly enough. After we fixed my latest gaffe (which thankfully &#8220;only&#8221; affected the UI), Duff tackled the problem of adding an active sanity check to our deploy processes that would just do a basic check (or checks) and tell us as part of the deployment itself if the check failed.</p>

<p>I love the term smoke test for this check; originally used in plumbing, the smoke test was when they&#8217;d force smoke through newly installed pipes to see if any smoke seeped out. It was later adopted by the electronics industry as well: &#8220;You plug in a new board and turn on the power. If you see smoke coming from the board, turn off the power. You don&#8217;t have to do any more testing.&#8221; <a id="smoke-test-on-wikipedia-origin"> </a><sup><a href="#smoke-test-on-wikipedia">1</a></sup> The smoke test is that first test you run on a newly assembled system just to make sure it&#8217;s not immediately and obviously broken.</p>

<p>So Duff dug in and added a new recipe to our internal deployment gem:</p>

<figure class='code'><figcaption><span>smoke.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Capistrano</span><span class="o">::</span><span class="no">Configuration</span><span class="o">.</span><span class="n">instance</span><span class="p">(</span><span class="ss">:must_exist</span><span class="p">)</span><span class="o">.</span><span class="n">load</span> <span class="k">do</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">all_smoke_tests_passed</span>
</span><span class='line'>    <span class="n">send_to_hipchat</span><span class="p">(</span><span class="s2">&quot;All smoke tests were successful.&quot;</span><span class="p">,</span> <span class="n">color</span><span class="p">:</span> <span class="s1">&#39;green&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">smoke_tests_failed</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">puts</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">******************</span><span class="se">\n\n</span><span class="s2">SMOKE TEST FAILURE!!!</span><span class="se">\n</span><span class="si">#{</span><span class="n">messages</span><span class="si">}</span><span class="se">\n\n</span><span class="s2">******************</span><span class="se">\n\n</span><span class="s2">&quot;</span>
</span><span class='line'>    <span class="n">send_to_hipchat</span><span class="p">(</span><span class="s2">&quot;http://f.cl.ly/items/2T3c2B2m3H2l3R2Y3o2z/Image%202013.02.15%201:50:04%20PM.jpeg&quot;</span><span class="p">,</span> <span class="n">message_format</span><span class="p">:</span> <span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="n">color</span><span class="p">:</span> <span class="s1">&#39;red&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="n">messages</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">message</span><span class="o">|</span>
</span><span class='line'>      <span class="n">send_to_hipchat</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">color</span><span class="p">:</span> <span class="s1">&#39;red&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">task</span> <span class="ss">:smoke_test</span> <span class="k">do</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">after</span> <span class="s2">&quot;deploy&quot;</span><span class="p">,</span> <span class="s2">&quot;smoke_test&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>It&#8217;s pretty simple, it just hooks in after deploy and runs a (by default empty) task. It also provides convenience methods for taking action upon success or failure. Usage is simple:</p>

<figure class='code'><figcaption><span>deploy.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;potluck/recipes/smoke&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">task</span> <span class="ss">:smoke_test</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">failed_tests</span> <span class="o">=</span> <span class="o">[]</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">curl_result</span> <span class="o">=</span> <span class="sb">`curl -s -w &quot;%{http_code}&quot; https://id.spreedly.com/signin -o /dev/null`</span>
</span><span class='line'>  <span class="n">failed_tests</span> <span class="o">&lt;&lt;</span> <span class="s2">&quot;Id smoke test FAILURE.&quot;</span> <span class="k">unless</span> <span class="p">(</span><span class="n">curl_result</span> <span class="o">==</span> <span class="s2">&quot;200&quot;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">curl_result</span> <span class="o">=</span> <span class="sb">`curl -s -w &quot;%{http_code}&quot; https://spreedly.com/ -o /dev/null`</span>
</span><span class='line'>  <span class="n">failed_tests</span> <span class="o">&lt;&lt;</span> <span class="s2">&quot;Public smoke test FAILURE.&quot;</span> <span class="k">unless</span> <span class="p">(</span><span class="n">curl_result</span> <span class="o">==</span> <span class="s2">&quot;200&quot;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">if</span> <span class="n">failed_tests</span><span class="o">.</span><span class="n">empty?</span>
</span><span class='line'>    <span class="n">all_smoke_tests_passed</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="n">smoke_tests_failed</span><span class="p">(</span><span class="n">failed_tests</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>All we have to do for a project is override the <code>:smoke_test</code> task, do whatever makes sense for that particular app, and use the convenience methods to report the result. Now if a smoke test fails, the whole team knows right away as it gets blasted into our Hipchat room:</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/smoke_test_failure.png" alt="Smoke Test Failure in Hipchat" /></p>

<p>We of course also see if the smoke test passed (though it&#8217;s much less &#8220;in your face&#8221;):</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/smoke_test_success.png" alt="Smoke Test Success in Hipchat" /></p>

<p>It&#8217;s amazing how comforting it is to see that line show up after a deploy.</p>

<p>Of course, there are plenty of other ways we test our apps, both pre- and post-deploy, but the smoke test is a great addition to the overall lineup and I&#8217;m grateful to Duff for getting them going for Spreedly. And I&#8217;d encourage other developers to consider adding an active check to the deploy process to see if anything starts smoking once everything&#8217;s live.</p>

<p><sup>1</sup> <em><a id="smoke-test-on-wikipedia"><a href="http://en.wikipedia.org/wiki/Smoke_testing#History_of_the_term">Smoke Testing on Wikipedia</a></a> <small><a href="#smoke-test-on-wikipedia-origin">back</a></small></em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Stitching Proxy]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/13/stitching-proxy/"/>
    <updated>2013-03-13T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/13/stitching-proxy</id>
    <content type="html"><![CDATA[<p>As part of redesigning <a href="https://spreedly.com">spreedly.com</a> to highlight our focus on our gateway API product (usually known affectionately as &#8220;Core&#8221;), we wanted to move the actual serving of the marketing parts of the site to a more appropriate app - initially our account management service, and eventually a single responsibility content-centric service.</p>

<p>Only one problem: spreedly.com was currently handled by our Subscriptions application, and we didn&#8217;t want to change either the API urls or the hosted payment page urls for that service. And it&#8217;s not just a temporary problem, either: we&#8217;re not discontinuing the Subscriptions product, and while we may eventually move it to its own subdomain, that will be a slow and careful transition that could easily last over a year.</p>

<p>So we were clearly going to have to serve up two different applications off of the same domain. The plan was to continue defaulting urls to the Subscriptions app, but to hijack a specific set of pages and paths and point them at the new app. I worked up a list of paths that should point at the new path, and our handsome and talented devop <a href="https://github.com/thejohnny">John</a> worked out how to do the mapping in our frontend load balancer. The production setup actually ended up being super simple since we already use <a href="http://nginx.org/">nginx</a> proxying to <a href="http://unicorn.bogomips.org/">unicorn</a>, and it was simply a matter of having a particular set of paths proxy to a different backend. And because there&#8217;s no special infractructure to support it there&#8217;s also no performance overhead to sharing the domain.</p>

<p>But&#8230; what about when we&#8217;re developing locally? While I&#8217;d eventually like to see us using <a href="https://github.com/boxen">Boxen</a> or something like it to closely mirror the production setup in our local development environments, we&#8217;re a ways off from that yet. Today we use the awesome <a href="http://pow.cx/">pow</a> to handle our local development serving, and while it does all kinds of cool things, it won&#8217;t serve multiple apps on the same domain.</p>

<p>I wanted to get something going quickly, which meant I needed a simple solution that integrated with our existing setup with a minimum of fuss. Enter <a href="https://github.com/ncr/rack-proxy">rack-proxy</a>. This handy tool lets you create a piece of <a href="http://rack.github.com/">Rack</a> middleware that will proxy the whole request over to another app of your choosing. Using the excellent <a href="http://guides.rubyonrails.org/rails_on_rack.html">Rails guide about Rack</a> and a nice template in <a href="http://stackoverflow.com/a/13538911/6284">a Stack Overflow answer</a>, I quickly had something up and running:</p>

<figure class='code'><figcaption><span>config/initializers/stitcher.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">if</span> <span class="no">ENV</span><span class="o">[</span><span class="s2">&quot;STITCH&quot;</span><span class="o">]</span> <span class="o">==</span> <span class="s2">&quot;1&quot;</span>
</span><span class='line'>  <span class="nb">require</span> <span class="s2">&quot;rack-proxy&quot;</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Stitcher</span> <span class="o">&lt;</span> <span class="no">Rack</span><span class="o">::</span><span class="no">Proxy</span>
</span><span class='line'>    <span class="no">EXACT</span> <span class="o">=</span> <span class="sx">%w(/ /terms /privacy)</span>
</span><span class='line'>    <span class="no">PREFIX</span> <span class="o">=</span> <span class="sx">%w(/pricing /about /support /gateways /assets)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</span><span class='line'>      <span class="vi">@app</span> <span class="o">=</span> <span class="n">app</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>      <span class="n">original_host</span> <span class="o">=</span> <span class="n">env</span><span class="o">[</span><span class="s2">&quot;HTTP_HOST&quot;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">rewrite_env</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>      <span class="k">if</span> <span class="n">env</span><span class="o">[</span><span class="s2">&quot;HTTP_HOST&quot;</span><span class="o">]</span> <span class="o">!=</span> <span class="n">original_host</span>
</span><span class='line'>        <span class="n">rewrite_response</span><span class="p">(</span><span class="n">perform_request</span><span class="p">(</span><span class="n">env</span><span class="p">))</span>
</span><span class='line'>      <span class="k">else</span>
</span><span class='line'>        <span class="vi">@app</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">rewrite_env</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>      <span class="n">request</span> <span class="o">=</span> <span class="no">Rack</span><span class="o">::</span><span class="no">Request</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">return</span> <span class="n">env</span> <span class="k">unless</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">host</span> <span class="o">==</span> <span class="no">ENV</span><span class="o">[</span><span class="s2">&quot;PUBLIC_FULL_DOMAIN&quot;</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">unless</span><span class="p">(</span>
</span><span class='line'>          <span class="no">EXACT</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'>          <span class="no">EXACT</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span> <span class="o">+</span> <span class="s2">&quot;/&quot;</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'>          <span class="no">PREFIX</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="o">||</span>
</span><span class='line'>          <span class="no">PREFIX</span><span class="o">.</span><span class="n">any?</span><span class="p">{</span><span class="o">|</span><span class="n">prefix</span><span class="o">|</span> <span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">starts_with?</span><span class="p">(</span><span class="n">prefix</span> <span class="o">+</span> <span class="s2">&quot;/&quot;</span><span class="p">)})</span>
</span><span class='line'>        <span class="n">env</span><span class="o">[</span><span class="s2">&quot;HTTP_HOST&quot;</span><span class="o">]</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s2">&quot;SUBSCRIPTIONS_INTERNAL_DOMAIN&quot;</span><span class="o">]</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">env</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">extract_http_request_headers</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
</span><span class='line'>      <span class="n">headers</span> <span class="o">=</span> <span class="k">super</span>
</span><span class='line'>      <span class="n">headers</span><span class="o">[</span><span class="s2">&quot;Host&quot;</span><span class="o">]</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s2">&quot;PUBLIC_FULL_DOMAIN&quot;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">headers</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">middleware</span><span class="o">.</span><span class="n">insert_before</span> <span class="no">ActionDispatch</span><span class="o">::</span><span class="no">Static</span><span class="p">,</span> <span class="no">Stitcher</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Lets walk through this real quick; it&#8217;s pretty straightforward, but there are a few nuances I want to highlight. First of all, you&#8217;ll notice this only runs if a particular ENV key is set. Doing so leverages our extensive use of environment variables for app configuration, and ensures that this will only run in development and never in production. Eventually I&#8217;d like to write more about the benefits we&#8217;ve seen from switching almost exclusively to configuration via environment variables, but for now you can just note that they&#8217;re used in multiple places in this little proxy to pull the right value.</p>

<p>Next, note that I had to overwrite <code>#call</code> - this is necessary to allow passing through unproxied requests to the &#8220;hosting&#8221; application. It&#8217;d be nice if rack-proxy provided a way to do this out of the box, but it&#8217;s simple enough to implement regardless. The decision of whether or not to proxy the request is made by looking at whether the <code>HTTP_HOST</code> for the request has changed; if it has, then we want this request to go to the proxied app. Also note the call to <code>#rewrite_response</code> - this is a method provided by rack-proxy to allow adjusting the response before it is passed back to the browser. It&#8217;s not strictly necessary for me to call it here since its default behavior is to do nothing, but I used it multiple times during debugging to get a peek at what the proxy was doing, so it&#8217;s handy to keep it in the chain.</p>

<p>The magic happens in <code>#rewrite_env</code>, where I check against the set of exact and prefix paths I want rewritten and determine whether the request matches them. If it does, the <code>HTTP_HOST</code> is set to the proxied app&#8217;s host, and we&#8217;re good to go. The one other check I am doing here is that I&#8217;m only ever proxying when on the public/marketing domain, since this app actually serves a couple of subdomains and I only want to rewrite on one of them.</p>

<p>Finally, there&#8217;s a bit of trickery going on in <code>#extract_http_request_headers</code> to make everything work smoothly. Even though I&#8217;m rewriting the host that the request should go to, I don&#8217;t want the <code>Host</code> header that&#8217;s passed to the proxied app to be affected, since it should be as clueless about the fact that it&#8217;s being proxied as possible. rack-proxy uses this method to prep the headers for submission upstream, and so I just hook it and make my own last minute adjustment.</p>

<p>And then the middleware is inserted at the very beginning of the middleware stack, and BOOM! it all just works. Well, not quite: <a href="http://nathaniel.talbott.ws/blog/2013/03/12/never-debug-http-in-the-browser/">I spent hours debugging an issue with the headers</a>, but other than that I really did have a solution working in a couple hours. And best of all, we now have a way in our local development environment to simulate the exact domain structure in production.</p>

<p>If you need to stitch another app into a Rack stack, I&#8217;d definitely recommend checking out <a href="https://github.com/ncr/rack-proxy">rack-proxy</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Never debug HTTP in the browser]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/12/never-debug-http-in-the-browser/"/>
    <updated>2013-03-12T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/12/never-debug-http-in-the-browser</id>
    <content type="html"><![CDATA[<p>It was coming down to the wire: the new <a href="https://spreedly.com">Spreedly</a> site was launching in less than 48 hours, and I really wanted to be able to try out the way we were going to be stitching two different applications together on one domain. It was the one piece of the puzzle that we couldn&#8217;t &#8220;pre-deploy&#8221; to production, since turning it on by definition would launch the site publicly everyone. So I started hacking together a Rack-based proxy (more about that in the future) to simulate the production setup, and within an hour or so I had something that was mostly working.</p>

<p>The problem was the &#8220;mostly&#8221; part. The proxy was working, the right things were loading on the right paths, but I couldn&#8217;t log into the proxied application. Logging in was actually working and redirecting me into the app, but then I was immediately being redirected back to the login page. It was like I couldn&#8217;t write to the session. Maybe a cookie problem?</p>

<p>I do most of my browsing with Chrome, and am generally a fan of the developer tools it ships with. So I started poking, going back and forth between the server logs and the browser&#8217;s request log, trying to figure out what was going on. It didn&#8217;t take long to confirm that the server was definitely writing out to the session correctly, but that for some reason the browser wasn&#8217;t returning the right session information back to the browser. I also confirmed that the site worked fine when not proxied, and it was something proxy related that was breaking things.</p>

<p>And then I spent multiple hours spinning my wheels, trying to figure out what was different between the working direct requests and the broken proxied requests. I tried looking at requests in Chrome for a while, and then I switched to Firefox and tried a few different tools there as well. It was getting late, and I was burning out, and I was making no progress, and I should just quit&#8230;</p>

<p>But my conundrum was that while I was pretty sure this was a problem that was specific to my hacked up proxy, I wasn&#8217;t 100% sure, and I didn&#8217;t want to flip the switch on Monday in production only to find out that nobody could log in. But finally, with no real progress to show for a few hours of debugging, I gave in and gave it a rest.</p>

<p>And sure enough, while I didn&#8217;t figure the answer out after quitting, I did realize I&#8217;d been approaching my debugging the wrong way. Debugging is an art, and I&#8217;d been doing the equivalent of trying to play a violin with a hack saw. What I needed was a tool that would let me textually compare the headers of the working and broken requests.</p>

<p>Enter <code>curl</code>, which I should&#8217;ve pulled out right away. I knew at this point that something was up with the cookies, but I had no earthly idea what. So I dug into the curl man page and started reading through the options (there are a <em>lot</em> of them) looking for how I could see what was happening with the cookies. OK, actually I just ran <code>man curl | grep -A10 cookie</code> since I didn&#8217;t have time to read the whole tome.</p>

<p>Working with what I learned from the man page, I first got myself set up so I could easily run the same request against the (working) unproxied app and the (broken) proxied app. Then I used curl&#8217;s handy <code>-c</code> option to have it write out a cookiefile when I made a request:</p>

<pre><code>$ curl \
  -i \
  -c cookies.working \
  -d "login=bob" -d "password=test" \
  http://workingapp/login
</code></pre>

<p>Nothing magic here; <code>-i</code> tells curl to print out the headers along with the response, <code>-c</code> stores the cookies in a curl-formatted file, and the <code>-d</code> switches pass in the login information (and make <code>curl</code> do a POST). I then repeated this against the broken version of the app, storing the cookies in a different file. By looking at the headers and responses from the two requests, I could see that both redirected me into the app, indicating that as far as the server was concerned, I had auth&#8217;d successfully.</p>

<p>Next step was to verify that curl would re-present the cookies correctly, and that it could reproduce the login issue. To do that I simply passed the written out cookie file to the app and noted whether I got redirected (indicating a missing session) or a 200 OK:</p>

<pre><code>$ curl \
  -i \
  -b cookies.working \
  http://workingapp/innerpage
</code></pre>

<p>The <code>-b</code> switch does the magic here, reading the cookie file written out by the previous command and passing the cookies to the app just like a browser would. And sure enough, the working version gave me back a 200 and the broken version redirected me back to the login page.</p>

<p>Now to dig into the cookie files themselves and see what was different about them! It took a few minutes of staring and poking, but very quickly I noticed that the broken version only had one cookie in its file, while the working version had written 4+ cookies. How was that happening?</p>

<p>Long story short, <a href="https://github.com/ncr/rack-proxy">rack-proxy</a> uses Ruby&#8217;s Net::HTTP heavily, and Net::HTTP tries to treat headers like a hash. But headers aren&#8217;t a hash; you can pass multiple headers of the same type, and that&#8217;s exactly how Set-Cookie works. Net::HTTP papers over this by joining with a comma the values of header keys there&#8217;s more than one. And thus I was ending up with one big invalid cookie rather than the four cookies I should&#8217;ve had.</p>

<p>Now it was as simple as figuring out how to get Net::HTTP to give me the header values individually and <a href="https://github.com/ncr/rack-proxy/pull/11">submitting a pull request</a> with a fix. I locked rack-proxy to the fixed revision in our Gemfile, and everything just worked. And while this problem wouldn&#8217;t have affected us in production (since nginx is doing all the proxying for us), I went into the launch on Monday morning much more confident since I knew this wouldn&#8217;t bite us when we flipped the switch.</p>

<p>Moral of the story? Browsers are the wrong tool for debugging HTTP. You need to be able to see and textually compare what&#8217;s traversing the wire, and even though the developer tools provided by modern browsers can give you a peek, they often obfuscate issues rather than making them obvious. curl and other text-based tools like it are the best way to see what&#8217;s really happening and quickly track down the problems that arise with HTTP.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Kernel#backtrace]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/11/backtrace/"/>
    <updated>2013-03-11T08:00:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/11/backtrace</id>
    <content type="html"><![CDATA[<p>The other day I was cranking along on part of our <a href="https://spreedly.com">Spreedly</a> codebase, furiously working to get it ready for <a href="http://blog.spreedly.com/2013/03/04/spreedly-funding-expanding-our-horizons-pivoting/">the launch of our new marketing site</a> and the publicity that (we hoped) was due to come with it. Now, it may not be obvious from the outside, but we re-did a lot more than just the look and feel of Spreedly, and as part of that I was working on getting billing working smoothly throughout the system.</p>

<p>One of the key things about how we bill is that a lot of it&#8217;s made up of very small metered charges. Because they&#8217;re so small, it&#8217;s not a huge deal if a metered fee here or there falls on the floor, and so as long as we never <em>over</em> charge a customer we&#8217;re more concerned with fixing issues that come up than we are with capturing every last penny. Thus there are various places in the chain of &#8220;add a fee&#8221; where things could go wrong that we just let them fail and notify ourselves rather than writing fancy recovery code.</p>

<p>But of course, this only works if you notify yourself in such a way that you can fix the problem, and that means a stack trace should show up in the notification. As I coded along I found myself in a situation where something could go wrong and yet it wasn&#8217;t due to an exception but rather just due to an &#8220;unexpected input&#8221; situation. That meant I had no exception to grab the stack trace off of, and for a few minutes I was stumped.</p>

<p>Now, I knew about <code>Kernel#caller</code>, but the problem with it is that it starts with (as indicated by the name) your caller&#8217;s stack, and in this case I wanted the stack to start right where I was creating the notification. Turns out there&#8217;s a simple solution:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Kernel</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">backtrace</span>
</span><span class='line'>    <span class="nb">caller</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>I dropped that code in a Rails initializer and then just called <code>backtrace</code> when building my notification, and it works beautifully.</p>

<p>Now, I&#8217;m pretty cautious about going in and adding methods to <code>Kernel</code>, but I think this is a good example of why it&#8217;s nice that Ruby lets us do so when we want to. If you find yourself needing a backtrace without raising an exception, I hope this helps you out!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Do It Again]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2013/03/09/rituals/"/>
    <updated>2013-03-09T08:00:00-05:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2013/03/09/rituals</id>
    <content type="html"><![CDATA[<p>When you&#8217;re raising six children, you repeat yourself. A lot. Sometimes it&#8217;s words: &#8220;No singing at the table, please.&#8221; Sometimes it&#8217;s actions: by the time number six came around, I&#8217;d done the &#8220;put the kids to bed&#8221; thing <em>thousands</em> of times. And often it&#8217;s pure joy: I&#8217;ll never tire of giving out hugs and kisses, and I&#8217;ll never tire of receiving them either.</p>

<p>Fact is, kids thrive on repetition. Knowing what comes next lets them anchor their constantly changing minds and bodies in something steady and unsurprising. If you give them a drink every night before they get in bed and then forget one night, they&#8217;ll be up five minutes later reminding you that you missed your cue. If they take a nap every day in the afternoon and for some reason it&#8217;s missed, the whining will commence and you&#8217;ll know exactly from whence it springs.</p>

<p>The dawning realization I&#8217;ve had over the past few months is that it&#8217;s not just children that are well served by thoughtful repetition. Turns out I&#8217;m a lot happier and healthier when my life has a cadence as well. By dint of living in a house full of little ones I&#8217;ve found myself slotted into a whole bunch of different repeating cycles whether I like it or not, and I&#8217;m finding that I do like it, and even thrive on it.</p>

<p>Of course as adults we&#8217;re used to having a degree of ritual in our life. We typically have some sort of weekday routine - get up, get pretty, get fed, get to work, get working, get home, get relaxed, get to bed - and the weekends are another cycle that repeats every week without fail. But often these are seen as indicative of drudgery, and something we should always be looking for an escape from. &#8220;Leave the work-a-day routine behind!&#8221; they say, and we nod our heads in agreement as we begrudge each time the wheel goes around and we find ourselves still on it.</p>

<p>But what if the problem isn&#8217;t the repitition, but rather our attitudes about it? What if what&#8217;s really needed is a more child-like mind, resting in the stability that a routine provides, and delighting in the things that can be learned and experienced within it? Going back to fundamentals, who gets tired of breathing a few times a minute, or eating a few times a day, and wishes they could escape from the terrible sameness of repeating those activities again and again?</p>

<p>I&#8217;m finding that my mistake as I left the routines of my parents&#8217; household was that I let routines happen to me, instead of purposefully building routines that I could embrace and enjoy. I know I&#8217;ve certainly gone months feeling dislocated each time a particular cycle repeated itself, largely because I&#8217;d allowed it to be imposed upon me without ever thinking through whether it was worthwhile or if it could be tweaked to make it more enjoyable. If you&#8217;re going to do something over and over again, it ought to be something you enjoy!</p>

<p>When properly applied, repetitive practices are powerful, and an inescapable part of what it means to be alive. I&#8217;ve decided to reclaim the word &#8220;ritual&#8221; from its spot on the list of &#8220;things you&#8217;d never intentionally add to your life&#8221; and use it to describe these patterns that can be really meaningful and powerful if embraced. And in future posts I want to walk through some of the rituals I and our family as a whole now enjoy, and talk about how we&#8217;ve both accidentally stumbled into them and at other times deliberately instituted them.</p>

<p>And hopefully, with a bit of &#8220;ritual&#8221; applied to my writing, it will become regular enough for those future posts to actually happen!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Putting Facebook on Ice]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2012/09/13/putting-facebook-on-ice/"/>
    <updated>2012-09-13T10:33:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2012/09/13/putting-facebook-on-ice</id>
    <content type="html"><![CDATA[<p>This is the last thing posted to my Facebook profile, probably forever:</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/the_last_facebook_post.png" alt="&quot;Time to ice my Facebook account. Going to cut it to just family, turn off the Twitter bridge, and disable all notifications.&quot;" /></p>

<p>This morning I did exactly that: I hopped on Facebook, removed all my non-family friends, deleted all my &#8220;Likes&#8221;, deleted all the Apps I had given access, left all groups, and went through and (laboriously!) turned off every email notification Facebook has. I now exist on Facebook, but really only as a pointer to where I&#8217;m actually participating online.</p>

<p>So two questions immediately come up: why? And why not go all the way and delete the account altogether?</p>

<p>The why is pretty easy: I&#8217;ve come to despise the social model of Facebook. The simplistic, synchronous &#8220;friend&#8221; model is good at putting content in front of me that I feel compelled to read, but bad at putting content in front of me that actually enriches my relationships. Add to that the giant sucking sound that is Facebook&#8217;s effort to grab as much personal content and then make that content as public as they can get away with, and I end up with a tinge of self-loathing every time I lose a half-hour to reading about the intimate details of the lives of people I don&#8217;t even know any more (if I ever did at all).</p>

<p>Facebook feels (to me) like Pleasure Island in the story of Pinocchio - a fun place designed to draw you in and make an ass of you, so that eventually you&#8217;ll turn a profit for the owners. I don&#8217;t feel that there is much empathy from the organization for their users, rather that the trajectory of the company is to exploit baser human tendencies to &#8220;drive higher engagement&#8221; and make a quick buck. Even the usage of an advertising business model in a social context just feels crass in a way that (for instance) Google ads never have; sort of like that person you found out invited you into their social circle so that they could sell you Amway products.</p>

<p>This is of course just my personal take: I know many folks get a lot of mileage out of Facebook, and feel that it has merit, and I say, &#8220;More power to them!&#8221; Which brings me to the second question, well put by Mr. Bass:</p>

<p><a href="https://twitter.com/pelargir/status/246216640667197440"><img src="http://nathaniel.talbott.ws/images/posts/go_all_the_way_tweet.png" alt="&quot;Go all the way… just deactivate it completely!&quot;" /></a></p>

<p>Why not go all the way and just delete the account? Well, first of all, there is no such thing as &#8220;delete&#8221; on Facebook, at least not as far as I can tell. While going through and cutting my Friend list down, there were two people, including one Matthew Bass, who were still in it even though they had &#8220;deleted&#8221; their account. So it seems kind of like a pointless gesture.</p>

<p>More importantly, my goal here is to stop putting value into Facebook, not to punish myself by disappearing from it completely. People can still find me by my email addresses, see where I&#8217;m actually hanging out via the links in my profile, know that I am related to that other Talbott they know, etc. If anything my super minimal ongoing presence on the site makes more of a statement than deleting the account would, by saying, &#8220;Yes, I know about Facebook, and I actively choose not to participate in it.&#8221;</p>

<p>And, with a still valid Facebook account, I can continue to check out the services that require it, take a peek when Facebook does something new to tick off the internet (I bet your listed email address on the site is @facebook.com, isn&#8217;t it?), and generally not get totally out of touch with non-geek consumers, which is an important set of people to understand. And I get all of these ongoing benefits without much more attachment to the site than I would have had I &#8220;deleted&#8221; my account.</p>

<p>So, going forward, you can find me on <a href="http://alpha.app.net/ntalbott">App.net</a> and <a href="http://twitter.com/ntalbott">Twitter</a>. And contact me via <a href="mailto:nathaniel@talbott.ws">email</a>. And read my latest thoughts here on the blog. And you can probably even send me a message on Facebook&#8230; but if a message gets sent via Facebook and there&#8217;s no email notification, will it ever get read? Probably not.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Enabling Fields With Capybara's rack-test Driver]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2012/09/08/enabling-fields-with-capybaras-rack-test-driver/"/>
    <updated>2012-09-08T19:18:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2012/09/08/enabling-fields-with-capybaras-rack-test-driver</id>
    <content type="html"><![CDATA[<p>I was writing a Cucumber test for <a href="https://spreedly.com">Spreedly</a> today, and
was getting frustrated when the fields I was filling in were silently being
ignored. It turns out that when using the rack-test driver with
<a href="https://github.com/jnicklas/capybara">Capybara</a>, it (rightly so) will not
submit any form fields marked as disabled. This is great and all, but since
these form fields are normally enabled via Javascript as the form is interacted
with, I was stumped. How to get them to be passed without monkeying around with
a driver that does full Javascript?</p>

<p>Turns out it is possible, but you have to dig pretty deeply into Capybara&#8217;s guts
to make it work. If you&#8217;re using Cucumber, just drop this into your support
directory:</p>

<script src="https://gist.github.com/3680893.js?file=capybara_helpers.rb"></script>


<p>Then use it by calling it within a step definition with whatever fields you want
enabled.</p>

<p>It should also adapt easily to non-Cucumber environments; just make it
accessible and call it alongside the code that attempts to set the fields.</p>

<p>Hopefully this saves someone else some time; I&#8217;ll never get that half-hour back
myself!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Great Blog Reorg]]></title>
    <link href="http://nathaniel.talbott.ws/blog/2012/09/07/the-great-blog-reorg/"/>
    <updated>2012-09-07T08:35:00-04:00</updated>
    <id>http://nathaniel.talbott.ws/blog/2012/09/07/the-great-blog-reorg</id>
    <content type="html"><![CDATA[<p>I&#8217;ve found my desire to write goes through phases; for awhile I&#8217;ll feel like I have nothing to say, and barely even scratch out the occasional tweet. But then I&#8217;ll go through a time when I have a bunch of ideas bubbling up that I want to explore in prose, and while &#8220;micro-blogging&#8221; (whether it be <a href="http://alpha.app.net/ntalbott">app.net</a> or <a href="http://twitter.com/ntalbott">Twitter</a>) is fun, it just doesn&#8217;t suffice.</p>

<p>The problem is, if I don&#8217;t like the place that I have to blog, I&#8217;ll tend not to write anything, which means I miss out on the thinking process involved with composing longer writing. It&#8217;s been a couple of years now since I&#8217;ve been happy with my blogging setup, and just recently I&#8217;ve been getting the writing itch <strong>really</strong> bad and its finally culminated in me getting my blogging house in order.</p>

<p>The whole thing is complicated enough that I actually sat down and mapped it out. I had two key goals: first, I wanted to separate out a family blog (birth announcements, Christmas letters, funny kid quotes) from my personal geeky musings. And I wanted to put both of those blogs onto platforms that made sense for them, rather than forcing Katie (and eventually the kids) to use the same tools as myself.</p>

<p>I also had a key requirement: do not break the internets. In other words, preserve permalinks, comments, etc. I&#8217;m not willing to abandon old content just because I&#8217;m moving to a new platform, and as they say, &#8220;We have the technology.&#8221; So a migration plan was key.</p>

<p>Here&#8217;s my final map:</p>

<ul>
<li>blog.talbott.ws -> Page sending folks to either family.talbott.ws or nathaniel.talbott.ws

<ul>
<li>blog.talbott.ws/[permalink] -> Octopress serving archived postings</li>
<li>blog.talbott.ws/archives -> Octopress archive page</li>
</ul>
</li>
<li>family.talbott.ws -> Tumblr

<ul>
<li>Link to blog.talbott.ws archive page</li>
<li>Link to talbottkids.tumblr.com archives</li>
<li>Link to nathaniel.talbott.ws</li>
</ul>
</li>
<li>nathaniel.talbott.ws -> Octopress</li>
</ul>


<p>I used the Jekyll migrator to export the old Mephisto content into an Octopress repo, then deployed it to Heroku. Thankfully Mephisto used a sane url structure, so it was easy enough to preserve the article links. I tweaked the default theme a bit so that it looked similar to the old one, and also put in some handling for legacy (pre-Disqus) comments imported from Mephisto.</p>

<p>Next I set up a Tumblr blog for the family; Tumblr has a nice iPhone app, looks good with short snippets of content, and is just generally maintenance free. Still on the list is figuring out a solid way to back up the content there, though I think that&#8217;s doable via their API.</p>

<p>Finally, I&#8217;m getting my personal blog rolling. It&#8217;s also Octopress, and I&#8217;m deploying it to Github. The plan is to shortly replace the default Octopress theme, though that&#8217;s not my main priority at the moment.</p>

<p>And now I have a solid place to write - w00t! As they say on the internets:</p>

<p><img src="http://nathaniel.talbott.ws/images/posts/feels_good_man.jpeg" alt="FEELS GOOD MAN" /></p>
]]></content>
  </entry>
  
</feed>
