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

 <title>Gowalla Engineering</title>
 <link href="http://engineering.gowalla.com/atom.xml" rel="self"/>
 <link href="http://engineering.gowalla.com"/>
 <updated>2013-03-12T14:03:19-07:00</updated>
 <id>http://engineering.gowalla.com</id>
 <author>
   <name>Gowalla Engineering</name>
   <email></email>
 </author>

 
 <entry>
   <title>Scaling at Gowalla: Databases & NoSQL</title>
   <link href="http://engineering.gowalla.com/2011/11/17/scaling-and-gowalla/"/>
   <updated>2011-11-17T00:00:00-08:00</updated>
   <id>http://engineering.gowalla.com/2011/11/17/scaling-and-gowalla</id>
   <content type="html">&lt;p&gt;This is an introduction to relational and non-relational databases as they relate to scalability of web apps. The recording is for a guest Lecture I gave at the University of Texas School of Information. &lt;/p&gt;

&lt;p&gt;In this talk I address the storage technologies and tools &lt;a href=&quot;http://gowalla.com&quot;&gt;Gowalla&lt;/a&gt; uses including &lt;a href=&quot;http://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt;, &lt;a href=&quot;http://memcached.org/&quot;&gt;Memcached&lt;/a&gt;, &lt;a href=&quot;http://redis.io/&quot;&gt;Redis&lt;/a&gt; and &lt;a href=&quot;http://cassandra.apache.org/&quot;&gt;Cassandra&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Video&lt;/h2&gt;

&lt;iframe width=&quot;575&quot; height=&quot;323&quot; src=&quot;http://www.youtube.com/embed/oL-A4JYwgH4?rel=0&amp;amp;hd=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;h2&gt;Slides&lt;/h2&gt;

&lt;script src=&quot;http://speakerdeck.com/embed/4ebc5157b721e200540005f2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Open Source Libraries&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Gowalla open-sourced a few NoSQL libraries that you can use in your own apps. Check out &lt;a href=&quot;http://github.com/gowalla/likeable&quot;&gt;Likeable&lt;/a&gt; &amp;amp;  &lt;a href=&quot;http://github.com/gowalla/chronologic&quot;&gt;Chronologic&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Scraping Wikipedia</title>
   <link href="http://engineering.gowalla.com/2011/11/16/scraping-wikipedia/"/>
   <updated>2011-11-16T00:00:00-08:00</updated>
   <id>http://engineering.gowalla.com/2011/11/16/scraping-wikipedia</id>
   <content type="html">&lt;p&gt;Here at Gowalla we use &lt;a href=&quot;http://campfirenow.com/&quot;&gt;Campfire&lt;/a&gt; extensively for
internal communication. We’ve always had some sort of chat robot hanging out
in our rooms with us, providing simple abilities, but recently GitHub released
&lt;a href=&quot;http://hubot.github.com/&quot;&gt;Hubot&lt;/a&gt; and we moved our bot functionality over to
&lt;a href=&quot;https://github.com/github/hubot-scripts&quot;&gt;Hubot scripts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Can We Query Wikipedia?&lt;/h2&gt;

&lt;p&gt;Just the other day, our own &lt;a href=&quot;http://www.andyellwood.com/&quot;&gt;Andy Ellwood&lt;/a&gt; asked
if we could have a script that would query Wikipedia and return article
summaries. Already looking for an opportunity to become more comfortable with
CoffeeScript and Hubot, I said “Sure.”&lt;/p&gt;

&lt;p&gt;So, I asked myself, does Wikipedia have an API? Well,
&lt;a href=&quot;http://www.mediawiki.org/wiki/API:Query&quot;&gt;it turns out that they do&lt;/a&gt;, but
it’s not terribly helpful. For the task at hand&amp;mdash;pulling a summary from
any given article&amp;mdash;the best their API can do is return the entire article
as a huge chunk of malformed HTML. Not exactly ideal, but this is what we have
tools for.&lt;/p&gt;

&lt;h2&gt;Scraping Article Pages&lt;/h2&gt;

&lt;p&gt;So I looked through GitHub’s repository of &lt;a href=&quot;https://github.com/github/hubot-scripts&quot;&gt;existing Hubot scripts&lt;/a&gt; from
the community for ideas on how to proceed. I found &lt;a href=&quot;https://github.com/github/hubot-scripts/blob/master/src/scripts/web.coffee&quot;&gt;web.coffee&lt;/a&gt;, which uses
&lt;a href=&quot;https://github.com/tautologistics/node-htmlparser&quot;&gt;HTMLParser&lt;/a&gt; and &lt;a href=&quot;https://github.com/harryf/node-soupselect&quot;&gt;Soupselect&lt;/a&gt; to parse arbitrary HTML into a workable
DOM. This makes dealing with Wikipedia’s malformed documents somewhat easier.&lt;/p&gt;

&lt;p&gt;So long as we’re going to parse all of the HTML in articles anyway, we may as
well just load the full article pages instead of dealing with their complicated
API:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;makeArticleURL = (title) -&amp;gt;
  &amp;quot;http://en.wikipedia.org/wiki/#{encodeURIComponent(title)}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, in order to get a summary for a given article, I noticed that each article
has a series of &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements on a given page, the first one of which is
usually the summary, so long as it contains enough text. First I made a utility
method to give me arbitrary DOM objects from HTMLParser for ease of use:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;parseHTML = (html, selector) -&amp;gt;
  handler = new HTMLParser.DefaultHandler((() -&amp;gt;),
    ignoreWhitespace: true
  )
  parser  = new HTMLParser.Parser handler
  parser.parseComplete html

  Select handler.dom, selector
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, pulling all paragraphs on the page was simple:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;paragraphs = parseHTML body, &amp;quot;p&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Finding a Summary&lt;/h2&gt;

&lt;p&gt;In order to find the right paragraph&amp;mdash;a summary&amp;mdash;I tried playing
with data from many articles and came up with a simple heuristic that does
quite well:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;findBestParagraph = (paragraphs) -&amp;gt;
  return null if paragraphs.length is 0

  childs = _.flatten childrenOfType(paragraphs[0], &amp;#39;text&amp;#39;)
  text = (textNode.data for textNode in childs).join &amp;#39;&amp;#39;

  # remove parentheticals (even nested ones)
  text = text.replace(/\s*\([^()]*?\)/g, &amp;#39;&amp;#39;).replace(/\s*\([^()]*?\)/g, &amp;#39;&amp;#39;)
  text = text.replace /\s{2,}/g, &amp;#39; &amp;#39;                # squash whitespace
  text = text.replace /\[[\d\s]+\]/g, &amp;#39;&amp;#39;            # remove citations
  text = _s.unescapeHTML text                       # get rid of nasties

  # if non-letters are the majority in the paragraph, skip it
  if text.replace(/[^a-zA-Z]/g, &amp;#39;&amp;#39;).length &amp;lt; 35
    findBestParagraph paragraphs.slice(1)
  else
    text
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Essentially, I collect all of the text under the element and strip out some
undesirable bits, then look to see if the remainder has at least 35 letters
in it. I can’t give a compelling explanation of why this works well, other
than that I tried several methods and limits before landing on this one.
Sometimes there are deceptively simple heuristics that can accomplish tasks
that may seem difficult at first. It can’t hurt to just dive in with some real
data and see what happens.&lt;/p&gt;

&lt;h2&gt;Find All Text Nodes in a DOM Tree&lt;/h2&gt;

&lt;p&gt;The only other bit of difficulty came when trying to extract the text from
the DOM tree generated by HTMLParser. For that, I wrote a recursive method:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;childrenOfType = (root, nodeType) -&amp;gt;
  return [root] if root?.type is nodeType

  if root?.children?.length &amp;gt; 0
    return (childrenOfType(child, nodeType) for child in root.children)

  []
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When dealing with trees, recursion often works quite well. In this case, I
just weed out text nodes from all elements in the DOM subtree rooted at &lt;code&gt;root&lt;/code&gt;,
returning empty array tombstones for everything else, which are later discarded
with &lt;code&gt;_.flatten&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;The Final Product&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/wikibot.png&quot; alt=&quot;The script in action&quot;&gt;&lt;/p&gt;

&lt;p&gt;The final script can be found in &lt;a href=&quot;https://github.com/github/hubot-scripts/blob/dc8c0f1c5a5c94e26513deeeeea29f9e646445e4/src/scripts/wikipedia.coffee&quot;&gt;GitHub’s official hubot-scripts repo&lt;/a&gt;.
Hopefully the simple tactics in this script will help you put together your
own interesting Hubot script, or just help improve your CoffeeScript skills.
Please also let us know if you find ways to improve the script&amp;mdash;we’re
always looking to improve!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Likeable: Love your Objects with Redis</title>
   <link href="http://engineering.gowalla.com/2011/11/03/likeable/"/>
   <updated>2011-11-03T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/11/03/likeable</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://github.com/gowalla/likeable&quot;&gt;Likeable&lt;/a&gt; is a new open-source Ruby library that we built here at Gowalla to power all of the &amp;quot;loves&amp;quot; on stories, comments, highlights and photos that you see. It&amp;#39;s built on top of &lt;a href=&quot;http://redis.io/&quot;&gt;Redis&lt;/a&gt; to be extremely simple, isolated and fast. Likeable plays well with &lt;a href=&quot;http://rubygems.org/gems/activerecord&quot;&gt;ActiveRecord&lt;/a&gt; objects, but can be used with &lt;em&gt;any&lt;/em&gt; Ruby object that implements an &lt;code&gt;#id&lt;/code&gt; method.&lt;/p&gt;

&lt;iframe width=&quot;575&quot; height=&quot;323&quot; src=&quot;http://www.youtube.com/embed/iJoMXUQ33Jw?rel=0&amp;amp;hd=1&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;To see it in action, head over to &lt;a href=&quot;http://gowalla.com/schneems&quot;&gt;my Gowalla profile&lt;/a&gt; and love the first thing you see. Immediately you&amp;#39;ll see the heart change colors and the love count increase by one. If you click on that number you&amp;#39;ll see everyone who has loved that object.&lt;/p&gt;

&lt;p&gt;This might seem trivial at first glance. But consider that &lt;em&gt;dozens of elements&lt;/em&gt; on the page must pull this information: how many people have loved it, whether the viewer has loved it, and (on some pages) which of your friends have loved it. Using Redis allows us to stay simple, flexible and fast.&lt;/p&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s say we&amp;#39;ve got a comment made on a recent Gowalla story.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;@comment = Comment.last
@comment.like_count  #=&amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If our user wants to like this comment, he can do so with ease:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;@user = User.find_by_username(&amp;#39;schneems&amp;#39;)
@user.like! @comment
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that&amp;#39;s it. The comment now reports the details of the like.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;@comment.like_count      #=&amp;gt; 1
@comment.likes           #=&amp;gt; [#&amp;lt;Likeable::Like ... &amp;gt;]
@comment.likes.last.user #=&amp;gt; #&amp;lt;User username: &amp;quot;schneems&amp;quot; ...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;The Install&lt;/h2&gt;

&lt;p&gt;For Rails apps, Likeable is extremely simple to set up.&lt;/p&gt;

&lt;p&gt;First, add Likeable to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;gem &amp;#39;likeable&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Set up your Redis connection in (e.g.) &lt;code&gt;config/initializers/likeable.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Likeable.setup do |likeable|
  likeable.redis = Redis.new
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, add the &lt;code&gt;Likeable::UserMethods&lt;/code&gt; module to your &lt;code&gt;User&lt;/code&gt; model:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;class User &amp;lt; ActiveRecord::Base
  include Likeable::UserMethods
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, add the &lt;code&gt;Likeable&lt;/code&gt; module to any model you want to be likeable:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;class Comment &amp;lt; ActiveRecord::Base
  include Likeable
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To learn more, check out the &lt;a href=&quot;http://github.com/gowalla/likeable&quot;&gt;Likeable source&lt;/a&gt;, look at the &lt;a href=&quot;https://github.com/schneems/likeable_example&quot;&gt;example Rails app&lt;/a&gt; or &lt;a href=&quot;http://www.youtube.com/watch?v=iJoMXUQ33Jw&quot;&gt;watch the Likeable screencast&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Contributing&lt;/h2&gt;

&lt;p&gt;We&amp;#39;d love to get contributions to Likeable. If you want it to do something it doesn&amp;#39;t already, &lt;a href=&quot;https://github.com/gowalla/likeable/issues&quot;&gt;open an issue on GitHub&lt;/a&gt;. Or, if you feel so inclined, create a patch and submit a pull request.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>AFNetworking FAQ</title>
   <link href="http://engineering.gowalla.com/2011/11/01/afnetworking-faq/"/>
   <updated>2011-11-01T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/11/01/afnetworking-faq</id>
   <content type="html">&lt;p&gt;This article is out of date. Please find the most recent version on &lt;a href=&quot;https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ&quot;&gt;the AFNetworking Wiki&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Boxer: Generating Sane JSON from Complex Objects for Our API</title>
   <link href="http://engineering.gowalla.com/2011/10/24/boxer/"/>
   <updated>2011-10-24T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/10/24/boxer</id>
   <content type="html">&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;Here at Gowalla we have a large API with many different types of objects
distributed across many different resources. So composing and showing views of
those objects for API responses has been a challenge.&lt;/p&gt;

&lt;p&gt;We started out by just rendering ActiveRecord models directly to JSON:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;class Api::UsersController &amp;lt; ApiController
  def show
    @user = User.find(params[:id])
    render :json =&amp;gt; @user
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But that quickly became unwieldy as we wanted full and simple control over
which attributes are returned, and to start returning method values alongside
model attributes. So we moved on to writing &lt;code&gt;.json.erb&lt;/code&gt; files, which allowed
us to specify exactly what appears in a response:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;# app/views/users/show.json.erb
&amp;lt;%= raw({
  :name =&amp;gt; @user.name,
  :recent_spots =&amp;gt; @user.recent_spots(30),
  :is_private =&amp;gt; @user.private?
}.to_json) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Though after a long while, these views ended up growing out of control, with
conditionals based on the authenticated user requesting the information,
whether they&amp;#39;re friends, whether the user resource is a business, whether a
promotion is running, etc.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;# app/views/users/show.json.erb
&amp;lt;%
  hash = {
    :name =&amp;gt; @user.name,
    :is_private =&amp;gt; @user.private?
  }
  if user.public?
    hash.merge!({
      :recent_spots =&amp;gt; @user.recent_spots(30),
      :recent_highlights =&amp;gt; @user.recent_highlights(10),
    })
  end
  if user.friends?(current_user)
    hash.merge!({
      :is_friend =&amp;gt; true,
      :mutual_friends =&amp;gt; user.mutual_friends(current_user).map(&amp;amp;:to_hash),
    })
  end
%&amp;gt;
&amp;lt;%= raw(hash.to_json) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;So during our developing of Gowalla 4, we came across Nathan Esquenazi&amp;#39;s
&lt;a href=&quot;https://github.com/nesquena/rabl&quot;&gt;RABL&lt;/a&gt; library, which is a great attempt
at attacking this problem. For our purposes, though, we went with a simpler
and less robust framework that would do exactly what we wanted.&lt;/p&gt;

&lt;p&gt;Our simple framework, &lt;a href=&quot;http://github.com/gowalla/boxer&quot;&gt;Boxer&lt;/a&gt;, knows about
different object representations, the various views each of our objects can
have and will let us compose objects together in responses that satisfy the
complexity of our large API.&lt;/p&gt;

&lt;p&gt;Instead of defining messy conditional views full of merged hashes, Boxer
provides a clean framework for describing the representation and views of
an object as hashes:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Boxer.box(:user) do |box, user|
  box.view(:base) do
    {
      :name =&amp;gt; user.name,
      :age  =&amp;gt; user.age,
    }
  end

  box.view(:full, :extends =&amp;gt; :base) do
    {
      :email      =&amp;gt; user.email,
      :is_private =&amp;gt; user.private?,
    }
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then you can &amp;quot;ship&amp;quot; the contents of a box with a model object (or any other
arguments you want to pass in) and get a JSON-ready hash:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;&amp;gt;&amp;gt; Boxer.ship(:user, User.first, :view =&amp;gt; :full).to_json
=&amp;gt; &amp;quot;{&amp;quot;name&amp;quot;: &amp;quot;Bo Jim&amp;quot;, &amp;quot;age&amp;quot;: 17, &amp;quot;email&amp;quot;: &amp;quot;b@a.com&amp;quot;, &amp;quot;is_private&amp;quot;: false}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In our case, our controllers do more or less a straight render of a shipped
box:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;def show
  @object = Object.find(params[:id])
  render :json =&amp;gt; Boxer.ship(:object, @object, :view =&amp;gt; :full)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more examples and a more in-depth explanation, see the
&lt;a href=&quot;https://github.com/gowalla/boxer#readme&quot;&gt;Boxer README&lt;/a&gt; and the
&lt;a href=&quot;https://github.com/gowalla/boxer/wiki&quot;&gt;project wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Boxer also goes through the trouble of solving small and common problems that
creep up when using this style of framework. Things like &lt;a href=&quot;https://github.com/gowalla/boxer/wiki/Preconditions&quot;&gt;preconditions&lt;/a&gt;,
&lt;a href=&quot;https://github.com/gowalla/boxer/wiki/Helper-Methods-in-Boxes&quot;&gt;helper methods&lt;/a&gt;, &lt;a href=&quot;https://github.com/gowalla/boxer/wiki/Box-Includes&quot;&gt;including methods for use in boxes&lt;/a&gt; and
&lt;a href=&quot;https://github.com/gowalla/boxer/wiki/Multiple-Inheritance&quot;&gt;multiple box inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have released Boxer &lt;a href=&quot;http://rubygems.org/gems/boxer&quot;&gt;as a gem&lt;/a&gt; and, as
noted, an &lt;a href=&quot;https://github.com/gowalla/boxer&quot;&gt;open-source project on GitHub&lt;/a&gt;.
Let us know what interesting uses you find for Boxer, in addition to any
suggested improvements.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>AFNetworking: A Delightful Networking Library for iOS and Mac OS X</title>
   <link href="http://engineering.gowalla.com/2011/10/24/afnetworking/"/>
   <updated>2011-10-24T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/10/24/afnetworking</id>
   <content type="html">&lt;p&gt;This article is out of date. Please find the most recent version on &lt;a href=&quot;https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking&quot;&gt;the AFNetworking Wiki&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Classifying Puppet Nodes with EC2 Security Groups</title>
   <link href="http://engineering.gowalla.com/2011/10/21/puppet/"/>
   <updated>2011-10-21T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/10/21/puppet</id>
   <content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;One of the tools we are using on the operations side of things here at Gowalla is the configuration management tool Puppet. Many of you are likely already familiar with the project, but if not, I definitely recommend that you check it out over at &lt;a href=&quot;http://puppetlabs.com&quot;&gt;Puppet Labs&lt;/a&gt;. It has matured quite a bit since its beginnings, and is now fairly easy to get up and running, especially with all of the open source modules being shared on PuppetForge and GitHub. &lt;/p&gt;

&lt;p&gt;After using Puppet for a bit, you will likely come to know the tedious task of adding and removing node definitions. This is especially true if your infrastructure is hosted on a cloud provider such as EC2, as ours is. We bring down and spin up new instances fairly often, and having to manually add and remove these definitions becomes time-consuming and hampers automation.&lt;/p&gt;

&lt;h2&gt;Puppet ENC and EC2 Security Groups&lt;/h2&gt;

&lt;p&gt;This is where Puppet&amp;#39;s &lt;a href=&quot;http://docs.puppetlabs.com/guides/external_nodes.html&quot;&gt;External Node Classifier&lt;/a&gt; feature comes to the rescue. It allows you to delegate node classification, and therefore which classes are applied to each node, to an external script or application. As you can imagine, this provides all kinds of possibilities for integrating with other systems that may already know about your nodes.&lt;/p&gt;

&lt;p&gt;But what if you don&amp;#39;t already have this information in another system? This is where we found ourselves. After doing a bit of research, we stumbled across a presentation that suggested using EC2 security groups to define nodes. Bingo! This seemed like a great solution. We already had our nodes (mostly) separated into different security groups based on their purpose, as this allowed us to easily define firewall rules between our different types of instances. Why not re-use information that&amp;#39;s already there?&lt;/p&gt;

&lt;p&gt;The implementation was fairly straightforward. We hacked together a quick Ruby script (&lt;a href=&quot;https://gist.github.com/1285462&quot;&gt;ec2_enc.rb&lt;/a&gt;) that would query the EC2 API with a node&amp;#39;s hostname to determine its security group. With that information in hand, the script loads a YAML file (&lt;a href=&quot;https://gist.github.com/1285462&quot;&gt;node_groups.yml&lt;/a&gt;) containing all of the security groups mapped to the classes and parameters to be applied, and passes the proper data back to the puppetmaster. After creating the YAML file with the required mappings, we were up and running.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s a simple solution that has worked quite well for us so far. Of course there&amp;#39;s always room for improvement&amp;mdash;please feel free to use, modify and send us feedback at will!&lt;/p&gt;

&lt;h3&gt;Files&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/1285462&quot;&gt;ec2_enc.rb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/1285462&quot;&gt;node_groups.yml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>So You Want to Hire an Intern?</title>
   <link href="http://engineering.gowalla.com/2011/10/21/interns/"/>
   <updated>2011-10-21T00:00:00-07:00</updated>
   <id>http://engineering.gowalla.com/2011/10/21/interns</id>
   <content type="html">&lt;p&gt;This past summer, Gowalla brought on its second intern, &lt;a href=&quot;https://twitter.com/ehm_may&quot;&gt;Michael May&lt;/a&gt;, a Computer Science undergrad from the University of Texas. In turn, Michael brought us a great amount of enthusiasm and ability.&lt;/p&gt;

&lt;p&gt;I had the pleasure of mentoring Michael over his internship. It led me to reflect on my days of interning when I was still at Georgia Tech. Having seen both sides of the intern/employer relationship, I&amp;#39;d like to clear up some common misconceptions about interns, and offer suggestions on how to keep the relationship fruitful and symbiotic.&lt;/p&gt;

&lt;h2&gt;Myth: Interns are cheap labor! Replace all your employees weith interns!&lt;/h2&gt;

&lt;p&gt;I hear this one all the time from developers &amp;mdash; Instead of hiring one employee, they&amp;#39;ll hire three interns: instant three-fold increase in output. Sadly, &lt;a href=&quot;http://en.wikipedia.org/wiki/The_Mythical_Man_Month#The_mythical_man-month&quot;&gt;The Mythical Man-Month&lt;/a&gt; applies at least as much for interns as for employees.&lt;/p&gt;

&lt;h2&gt;Reality:&lt;/h2&gt;

&lt;p&gt;Interns are new employees. Like any new employee, they&amp;#39;ll need a certain amount of ramping-up time before they can start contributing. Others from the team will have to invest time to get them up to speed. And unlike a full-time employee, you lose all that training time when they leave to go back to school. They may be &amp;quot;cheap&amp;quot; on the pocketbook, but their cost goes far deeper than that. The good news: it forces your organization to get good at bringing people up to speed, and to put the right processes and tools in place to do so &amp;mdash; an asset for a quickly-growing company.&lt;/p&gt;

&lt;h2&gt;Myth: Interns are great for doing degrading or extremely repetitive work!&lt;/h2&gt;

&lt;p&gt;In my first internship, I didn&amp;#39;t have to make coffee, but I did have to make thousands of manual z-folds for brochures we sent out.  I also had to wash the bosses&amp;#39; grill, and even disassemble and fix a toilet. This might have been great for the company I was working for, but it wasn&amp;#39;t exactly the work experience I would have liked to put on my post-college résumé.&lt;/p&gt;

&lt;h2&gt;Reality:&lt;/h2&gt;

&lt;p&gt;Interns offer the chance to hire someone fresh out of college who was trained on the cheap and already knows your organization inside and out. If you insist on using your interns for nothing but cheap, mindless labor, you won&amp;#39;t find them knocking down your door after graduation. (Even worse: they might quit on you mid-term.) But even if they&amp;#39;re willing to come back to work for you, how have those chores prepared them to be valuable contributors?&lt;/p&gt;

&lt;p&gt;Give your interns the tools and resources they need to do their jobs &amp;mdash; not just a desk and an internet connection, but also direction and feedback. The more you treat them like real employees, the more you&amp;#39;ll get back. If your employees aren&amp;#39;t learning from their mistakes, and celebrating their successes, how can the company know if it&amp;#39;s headed in the right direction? Be forward with expectations, and be vocal when those expectations aren&amp;#39;t met, or when they&amp;#39;ve been surpassed. This isn&amp;#39;t easy, but it has to be done.&lt;/p&gt;

&lt;h2&gt;Myth: Interns are lazy! They&amp;#39;re not capable of doing &amp;quot;real&amp;quot; work.&lt;/h2&gt;

&lt;p&gt;When I worked for a major American appliance manufacturer, I played Flash games for a whole week because no one could find me anything &amp;quot;I could do.&amp;quot; While it did wonders for my high scores, it was a suck on my morale, and a drain on company funds.&lt;/p&gt;

&lt;h2&gt;Reality:&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve seen interns do incredible things. Once he was comfortable with the code and the team, Michael started knocking out features and closing quite a few GitHub issues. Just like full-time employees, interns want to do work that impresses and amazes. Just like full-time employees, interns work best when they can see how the work they&amp;#39;re doing affects the big picture. Pair them up with different members of your team and come up with a number of different projects your intern can work on. Don&amp;#39;t underestimate their abilities.&lt;/p&gt;

&lt;h2&gt;Sum it all up:&lt;/h2&gt;

&lt;p&gt;Interns take a lot of time and energy, but they can be incredibly rewarding to you and your company. If you want to hire one, make sure they have a dedicated mentor, someone who can and should regularly ask: &amp;quot;Do you have enough to do?&amp;quot;, &amp;quot;Is there anything you need?&amp;quot;, &amp;quot;What are you working on?&amp;quot; &amp;mdash; and simply, &amp;quot;Are you happy?&amp;quot;. The mentor should have informal meetings with the intern on a regular basis &amp;mdash; at least once a week, but perhaps as often as once a day.&lt;/p&gt;

&lt;p&gt;You will also need several people interested in spec-ing out tasks for your junior employee &amp;mdash; not just for the initial assignment, but to answer the occasional question during the task. And you&amp;#39;ll need employees to do pair programming with the intern until they&amp;#39;re familiar enough with your codebase to take on tasks by themselves. When your intern is busy, your intern is happy. And so is your company.&lt;/p&gt;
</content>
 </entry>
 

</feed>