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

  <title><![CDATA[99designs Tech Blog]]></title>
  <link href="http://99designs.com/tech-blog/atom.xml" rel="self"/>
  <link href="http://99designs.com/tech-blog/"/>
  <updated>2013-06-19T22:04:24+10:00</updated>
  <id>http://99designs.com/tech-blog/</id>
  <author>
    <name><![CDATA[99designs]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Internationalizing 99designs]]></title>
    <link href="http://99designs.com/tech-blog/blog/2013/06/17/internationalizing-99designs/"/>
    <updated>2013-06-17T10:25:00+10:00</updated>
    <id>http://99designs.com/tech-blog/blog/2013/06/17/internationalizing-99designs</id>
    <content type="html"><![CDATA[<p>by <a href="https://plus.google.com/u/0/109946864654892236078?rel=author">Lars Yencken</a></p>

<p>Two years ago, 99designs had localized sites for a handful of English speaking countries, and our dev team had little experience in multilingual web development. But we felt that translating our site was an important step, removing yet another barrier for designers and customers all over the world to work together. Today we serve localized content to customers in 18 countries, across six languages. Here&#8217;s how we got there, and some of the road blocks we ran into.</p>

<h2>Starting local</h2>

<p>The most difficult aspect to internationalizing is language, so we started with localization: everything <em>but</em> language. In particular, this means region-appropriate content and currency. A six-month development effort saw us refactor our core PHP codebase to support local domains for a large number of countries (e.g. 99designs.de), where customers could see local content and users could pay and receive payments in local currencies. At the end of this process, each time we launched a regional domain we began redirecting users to that domain from our Varnish layer, based on GeoIP lookups. The process has changed little since then, and continued to serve us well in our recent launch in Singapore.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/world-density-map.png" width="600" height="451" title="A density map of 99designs activity" ></p>

<h2>Languages and translation</h2>

<p>With localization working, it was time to make hard decisions about how we would go about removing the language barrier for non-English speakers (i.e. the majority of the world).There were a lot of questions for us to answer.</p>

<ul>
<li>What languages will we offer users in a given region?</li>
<li>How will users choose their language?</li>
<li>How will we present translated strings to users?</li>
<li>How will strings be queued for translation?</li>
<li>Who will do the translation?</li>
</ul>


<h3>What languages to offer?</h3>

<p>Rather than making region, language and currency all user selectable, we chose to restrict language and currency availability to a user&#8217;s region. This was a trade-off which made working with local content easier: if our German region doesn&#8217;t support Spanish, we avoid having to write Spanish marketing copy for it. Our one caveat was for all regions to support English as a valid language. As an international language of trade, this lessens any negative impact of region pinning.</p>

<h3>Translating strings</h3>

<p>There were two main approaches we considered for translation: use a traditional <a href="http://www.gnu.org/software/gettext/">GNU gettext</a> approach and begin escaping strings, or else try a translation proxy such as <a href="http://www.smartling.com/">Smartling</a>. gettext had several advantages: it has a long history, and is well supported by web frameworks; it&#8217;s easily embedded; and translations just become additional artifacts which can be easily version controlled. However, it would require a decent refactoring of our existing PHP codebase, and left open issues of how to source translations.</p>

<p>In Smartling&#8217;s approach, a user&#8217;s request is proxied through Smartling&#8217;s servers, in turn requesting the English version of our site and applying translations to the response before the user receives it. When a translation is missing, the English version is served and the string is added to a queue to be translated. Pulling this off would mean reducing substantially the amount of code to be changed, a great win. However, it risked us relying on a third-party for our uptime and performance.</p>

<p>In the end, we went with Smartling for several reasons. They provided a source of translators, and expertise in internationalization which we were lacking. Uptime and performance risks were mitigated somewhat by two factors. Firstly, Smartling&#8217;s proxy would be served out of the US-East AWS region, the same region our entire stack is served from, increasing the likelihood that their stack and ours would sink or swim together. Secondly, since our English language domains would continue to be served normally, the bulk of our traffic would still bypass the proxy and be under our direct control.</p>

<h2>Preparing our site</h2>

<p>We set our course and got to work. There was substantially more to do than we first realized, mostly spread over three areas.</p>

<h3>Escaping user-generated content</h3>

<p>Strings on our site which contained user content quickly filled our translation queue (think &#8220;Logo design for <em>Greg</em>&#8221; vs &#8220;Logo design for <em>Sarah</em>&#8221;). Contest titles, descriptions, usernames, comments, you name it, anything sourced from a user had to be found and wrapped in a <code>&lt;span class="sl_notranslate"&gt;</code> tag. This amounted to a significant ongoing audit of the pages on our site, fixing them as we went.</p>

<h3>Preparing Javascript for translation</h3>

<p>Our Javascript similarly needed to be prepared for translation, with rich client-side pages the worst hit. All strings needed to be hoisted to a part of the JS file which could be marked up for translation. String concatenation was no longer ok, since it made flawed assumptions about the grammar of other languages. Strings served through a JSON API were likewise hidden from translation, meaning we had to find other ways to serve the same data.</p>

<h3>Making our design more flexible</h3>

<p>In our design and layout, we could no longer be pixel-perfect, since translated strings for common navigation elements were often much longer in the target language. Instead, it forced us to develop a more robust design which could accommodate the variation in string width. We stopped using CSS transforms to vary the case of text stylistically, since other languages are more sensitive to case changes than English.</p>

<h2>The wins snowball</h2>

<p>After 9 months of hard work, we were proud to launch a German language version of our site, a huge milestone for us. With the hardest work now done, the following 9 months saw us launch French, Italian, Spanish and Dutch-language sites. Over time, the amount of new engineering work reduced with each launch, so that the non-technical aspects of marketing to, supporting and translating a new region now dominate the time to launch a new language.</p>

<h2>The challenges</h2>

<p>We also encountered several unexpected challenges.</p>

<h3>Client-side templating</h3>

<p>We mentioned earlier that the richer the client-side JS, the more work required to ensure smooth translation. The biggest barrier for us was our use of <a href="http://mustache.github.io/">Mustache</a> templates, which were initially untranslatable on the fly. To their credit, Smartling vastly improved their support for Mustache during our development, allowing us to clear this hurdle.</p>

<h3>Translating non-web artifacts</h3>

<p>It should be no surprise: translation by proxy is a strategy for web pages, but not a strong one for other non-web artifacts. In particular, for a long time translating emails was a pain, and in the worst case consisted of engineers and country managers basically emailing templates for translation back and forward. After some time, we worked around this issue by using Smartling&#8217;s API in combination with gettext for email translation.</p>

<h3>Exponential growth of translation strings</h3>

<p>Over time, we repeatedly found our translation queue clogged with huge numbers of strings awaiting translation. Many of these cases were bugs where we hadn&#8217;t appropriately marked up user-generated content, but the most stubborn were due to our long-tail marketing efforts. Having a page for each combination of industry, product category and city led to an explosion of strings to translate. Tackling these properly would require a <a href="http://en.wikipedia.org/wiki/Natural_language_generation">natural language generation</a> engine with some understanding of each language&#8217;s grammar. For now we&#8217;ve simply excluded these pages from our translation efforts.</p>

<h2>The future</h2>

<p>This has been an overview of the engineering work involved in localizing and translating a site like ours to other languages. Ultimately, we feel that the translation proxy approach we took cut down our time to market significantly; we&#8217;d recommend it to other companies who are similarly expanding. Now that several sites are up and running, we&#8217;ll continue to use a mix of the proxy and gettext approaches, where each is most appropriate.</p>

<p>We&#8217;re proud to be able to ship our site in multiple languages, and keen to keep breaking down barriers between businesses and designers wherever they may be, enabling them to work together in the languages in which they&#8217;re most comfortable.</p>

<p>Discuss on <a href="https://news.ycombinator.com/item?id=5902935">Hacker News</a> or <a href="http://www.reddit.com/r/programming/comments/1gmfl8/internationalizing_99designs/">Reddit</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The rails asset pipeline for every framework!]]></title>
    <link href="http://99designs.com/tech-blog/blog/2013/06/04/Sprockets-with-Go/"/>
    <updated>2013-06-04T10:56:00+10:00</updated>
    <id>http://99designs.com/tech-blog/blog/2013/06/04/Sprockets-with-Go</id>
    <content type="html"><![CDATA[<p>by Daniel Heath</p>

<p>I recently found myself wanting the features of the rails asset pipeline in my golang project at work. Since there isn&#8217;t much in the way of asset pipelining for golang yet, I built it. Turns out, sprockets is really easy to integrate. Here&#8217;s how you can go about setting it up for your project.</p>

<h2>Assets in development</h2>

<p>First things first - lets get it to the &#8216;it works on my machine&#8217; stage. I&#8217;ve put together a <a href="https://github.com/DanielHeath/sprockets-sample">sample repo</a> using the asset pipeline, which you can use as a guide.</p>

<p>The setup for your app will be similar:</p>

<ul>
<li>The <code>assets</code> folder contains your stylesheets, javascript, etc (this directory name is set in <code>sprockets/environment.rb</code>).</li>
<li>You&#8217;ll need a similar <code>Rakefile</code> to build assets (and maybe launch the server)</li>
<li>You might store the <code>sprockets</code> directory somewhere else - update the <code>Rakefile</code> to match.</li>
<li>Use a Gemfile and the bundler rubygem to manage dependencies.</li>
<li>Edit the rakefile to change the port the asset server runs on.</li>
</ul>


<p>When your app starts up (in development), it should make a request to <code>http://localhost:11111/assets/manifest.json</code>, which provides a JSON hash linking asset names (e.g. &#8220;application.css&#8221;) to the relative URLs the compiled assets can be fetched from. To generate a link to an asset in your app, use the JSON hash you fetched to lookup the URL. For example, the URL for &#8220;application.css&#8221; this might look like <code>http://localhost:11111/application-8e5bf6909b33895a72899ee43f5a9d53.css</code>.</p>

<p>That should be all you need for development - you should be able to see SASS/Coffeescript assets compiled and loading normally. Hooray!</p>

<h2>Assets in production</h2>

<p>For production we want to pre-compile assets rather than regenerating them each time they change.</p>

<p><code>rake assets</code> will create a &#8216;public&#8217; folder containing &#8216;manifest.json&#8217; (same format as before). Get this directory onto your production servers. <code>git add -Af public/</code> will add it to source control if you deploy via git.</p>

<p>When generating a link to an asset, simply look up <code>manifest.json</code> from the filesystem rather than from HTTP.</p>

<h2>Fin</h2>

<p>If you&#8217;ve followed these steps, you&#8217;ll have a fullly functioning asset pipeline for your golang project. The whole thing, including deployment, took me well under a day to add to our app. The resulting assets are minified, concatenated, and gzipped (for size). They are also fingerprinted, so you can serve them with an unlimited cache lifetime and reap the benefits.</p>

<p>Although I set this up for golang, there&#8217;s nothing go-specific about it. The same technique works just as well for any language or framework without a mature asset pipeline. If you find yourself in need, just use this pattern and you can be up and running in no time.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bug tracking with GitHub Survivor]]></title>
    <link href="http://99designs.com/tech-blog/blog/2013/01/05/github-survivor/"/>
    <updated>2013-01-05T22:55:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2013/01/05/github-survivor</id>
    <content type="html"><![CDATA[<p>by Stuart Campbell</p>

<p>At 99designs, we try to make sure we&#8217;re always fixing bugs as well as writing
code. It can be easy to neglect bugs when you&#8217;re busy churning out new features.</p>

<p>We use GitHub issues to track bugs in our various applications. GitHub issues
integrate well with our codebase, commits and pull requests, but the reporting
facilities are a bit limited.</p>

<p>As our team grows, it&#8217;s become increasingly important for us to be able to
answer key questions about bugs, including:</p>

<ul>
<li>How many bugs are currently open?</li>
<li>Have we each remembered to spend time working on bug fixes this sprint?</li>
<li>Are we closing more bugs than we&#8217;re opening?</li>
</ul>


<p>To help answer these questions, a few of our team spent a number of
<a href="http://99designs.com/tech-blog/blog/2012/03/16/research-and-development/">hack days</a>
implementing a bug dashboard named <a href="https://github.com/99designs/githubsurvivor">GitHub Survivor</a>.</p>

<p>Unlike the similarly-named reality TV show, GitHub Survivor doesn&#8217;t feature
eliminations, gruelling physical challenges, or Jeff Probst. However, it <em>does</em>
pit developers against one another &mdash; in a light-hearted way.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/github-survivor.png" width="500" height="315"></p>

<p>We display GitHub Survivor on a big screen in the office, where all the team can
see it. We&#8217;ve found it helps keep our minds on bugs &mdash; it reminds us to
make a small effort every sprint, gradually bringing the bug count closer to
zero.</p>

<p>A bug leaderboard occupies the bulk of the screen. It shows who&#8217;s closed the
most bugs this sprint <em>(may they be laden with Praise and Whisky!)</em> and who&#8217;s
forgotten to spend some time fixing bugs <em>(may they toil in the maintenance of a
thousand <a href="http://en.wikipedia.org/wiki/Malbolge">Malbolge</a> programs!)</em>.</p>

<p>There are charts showing the number of bugs opened and closed in recent sprints,
the open bug count over time, and a big indicator showing the current open bug
count.</p>

<p>The <a href="https://github.com/99designs/githubsurvivor">source is available</a> for you
to inspect and adapt to your needs. Please try it out, make improvements and
contribute them back! We hope you find it useful.</p>

<p>We&#8217;re passionate about building high-quality software at 99designs, and this
is just one way we measure whether we&#8217;re doing a good job of that. If you&#8217;re
similarly interested in building cool things in an awesome environment,
<a href="http://99designs.com.au/about/jobs">check out our open positions</a>!</p>

<p>Join the discussion at <a href="http://news.ycombinator.com/item?id=5018583">Hacker News</a>
and <a href="http://www.reddit.com/r/programming/comments/1639ru/github_survivor_a_bug_leaderboard_for_github/">Reddit</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby metaprogramming for the lulz]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/10/30/abusing-ruby-for-fun-and-profit/"/>
    <updated>2012-10-30T22:30:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/10/30/abusing-ruby-for-fun-and-profit</id>
    <content type="html"><![CDATA[<p>by Richo Healey</p>

<p>What if it were possible to call methods with spaces in their name directly from Ruby?</p>

<p>If you&#8217;ve seen Gary Bernhardt&#8217;s <a href="https://www.destroyallsoftware.com/talks/wat">awesome talk</a> where he digs into some of the quirks of Ruby, you&#8217;ll know that it&#8217;s pretty trivial to get bare words in Ruby:</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="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">001</span> <span class="o">&gt;</span> <span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">002</span><span class="o">?&gt;</span>   <span class="n">args</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">003</span><span class="o">?&gt;</span>   <span class="k">end</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="kp">nil</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">004</span> <span class="o">&gt;</span> <span class="n">ruby</span> <span class="n">has</span> <span class="n">bare</span> <span class="n">words</span>
</span><span class='line'><span class="no">SystemStackError</span><span class="p">:</span> <span class="n">stack</span> <span class="n">level</span> <span class="n">too</span> <span class="n">deep</span>
</span></code></pre></td></tr></table></div></figure>


<p>Wait.. What?</p>

<p>Disappointing to say the least. Obviously something is amiss. It turns out this is just a quirk in irb; if you try instead</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>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">001</span> <span class="o">&gt;</span> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">method_missing</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">002</span><span class="o">?&gt;</span>   <span class="n">args</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">003</span><span class="o">?&gt;</span>   <span class="k">end</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">nil</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">004</span> <span class="o">&gt;</span> <span class="n">ruby</span> <span class="n">has</span> <span class="n">bare</span> <span class="n">words</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s2">&quot;ruby has bare words&quot;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">005</span> <span class="o">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Cool, so what else can we do with this? It&#8217;s trivial to define a method with a space in its name, and calling it isn&#8217;t terribly difficult:</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>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">005</span> <span class="o">&gt;</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:define_method</span><span class="p">,</span> <span class="ss">:&quot;i have a space&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">006</span> <span class="o">&gt;</span>     <span class="nb">puts</span> <span class="s2">&quot;I has a space&quot;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">007</span><span class="o">?&gt;</span>   <span class="k">end</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="c1">#&lt;Proc:0x007ff89c1e0b58@(irb):5 (lambda)&gt;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">00</span><span class="mi">8</span> <span class="o">&gt;</span> <span class="nb">send</span><span class="p">(</span><span class="ss">:&quot;i have a space&quot;</span><span class="p">)</span>
</span><span class='line'><span class="n">I</span> <span class="n">has</span> <span class="n">a</span> <span class="n">space</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">nil</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">00</span><span class="mi">9</span> <span class="o">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>But having created such a monstrosity, how do you call it from the repl? Or for that matter, from an actual Ruby program? This is obviously something you should be doing in production&#8230;</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>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">self</span><span class="o">.</span><span class="n">instance_exec</span> <span class="k">do</span>
</span><span class='line'><span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="n">sym</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>  <span class="c1"># Splat args if passed in from a parent call</span>
</span><span class='line'>  <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">length</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">is_a?</span><span class="p">(</span><span class="nb">Array</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="mi">0</span><span class="o">].</span><span class="n">class</span> <span class="o">==</span> <span class="no">NameError</span>
</span><span class='line'>    <span class="n">args</span> <span class="o">=</span> <span class="n">args</span><span class="o">[</span><span class="mi">0</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">method_names</span><span class="p">,</span> <span class="n">arguments</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">partition</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="n">a</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="no">NameError</span> <span class="p">}</span>
</span><span class='line'>  <span class="nb">method</span><span class="p">(</span><span class="o">[</span><span class="n">sym</span><span class="o">.</span><span class="n">to_s</span><span class="p">,</span> <span class="o">*</span><span class="n">method_names</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:name</span><span class="p">)</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">))</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">)</span>
</span><span class='line'><span class="k">rescue</span> <span class="no">NameError</span> <span class="o">=&gt;</span> <span class="n">e</span>
</span><span class='line'>  <span class="k">return</span> <span class="o">[</span><span class="n">e</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="o">]</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>Bam. You may be looking at this baffled (or if you&#8217;re reasonably tight with metaprogramming in Ruby, sharpening/setting fire to something with a view to causing me significant bodily harm).</p>

<p>Walking through this, we first of all act on whatever <code>self</code> is; in most cases this will be the local scope. If we didn&#8217;t do this, we&#8217;d be defining the method on <code>Object</code>, which can cause all kinds of headaches when you&#8217;re trying to debug.</p>

<p>Immediately after this, we unpack arguments if they look like they were created by an earlier instance of this method. This is unwieldy, but unfortunately Ruby&#8217;s single return values and the recursion we&#8217;re employing here make it necessary. We could definitely define a subclass of <code>Array</code> to make the test cleaner and the implementation more robust, but I preferred to keep this as short as possible and use the bare minimum number of Ruby primitives.</p>

<p>Once we&#8217;ve unpacked our arguments, we do the real magic. First off, we split our arguments into <code>NameError</code>s, the container we&#8217;re using for our missing method names, and everything else (the legitimate arguments we were called with).</p>

<p>We try to find a method with the current name (as we&#8217;ll be building our method name right to left with recursive calls to <code>method_missing</code>), and failing that we pack up our current attempt with our arguments, and return it for the next pass.</p>

<p>There are enough issues with this (if you defined the methods <code>foo bar baz</code> and <code>bar baz</code>, a call to <code>foo bar baz</code> would call <code>foo</code> with <code>bar baz</code>s return) to make it unwieldy. On the other hand; if those bugs are the only thing stopping you from putting this into production, you’ve probably got larger issues.</p>

<p>If this large scale abuse of the language excites you, you might be interested to know that <a href="https://99designs.com.au/about/jobs">we&#8217;re hiring</a>.</p>

<p>At this point you&#8217;re probably eager to know.. does it work?</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>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">001</span> <span class="o">&gt;</span> <span class="nb">load</span> <span class="s2">&quot;bare_words.rb&quot;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">002</span> <span class="o">&gt;</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:define_method</span><span class="p">,</span> <span class="ss">:&quot;i has a space&quot;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="nb">name</span><span class="p">,</span> <span class="n">greeting</span><span class="o">|</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">003</span> <span class="o">&gt;</span>     <span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">greeting</span><span class="si">}</span><span class="s2">, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">!&quot;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">004</span><span class="o">?&gt;</span>   <span class="k">end</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="c1">#&lt;Proc:0x007fc6b41872c0@(irb):2 (lambda)&gt;</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">005</span> <span class="o">&gt;</span> <span class="n">i</span> <span class="n">has</span> <span class="n">a</span> <span class="n">space</span> <span class="s2">&quot;richo&quot;</span><span class="p">,</span> <span class="s2">&quot;Hello&quot;</span>
</span><span class='line'><span class="no">Hello</span><span class="p">,</span> <span class="n">richo!</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">nil</span>
</span><span class='line'><span class="mi">1</span><span class="o">.</span><span class="mi">9</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="n">p286</span> <span class="p">:</span><span class="mo">006</span> <span class="o">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Join the discussion at <a href="http://news.ycombinator.com/item?id=4725466">Hacker News</a> and <a href="http://www.reddit.com/r/programming/comments/12fgub/ruby_metaprogramming_for_the_lulz/">Reddit</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Talk Like a Pirate Day]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/09/19/talk-like-a-pirate-day/"/>
    <updated>2012-09-19T13:10:00+10:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/09/19/talk-like-a-pirate-day</id>
    <content type="html"><![CDATA[<p>by David Lutz</p>

<p><img class="center noborder" src="http://99designs.com/tech-blog/images/agent99-pirate2.jpg" width="541" height="398"></p>

<p>If you had happened to have been wandering around the 99designs office today you would have heard hysterical laughter and cries of &#8220;yarrrr&#8221;.</p>

<p>Something we try to do is foster a good &#8220;DevOps&#8221; working culture.  One of the critical components of DevOps is a collaborative way of working and close working relationship between those working in development and operations.  And other parts of the business for that matter.  Company culture is something that is tricky to improve if it&#8217;s not working, but immediately obvious when it is working.</p>

<p>A key component of good company culture is good communication.  We make extensive use of IRC as a communication medium.  Naturally we use it for technical discussions like &#8220;How does this component of code work&#8221;, but just like companies like GitHub and Etsy we use IRC within the company as a very effective method of documenting what both dev and ops are doing day to day. We also have a bot that lives in IRC and does useful things for us.  Our bot is called agent99.  She makes our life easier and has the ability to do such things as deploy new versions of code to our production website.</p>

<p>She also has a bit of character. She can find memes to punctuate the moment, or fetch funny pictures of cats when asked.</p>

<p>We&#8217;ve actually open-sourced <a href="https://github.com/99designs/agent99">agent99</a> as well as <a href="https://github.com/99designs/">many other</a> pieces of code. We like to contribute code that we think might be useful to others back to the community.</p>

<p>So what was the source of hysterical laughter?  Well today is Talk Like a Pirate Day.  So one of our staff hacked together a plugin to make agent99 send a &#8220;yarr&#8221; over the office speakers. Hilarity ensued. It was quicky repatched, so that &#8220;yarr&#8221; only works one golden day a year.</p>

<p>This is a little example of where all are empowered to use technology to make it a more enjoyable workplace. And a work environment that is both fun and technically challenging is a competitive advantage in that helps attract and retain motivated and happy employees!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[99designs color explorer]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/08/02/color-explorer/"/>
    <updated>2012-08-02T10:00:00+10:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/08/02/color-explorer</id>
    <content type="html"><![CDATA[<p>by Dennis Hotson</p>

<p><em>Here&#8217;s a sneak peek of some experimental stuff we&#8217;ve been working on at <a href="http://99designs.com">99designs</a>.<br /></em>
<em><a href="http://99designs.com/labs/color">99designs color explorer</a> is a tool for browsing designs by color.</em></p>

<p><a href="http://99designs.com/labs/color"><img class="center noborder" src="http://99designs.com/tech-blog/images/color-explorer.png" width="700" height="503" title="99designs color explorer" ></a></p>

<h2>Nerdy technical details</h2>

<p>For those interested in the technical details, color explorer uses <a href="https://github.com/99designs/colorific">colorific</a> to extract colors from logo designs (We&#8217;ve written <a href="http://99designs.com/tech-blog/blog/2012/05/11/color-analysis/">more about colorific</a> previously). It&#8217;s also using <a href="https://github.com/dhotson/colordb">colordb</a>, a side project of mine designed to efficiently index and search by color using some fancy perceptual nearest-neighbour algorithms.</p>

<p>Colordb turned out to be super easy to implement thanks to a few excellent Python libraries: <a href="http://toblerity.github.com/rtree/">Rtree</a>, <a href="http://flask.pocoo.org/">Flask</a> and <a href="http://code.google.com/p/python-colormath/">colormath</a>.</p>

<p>Rome wasn&#8217;t built in a day—but the 99designs color explorer definitely <em>was</em> built in a day thanks to these great libraries.</p>

<h2>R-trees</h2>

<p><a href="http://en.wikipedia.org/wiki/R-tree">R-trees</a> are a useful data structure for indexing spatial data such as the location of planets in the solar system or coffee shops in your local area. In this case, colordb uses an R-tree to index colors since colors can also be kind of spatial and three dimensional (colordb uses the <a href="http://en.wikipedia.org/wiki/Lab_color_space">Lab color space</a> that has L, a, and b dimensions instead of the typical x, y and z). Normally you&#8217;d use an R-tree to help find nearby coffee shops but I&#8217;ve used it instead to find nearby colors.</p>

<p>The best part about R-trees is that they let you do nearest-neighbour searches efficiently. This means that you can search for a color and it will return results with colors that are similar—it means the search doesn&#8217;t have to be exact.</p>

<p>By indexing colors in the Lab color space, colordb is also able to give search results that are <em>perceptually similar</em>. Color differences in the Lab color space are perceptually uniform. This means that <strong>comparing colors in the Lab color space matches how human eye perceives color</strong>.</p>

<h2>Flask</h2>

<p><a href="http://flask.pocoo.org/">Flask</a> is a micro-framework for making little web apps in Python. Flask made it dead-easy to add a simple HTTP interface to colordb in order to integrate colordb with the rest of the 99designs codebase.</p>

<h2>Putting it all together</h2>

<p>So, there&#8217;s a couple of things that make color explorer work:</p>

<p>We used colorific to extract the top two colors in a design and insert them into colordb.
At the time of writing, there are ~120,000 designs indexed in colordb.</p>

<p>The color explorer backend code connects to colordb over HTTP to search for a color. Colordb returns designs that contain a color similar to the one searched for. Color explorer is then able to serve up the HTML markup with the matching designs into what you see on the page.</p>

<p>That&#8217;s about all there is really. It&#8217;s quite simple.</p>

<h2>Why?</h2>

<p>So, what&#8217;s the point of all this? Well, mostly because I thought it&#8217;d be fun to make. :-)</p>

<p>But there&#8217;s another reason. I&#8217;m a big fan of using clever computer science to make software <em>simpler</em>. I love the idea of making user&#8217;s lives easier by using sophisticated algorithms to <em>reduce</em> complexity.</p>

<p>Color explorer is an experiment in taking an open ended problem such as &#8220;search designs by color&#8221; and using clever computer science to create a solution that is simple, powerful and easy to use.</p>

<p>Some other great examples of this principle in practice are Google&#8217;s search and Apple&#8217;s Siri.</p>

<p>I think it&#8217;s pretty amazing that Google is able to hide an incredibly sophisticated search engine behind a single text input. Likewise, Apple&#8217;s Siri is able to combine sophisticated machine learning, voice recognition and language analysis to enable people to perform tasks simply by speaking into their phone.</p>

<p><em>Isn&#8217;t that remarkable?</em></p>

<h2>Acknowledgements</h2>

<p>A big thanks to <a href="https://twitter.com/#!/josh_amos">Josh Amos</a> for his help on the UI and visual style.</p>

<p>This experiment was built as part of a 99designs <abbr title="Research and Development">R&amp;D</abbr> day. Every second Friday we have a day to spend on an interesting work related side-project. So, a big thank you to <a href="http://99designs.com">99designs</a> for letting our dev and design team loose to make cool and crazy stuff.</p>

<p>By the way, if this sounds like your cup of tea—did I mention that <a href="http://99designs.com/about/jobs">99designs is hiring</a>? :-)</p>

<h2>Discuss</h2>

<p>Join the discussion at <a href="http://news.ycombinator.com/item?id=4328470">Hacker News</a> and <a href="http://www.reddit.com/r/programming/comments/xk71s/99designs_color_explorer/">Reddit</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Extracting colors with Colorific]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/05/11/color-analysis/"/>
    <updated>2012-05-11T13:24:00+10:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/05/11/color-analysis</id>
    <content type="html"><![CDATA[<p>by Dennis Hotson and Lars Yencken</p>

<p><em>At 99designs we love great design, and a big part of good design is use of
color. We were interested to see how designers make use of color in their
designs, so we built an automatic color extractor to enable us to analyse
color usage at a massive scale.</em></p>

<h2>Introduction</h2>

<p>Think of a design you love. Part of the story it tells is in the colors it
uses, the contrast of light and shade, and the subtle emotions those colors
convey.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/heart-small.png" width="300" height="260" title="99designs loves color" ></p>

<p>It&#8217;s pretty easy for a human to tell what colors are important in a design.
Take this logo below for example. Most people identifying the important colors would
come up with something like this:</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/13913961-largecrop.jpg" width="237" height="166" title="The Elite Barber Shop by piratepig™" ></p>

<div class="swatch">
  <div class="color" style="background: #bf1e2e">#bf1e2e</div>
  <div class="color" style="background: #569cbe">#569cbe</div>
</div>


<p>Images are made up of pixels, and if you just count the colors of every pixel,
you don&#8217;t get anything like the list of colors above. This post is about our
journey working out how to automatically work out an image&#8217;s color palette that
is close to what a real person would pick.</p>

<h2>Problem 1: Detecting background color</h2>

<p>Quick quiz: What&#8217;s the primary color in this image?</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/motorola-small.jpg" width="300" height="210" title="The Motorola logo" ></p>

<p>Answer: White!</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/motorola-pie.png" width="204" height="204" title="Point colors found in the Motorola logo" ></p>

<p>The problem here is that simply counting the number of pixels with a given
color <strong>the background color nearly always dominates</strong>. We need to work out the
background color so we can exclude it.</p>

<p>We found a simple approach that works well in most cases. We
found that if the pixels in the corners of the image are the same color, that
color was the background.</p>

<p>Let&#8217;s look again. In this case, the corner pixels are: <code>#ffffff</code>, <code>#ffffff</code>,
<code>#ffffff</code>, <code>#ffffff</code> &#8211; all white. We can thus safely exclude white as
a background color, leaving red as the most frequent color. <em>Nice!</em></p>

<h2>Problem 2: Too many colors</h2>

<p>Quiz time again, how many colors are in this image?</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/google.png" width="358" height="148" title="Google's logo" ></p>

<p>4 colors right? Not quite. Look closer at the G for example:</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/google-zoom.png" width="375" height="210" title="Zoomed in on Google's G" ></p>

<p>There&#8217;s actually 255 different colors (an occult number for computer
scientists). If we take the top four, we get:</p>

<div class="swatch">
  <div class="color" style="background: #01a514">#01a514</div>
  <div class="color" style="background: #0048f1">#0048f1</div>
  <div class="color" style="background: #1d4cee">#1d4cee</div>
  <div class="color" style="background: #ea2434">#ea2434</div>
</div>


<p>Aww, not that great. It has two very similar blues, and misses the yellow
entirely.</p>

<p>The problem is that colors that are not <em>exactly</em> the same are treated
differently to a computer. All the different shades and
variants of colors mess up the counts. Humans easily group sets of colors together
though, and ideally our program would do the same.</p>

<p>So how can we judge if two colors look the same to the human eye or not?
Fortunately, a bit of color theory comes in handy here.</p>

<h3>Aside: Color theory</h3>

<p>On a computer, colors are usually represented in the RGB color space. This
means that a color is made up of three components: Red, Green and Blue. To work
out the distance between two colors you can use the Euclidian distance of the
components.</p>

<p>Comparing colors in the RGB color space works ok, but it&#8217;s not
perfect. Differences in RGB don&#8217;t accurately match how the human eye perceives
color. For example, yellow often appears brighter to humans than a blue of the
same brightness. Also, humans can perceive smaller differences in green hues
than in pink.</p>

<p>A better way to compare colors is to convert to the Lab color space. Lab is
designed to allow comparison in a way that matches how the human eye perceives
color. A color in the Lab color space has three components: &#8220;L&#8221; represents lightness,
the &#8220;a&#8221; component ranges from green to magenta, the &#8220;b&#8221; component ranges from
blue to yellow. The distance between colors in the Lab color space is often
called the delta-E. A delta-E of less than 1.0 means that the human eye
cannot tell the difference between two colors.</p>

<p>We can take advantage of this to group similar colors together in a way that matches how the eye would do it naturally.</p>

<h3>Merging colors together</h3>

<p>By combining visually similar colors, we&#8217;re able to address most of
the earlier problems. The color theory above tells us which colors to merge:
pairs with a low delta-E are visually similar, and can be safely combined.
On our noisy image, this leads to a clearer list of colors:</p>

<div class="swatch">
  <div class="color" style="background: #0048f1">#0048f1</div>
  <div class="color" style="background: #ea2434">#ea2434</div>
  <div class="color" style="background: #f8a912">#f8a912</div>
  <div class="color" style="background: #01a514">#01a514</div>
</div>


<p>Much better!</p>

<p>As it turns out, there&#8217;s a whole lot of situations in which extra colors get
added: antialiasing on edges of shapes, image compression artifacts, textures
and gradients all add to the number of different colors that occur, even
if they don&#8217;t change the overall palette. This technique helps to deal with
these issues. It can leave behind very low counts of some noisy colors
&#8211; an additional threshold filter helps to clean up colors that don&#8217;t
occur very often.</p>

<h2>Problem 3: &#8220;interesting&#8221; colors</h2>

<p>Now we can work out what colors are used in a design, but it turns out that a
lot of the colors we find aren&#8217;t that visually interesting.</p>

<p>Which colors are the most interesting here?</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/colorific/13914441-largecrop.png" width="500" height="370"></p>

<p>When we ask people, they usually pick the brighter and more distinctive colors.
But the palette this image uses is much more like this:</p>

<div class="swatch">
  <div class="color" style="background: #d0d0d0">#d0d0d0</div>
  <div class="color" style="background: #000000">#000000</div>
  <div class="color" style="background: #a0a0a0">#a0a0a0</div>
  <div class="color" style="background: #323232">#323232</div>
</div>


<p>In fact, it seems like grays and subdued shades are often used used as fillers
to give highlights more impact. How could we isolate these distinctive colors?</p>

<p><em>Excellent question! Lab coats on!</em></p>

<p>After flicking through designs until our retinas got tired, we turned to color
theory again. It turns out color theory has a name for the concept of color
interestingness: &#8220;saturation&#8221;.</p>

<p><strong>Cutting out colors with a low saturation gives you much more interesting
results.</strong></p>

<div class="swatch">
  <div class="color" style="background: #d40000">#d40000</div>
  <div class="color" style="background: #520000">#520000</div>
</div>


<p>We can now automatically work out the palette for an image that
closely matches what a human would pick.</p>

<h2>Introducing Colorific</h2>

<p>At 99designs we love open source &#8211; so we&#8217;re releasing Colorific, our automatic color palette detector. Check it out at <a href="https://github.com/99designs/colorific">github</a>.</p>

<p>Python users can install Colorific via the pip packaging system:</p>

<p><code>pip install colorific</code></p>

<p>Colorific has been tested on Python 2.7, but if you have any problems please <a href="https://github.com/99designs/colorific">submit an issue on github</a>.</p>

<h3>Usage</h3>

<p>Colorific is designed to run in a streaming manner. You feed in image filenames as input and colorific spits out the filename and the color palette as output.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ echo myimage.png | colorific
</span><span class='line'>myimage.png #3e453f,#2ea3b7,#bee6ea,#51544c,#373d38 #ffffff</span></code></pre></td></tr></table></div></figure>


<h2>What&#8217;s next?</h2>

<p>Tune in next time and we&#8217;ll tell you all about how we apply Colorific at a massive scale to analyse the huge number of incoming designs at 99designs.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Research and Development]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/03/16/research-and-development/"/>
    <updated>2012-03-16T14:00:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/03/16/research-and-development</id>
    <content type="html"><![CDATA[<p>by Michael De Wildt</p>

<p><em>The 99designs Research and Development programme enables members of our
development team to spend a full day every two weeks (what we Australians call
a “fortnight,” much to the amusement of our American colleagues) to work on
projects we think are important. Read on to find out why 99designs does this,
how it works in practical terms, and the successes and challenges we’ve
encountered.</em></p>

<h2>Why we do it</h2>

<p>Everyone has a proverbial “itch to scratch” and our R&amp;D programme allows
us to, well, scratch it. Companies allocating time for their best and
brightest to innovate is not a new school of thought. Many, technology based
and otherwise, have realised that the return on investment of allowing
employees to work autonomously on projects of their own choosing is
substantial.</p>

<p>99designs’ programme serves as an incubator for ideas, and it follows that one
tangible result is fantastic new products. Also, we learn new skills by
dabbling with brand new technologies and then applying the lessons learned in
our day-to-day tasks.  And then, of course, there is the more difficult to
measure result: greater staff satisfaction.</p>

<h2>We&#8217;re not alone</h2>

<p>A good example of a company that has been doing this for a very long time is
the one that brought us the little yellow notes you’ll likely see if you
glance around you right now, scribbled with clever quips or very insecure
password reminders and stuck to computer monitors. Bill Coyne, a former senior
vice president of R&amp;D at 3M, put forward one of the best arguments I’ve
encountered about why it’s key for the company’s engineers to spend 15 percent
of their time pursuing their own ideas:</p>

<blockquote><p>Most of the inventions that 3M depends upon today came out of that kind of
individual initiative… You don’t make a difference by just following orders.</p></blockquote>

<p>The 15 percent rule was instituted after an employee at the then-struggling
company went a bit rogue at work and invented the world’s first masking tape
back in 1925. Post-It notes hit the market in 1980. The company now employs
7,350 researchers and has sales of $27 billion a year.</p>

<p>In the technology sector, <a href="http://www.atlassian.com">Atlassian</a> and Google are
two well-known evangelists of R&amp;D time. <a href="http://www.google.com/jobs/lifeatgoogle/englife/index.html">Google&#8217;s “20 percent time”</a> paved the
way for key products such as Gmail, Chrome and Google News. Atlassian credits
its own 20-percent programme with helping to keep its developers so happy that
it doesn’t need to pour a lot of money into recruiting new talent. Prospects
simply hear about its innovative culture and climb over one another to join
them.</p>

<h2>How we do it</h2>

<p>99designs’ R&amp;D days are scheduled at the end of our fortnightly
development sprints, so that we have one every second Friday. The day gives us
a nice buffer in which to get creative after our projects and other business
tasks are wrapped up Thursday and before a new sprint starts Monday.</p>

<p>We like to hold an informal meeting the day before our R&amp;D day to share
ideas about what we’d like to tackle. Not everyone has a killer idea every
time, and it’s not uncommon for a colleague to describe a project that sounds
a lot cooler then what you had in mind. The get-together allows teams to self
organise and game plans to develop. Another benefit of holding a prep meeting
is that it gets us all amped up to hack on whatever we want all day the
following day.</p>

<p>The Monday after an R&amp;D day, each team or individual gives a five-minute
presentation on what they achieved, what they learned and whether it’s
something they want to pursue further.</p>

<h2>Successes so far</h2>

<p>The 99designs R&amp;D program was implemented six months ago and in those 10
or so days we’ve managed to come up with some useful tools and fun apps.</p>

<p>One of our very first projects to be adopted as a mainstream product feature
was an admin toolbar. This project came from a few developers who were
frustrated with how difficult it was to search for and manage contests, so
during our very first R&amp;D day we decided to form a team and build
a solution. To the delight of our staff, the toolbar is now part of the
application and used on a daily basis.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/mapviz.png" width="505" height="318" title="Mapviz in action" ></p>

<div align="center"><p><em>Mapviz pans across the world, showing logins and
design entries</em></p></div>


<p>Another frustration among developers was the lack of visibility and subsequent
difficulty managing errors within our application. Yes, we have error logs.
But who in their right mind likes trawling through them to get to the bottom
of an issue? “Triage” is the aptly named error management system we developed
over eight R&amp;D days. This open source, ongoing project will soon be rolled
out into our application and will make our lives a lot easier.</p>

<p>On the fun side, one of our developers created a nice little app called
Mapviz, which provides a real-time visualisation of all customer log-ins,
contest launches and design entries on a world map. Our marketing team was
blown away by it.</p>

<h2>Challenges</h2>

<p>One challenge we face is coming up with a way to involve all of our teams,
including support and marketing, in the R&amp;D programme. Involving
non-technical team members from time to time could allow the development team
to get inspiration and ideas from a different angle. Then there’s the
challenge that comes with being a global company – the Pacific Ocean creates
quite a barrier between our Melbourne and San Francisco offices, making it
tough for us to consistently communicate ideas efficiently and effectively.</p>

<p>Secondly, is an R&amp;D day twice a month the best approach for fostering
innovation? Our friends at <a href="http://www.flippa.com/">Flippa</a> have taken on what
they like to call &#8220;Triple Time,” in which the development team dedicates three
consecutive days every month to R&amp;D. This approach might work well for us,
however, giving it a go will be a challenge when we are so used to our current
programme.</p>

<p>Another interesting approach is the “<a href="http://confluence.atlassian.com/display/DEV/FedEx+Day+FAQ">FedEx day</a>” championed by
Atlassian, during which a team is given one day to build and demonstrate
a finished or near-complete product. Could introducing a deliver-in-a-day
element hinder or supplement our current programme?</p>

<h2>Looking ahead</h2>

<p>The evidence is clear that we’re off to a good start – we’re delivering some
great products, helping to foster an innovative company culture and learning
new technical skills. However, like everything at 99designs, the programme is
continually evolving and improving.</p>

<p>I’m curious to learn more about what other companies are doing to foster
innovation. Does your company have an R&amp;D program? How is it structured
– as a percentage of time, designated days, another format?  How else are
employees encouraged to innovate?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Feature flipping]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/03/01/feature-flipping/"/>
    <updated>2012-03-01T17:56:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/03/01/feature-flipping</id>
    <content type="html"><![CDATA[<p>by Chris Campbell</p>

<p><em>This post describes feature flipping, an approach to development that helps
solve some of the issues associated with risk management and quality assurance
when a fast moving development team expands.</em></p>

<h2>Continuous deployment in large teams</h2>

<p>Developers at 99designs use agile and lean startup methodologies, but as our
development team gets bigger, deployments happen more frequently. This volume
of change brings increased risk for the stability of our site. It can also be
quite a challenge to measure the success of a single new feature on a rapidly
changing website with multiple new features operating at any given time. In
our earlier days we’d demo new features on a staging server, but as 99designs
has grown, using several staging servers to demo all our new features at once
has become clunky. So how do we solve these issues? Feature flipping.</p>

<h2>What is feature flipping?</h2>

<p>Feature flipping enables the ability to turn site features on or off on
a per-user basis. You&#8217;ve probably encountered it before with companies like
Google or Facebook when they&#8217;re rolling out major changes. A few examples
include the recent UI changes to Google Docs and Google Mail, and Facebook&#8217;s
new Timeline. Our approach was inspired by our friends at
<a href="http://www.youtube.com/watch?v=QhI42ziaTwI&amp;feature=youtu.be">Learnable</a>, and
slots in well with the <a href="http://theleanstartup.com/">Lean Startup</a> methodology
of releasing minimum viable products, measuring, and adapting through fast
feedback.</p>

<p>Rolling out features incrementally gives companies the ability to ensure the
appropriateness and stability of a feature. Some companies make this visible
to users via an opt in/out approach, but in our case we use this internally as
an improved form of A/B testing. Traditionally we would only A/B test on
landing pages and static content, but feature flipping also allows us to
experiment with pervasive site functionality.</p>

<h2>How it works at 99</h2>

<p>Before running through our approach, let&#8217;s first examine it from a developers
perspective and from a site admin&#8217;s perspective.</p>

<h4>Developers</h4>

<p>As a developer, you create a new feature simply by registering it in
a specific module in our codebase.</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='python'><span class='line'><span class="n">features</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&#39;raptors&#39;</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s">&#39;Unleashes raptors over the site&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now that we&#8217;ve defined our feature, it&#8217;s available for use in a conditional
statement, which you use to guard feature-specific code.</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>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">if</span> <span class="n">feature</span><span class="p">(</span><span class="s">&#39;raptors&#39;</span><span class="p">):</span>
</span><span class='line'>    <span class="n">unleash_raptors</span><span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>


<p>Boom! Our <em>raptors</em> feature can now be toggled on or off for any user who
interacts with our site.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/raptors.jpg" width="466" height="294" title="Example of feature enabled" ></p>

<div align="center"><p><em>Do you like raptors? We like raptors!</em></p></div>


<p>To kick off an incremental roll out, a commit is required with a defined set
of eligibility criteria a user must meet before the feature is enabled for
them. For example, the user must be a designer and needs to have submitted
a minimum of 5 entries.</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='python'><span class='line'><span class="n">feature</span><span class="p">(</span><span class="s">&#39;raptors&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">rollout</span><span class="p">(</span><span class="n">role</span><span class="o">=</span><span class="s">&#39;designer&#39;</span><span class="p">,</span> <span class="n">min_entries</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Of course, we make sure to test the new behaviour in addition to the old.</p>

<h4>Admin</h4>

<p>99designs staff get a nice interface where they can turn on and off features
for themselves or a specific user. Here they can also view the progress of any
experiments hanging off this feature. Many of our stakeholders are located
remotely; by giving them the power to enable features themselves, they can try
these out in production and provide feedback. This removes the need for
a dedicated staging environment for demoing.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/raptors-feature.jpg" width="700" height="53" title="Example of feature interface" ></p>

<div align="center"><p><em>Enabling or disabling a feature is just a button
click</em></p></div>


<h4>Under the hood</h4>

<p>When we first considered how best to implement features, we recognized that
every feature we introduced would require us to perform an additional
user-feature check. This would clearly result in rapid growth of queries as we
began checking features for every user on every page of our site.</p>

<p>For logged out users, we decide to to go with a cookie based solution.
However, for logged-in users we wanted our user features to be persistent. We
thought about using MySQL, but based on Redis
<a href="http://code.google.com/p/redis/wiki/Benchmarks">benchmarks</a> and its inbuilt
<em>sets</em> data structure, going this route seemed an ideal solution. We decided
to go with a combined cookie and Redis approach to minimise the number of
database lookups without impacting the performance of our site.</p>

<p>These two methods work well together. When a user logs into 99designs, cookie
based features are synched up with Redis by taking a simple union of features
enabled and persisting the resulting set. This allows us to determine exactly
who has what features as well as when a user obtained those features.</p>

<h2>Challenges</h2>

<p>Developing with a multi-version mindset is probably one of the most
challenging parts of feature flipping. What was once a simple deployment
requiring a migration now entails more thought to allow the old and new
versions to function independently of one other.</p>

<p>Deprecated code can start to accumulate when you start leaving code wrapped in
feature checks. We try to curtail this as much as possible by coming back to
clean up unused code paths once a feature has been fully rolled out. Also, we
generally have a grace period even for features we&#8217;re decided on, so that we
can roll back if the need arises.</p>

<p>Unit and integration tests become more difficult when you’re working with an
exponential number of feature combinations at any given time. This can lead to
an outsized volume of test cases, a problem we&#8217;re still solving.</p>

<h2>What now?</h2>

<p>Feature flipping is our approach to solving several problems we face as
99designs expands. Managing features gives us fine-grained control over
exactly what our users see, and is paving the way for us to experiment and
adapt to our users much faster than was previously possible.</p>

<p>Big companies often execute this approach to development seamlessly, while
there’s more of a learning curve for small to mid-sized companies. In our
case, we’re still learning but we&#8217;re far enough along to be reaping the
benefits.</p>

<p>Where to go from here? We suggest you explore a few open source solutions that
deal with features:</p>

<ul>
<li><a href="https://github.com/pda/flip">flip</a> - Declare and manage features.</li>
<li><a href="https://github.com/jamesgolick/rollout">rollout</a> - Conditionally roll out features with redis.</li>
<li><a href="https://github.com/jamesgolick/degrade">degrade</a> - Keeps track of features, degrades functionality if errors are too high.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Asynchronous task queues]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/02/17/async-task-queues/"/>
    <updated>2012-02-17T15:18:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/02/17/async-task-queues</id>
    <content type="html"><![CDATA[<p>by Richard Bone</p>

<p><em>Although our user facing site is the most visible part of what we do, it&#8217;s
only half the story. The other half takes part in asychronous queues, which
work overtime behind the scenes, and process hundreds of millions of tasks
each year. In this post I&#8217;ll explain a bit about why we use queueing at
99designs, and how it all works.</em></p>

<h2>A Bit of Background</h2>

<p>If you&#8217;ve never heard of asynchronous task queues before, the idea behind them
is pretty simple. Say you had a task you needed to do such as buying some
milk but you didn&#8217;t have the time to take care of it yourself, so instead you
leave a note for a friend/spouse/roommate asking them to do it for you when
they have a chance. Congratulations, you&#8217;ve just implemented an asynchronous
task queue.</p>

<h2>Why We Use Queues</h2>

<p>Now obviously our web apps aren&#8217;t busy ordering milk, more common uses for
a queue are things like talking to third party API&#8217;s, sending emails, or
performing computationally expensive tasks like image resizing. But why do we
need a queue at all? Wouldn&#8217;t it be easier to just do the work a user
requires immediately? Well, there&#8217;s a few reasons:</p>

<p>The first reason is speed: When we&#8217;re talking to a third party API we have to
face reality; unless that third party is physically located next to our
infrastructure, there&#8217;s going to be latency involved. All it would take is
the addition of a few API calls and we could easily end up doubling or
tripling our response time, leading to a sluggish site and unhappy users.
However if we push these API calls into our queue instead, we can return
a response to our users immediately while our queues take as long as they like
to talk to the API.</p>

<p>The second reason is reliability: We don&#8217;t live in a world of 100% uptime,
services do go down, and when they do it&#8217;s important that our users aren&#8217;t the
ones that suffer. If we were to make our API calls directly in the users
requests we wouldn&#8217;t have any good options in the event of a failure. We could
retry the call right away in the hope that it was just a momentary glitch, but
more than likely we&#8217;ll either have to show the user an error, or silently
discard whatever we were trying to do. Queues neatly get around this problem
since they can happily continue retrying over and over in the background, and
all the while our users never need to know anything is wrong.</p>

<p>The final reason to use a queue is for scalability. If we had a surge in
requests that involved something CPU intensive like resizing images, we might
have a problem if all of our apps were responsible for this. Not only would
the increased CPU load slow down other image resize requests, it could very
well slow down requests across the entire site. What we need to do is isolate
this workload from the user&#8217;s experience, so that it doesn&#8217;t matter if it
happens quickly or slowly. This is where queues shine. Even if our queues
become overloaded, the rest of the site will remain responsive.</p>

<h2>How We Implement It At 99designs</h2>

<p>Understanding why we use queues is one thing, actually implementing it is
quite another. In the case of 99designs we chose <a href="http://kr.github.com/beanstalkd/">beanstalk</a> as our queue, it&#8217;s
key features being performance, reliability and simplicity.  Rather than
having just one centralized queue which our servers push tasks to, we instead
have a separate queue on every app server. Queuing a task locally is always
going to be very quick, and having multiple queues gives us a healthy dose of
redundancy in the event of a beanstalk failure &#8212; something I&#8217;ve yet to
see.</p>

<p>Of course on its own a queue doesn&#8217;t do anything; simply pushing tasks onto it
doesn&#8217;t magically make them happen. For that you need a worker. Since a lot of
what 99designs does is PHP-based we had to develop our own custom worker
daemon, as there weren&#8217;t any open source solutions for beanstalk. Each worker
node maintains a pool of worker processes to connect to each queue and listen
for new tasks. In the event that our queues start to back up, we can easily
launch a new worker instance thanks to AWS and have it processing tasks within
minutes.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/queues-in-action.png" width="466" height="392" title="Our one-queue-per-app model" ></p>

<div align="center"><p><em>Our one-queue-per-app model</em></p></div>


<p>The final part that ties all of it together is how we deal with failures. In
the event that a task fails it doesn&#8217;t simply disappear into the ether.
Instead we&#8217;ll release the task with a delay, essentially putting it back onto
the queue after a certain amount of time has passed. If a task continues to
fail we use an exponential backoff strategy to prevent failing tasks from
clogging up our queues. If after multiple releases the task still has not
finished successfully then we &#8220;bury&#8221; it. Buried tasks are then manually
inspected at a later date, and a decision is made to either fix the problem
(if possible), or delete the task if it is deemed unrecoverable.</p>

<h2>Work in progress</h2>

<p>There&#8217;s still more that we&#8217;d like to do with our queueing systems. If too many
tasks fail, and are buried, we get alerts which wake us in the night.
Sometimes, this happens because an external service we use goes down,
something we can&#8217;t do much about anyway. Unfortunately, our tasks don&#8217;t yet
coordinate their back off in any way; each assumes it&#8217;s the only one failing.
Ideally, we&#8217;d track failures against external APIs, and simply delay groups of
tasks for longer, giving third party services time to recover.</p>

<h2>In closing</h2>

<p>Asynchronous tasks are a crucial, and often overlooked, part of how any large
site operates. We hope this post gives some insight into why queues are
important, and how they can improve your site&#8217;s performance and reliability.
Whilst there are many different queuing architectures possible, we also hope
our recipe serves as a useful pattern for other sites.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Infrastructure at 99designs]]></title>
    <link href="http://99designs.com/tech-blog/blog/2012/01/30/infrastructure-at-99designs/"/>
    <updated>2012-01-30T22:17:00+11:00</updated>
    <id>http://99designs.com/tech-blog/blog/2012/01/30/infrastructure-at-99designs</id>
    <content type="html"><![CDATA[<p>by <a href="https://plus.google.com/u/0/109946864654892236078?rel=author">Lars Yencken</a></p>

<p><em>99designs hosts design contests, and has been growing rapidly year on
year. This post gives an overview of the infrastructure which powers our site,
how we make sure it continues to hum smoothly, and the challenges we face as
we scale.</em></p>

<h2>A little context</h2>

<p>Since its humble origins in ad-hoc contests within Sitepoint&#8217;s forums,
99designs has turned out to be one of the success stories of the Melbourne
start-up scene. Although we now have offices in both Melbourne and San
Francisco, the development team is in the Melbourne office, close to where the
action all began. Our team here has 8 devs, 2 dev ops, 2 ux/designers, and is
expanding. Half the people here arrived within the past year, myself included,
amounting to a lot of growth and change over a limited amount of time.</p>

<p>Our site sees hundreds of thousands of unique visitors a month, generating
pageviews in the tens of millions. Since we deal with graphic design, many of
our pages are asset heavy &#8212; these pageviews fan out to some 40 times as
many requests. Whilst there are many larger sites on the net, we thought this
was enough to warrant sharing the way we do things.</p>

<h2>Requests in layers</h2>

<p>The easiest way to describe how we serve requests is to talk about it in
layers, each of which solves a set of problems we face. We&#8217;ll cover six pieces
of this puzzle: <em>load balancing</em>, <em>acceleration</em>, <em>application</em>, <em>asynchronous
tasks</em>, <em>storage</em> and <em>transient data</em>.</p>

<h4>Load balancing</h4>

<p>Let&#8217;s start at the beginning of a request. When a user visits 99designs.com,
the request firstly hits our Elastic Load Balancer (ELB). The load balancer is
a highly reliable service which ensures that requests are spread evenly
between the Varnish servers beneath it. It also performs active health checks,
so that requests only hit healthy servers, and SSL unwrapping, allowing us to
work with an unencrypted stack from there on down. On the SSL front, using
a separate ELB for each domain turns out to be a convenient way of running
multiple secure domains.</p>

<h4>Acceleration</h4>

<p>Our acceleration layer consists of several
<a href="https://www.varnish-cache.org/">Varnish</a> servers, which allow us to serve
a large amount of media with only a limited app stack beneath them. We have
a long-tail of static media, so we run Varnish with a file-based rather than
in-memory storage backend. Varnish is fast, and incredibly configurable
through its inbuilt DSL. Furthermore, its command-line tools for inspecting
live traffic are second to none, and are incredibly useful in tracking down
odd site behaviour.</p>

<h4>Application</h4>

<p>Dynamic or otherwise uncached requests are served from our PHP application
layer, using Apache/mod_php. Our polyglot team takes inspiration from some of
the best frameworks in the Ruby, Python and Javascript worlds, and we&#8217;re not
above porting over what we need. We also open source what we can, for example
our lightweight web application framework
<a href="http://github.com/99designs/ergo">Ergo</a>. Designs which users submit aren&#8217;t
stored on every app server, but are instead stored in S3. Since end-user
latency is so poor for S3, we serve designs through our app layer, and cache
them locally after each request.</p>

<p><img class="center" src="http://99designs.com/tech-blog/images/architecture-v2.png" width="504" height="438" title="Our multi-layer stack" ></p>

<div align="center"><p><em>The high-level components of our stack</em></p></div>


<h4>Asynchronous tasks</h4>

<p>We strive to have a responsive site where users aren&#8217;t kept waiting, but often
requests might need to do some extended work, or access an external API.
Integrated with our application layer is an asyncronous layer which tackles
this problem. We queue up tasks using
<a href="http://kr.github.com/beanstalkd/">Beanstalk</a> in-memory task queues on each of
our app servers, using the <a href="https://github.com/pda/pheanstalk">Pheanstalk</a>
bindings. Beanstalk is known to be <a href="http://adam.heroku.com/past/2010/4/24/beanstalk_a_simple_and_fast_queueing_backend/">lightweight and performant</a>,
with the trade-off that we lose some visibility into the immediate contents of
our queues. A pool of PHP workers listens to these queues, and takes care of
anything lengthy or requiring access to an external API. Tasks which need to
run at a particular time are stored instead in the database, and added to the
queues by cron when they fall due.</p>

<h4>Storage</h4>

<p>Our storage layer features Amazon&#8217;s managed MySQL service (RDS) as the
primary, authoritative and persistent store for our crucial data. An RDS
instance configured to use multiple availability zones provides master-master
replication, providing crucial redundancy for our DB layer. This feature has
already saved our bacon multiple times: the fail over has been smooth enough
that by the time we realised anything was wrong, another master was correctly
serving requests. Its rolling backups provide a means of disaster recovery.
We load-balance reads across multiple slaves as a means of maintaining
performance as the load on our database increases. For media files and data
blobs, we use S3 for redundant and highly-available storage, with periodic
backups to Rackspace Cloudfiles for disaster recovery.</p>

<h4>Transient data</h4>

<p>Aside from our database proper, there are three services which we use
primarily for transient data: Memcached, MongoDB and Redis. Memcached runs
locally on every application server, with a peering arragement between
servers, and helps us reduce our database queries dramatically. We log errors
and statistics to capped collections in MongoDB, providing us with more
insight into our system&#8217;s performance. Redis captures per-user information
about which features are enabled at any given time; it supports our
development stragegy around dark launches, soft launches and incremental
feature rollouts.</p>

<h2>Software as infrastructure</h2>

<p>99designs strongly follows the “software as infrastructure” mantra. Like many
companies now, we don&#8217;t own any hardware ourselves, preferring to remain
flexible, and relying heavily on Amazon&#8217;s cloud offering. Growing as we have
has meant a lot of change in a limited period of time, and has built into our
culture a distrust for documentation and the dual-maintenance problem it
creates. Instead, we focus on automation of as much as possible.</p>

<p>We currently use Rightscale to manage our server configurations, which
basically amounts to using a managed form of Chef for provisioning new
servers. We make sure each server type has a recipe which allows us to spin up
replacements at a moment&#8217;s notice. This means we can treat servers as
disposable, and mean it.</p>

<p>The layers and services which make up our infrastructure amount to a fair
number of moving parts, so monitoring and keeping track of the distributed
application state is important. We do that through a number of services,
incuding a large number custom monitoring pages, NewRelic, CloudWatch, Statsd
and others. Two large monitoring screens feature prominently in our office,
making sure we&#8217;re aware of changes to the site. Despite all this information,
we&#8217;re continuously working to get a better understanding around site behaviour
and performance.</p>

<h2>Challenges</h2>

<p>Whilst the team here has some pride in our accomplishments, there&#8217;s a lot we
still have to work on. Here&#8217;s some of our biggest challenges:</p>

<ol>
<li><p><em>Scaling back infrastructure, rather than just scaling out.</em> As our site
changes and our customer base grows, the load we place on our backend
systems can vary dramatically. One way to deal with this is to over-provision,
so as to meet such spikes without issue. A challenge for us is to automate and
stress-test even more of our infrastructure, so that we can bring up new
servers even faster and more reliably. This would allow us to confidently
reduce capacity when we have excess, rather than simply expanding.</p></li>
<li><p><em>Providing a strong experience for international customers.</em> We have
a diverse and international customer-base, yet all the action is currently
served out of Amazon&#8217;s US-East data center. This leads to quite a disparity in
customer experience. We&#8217;re currently trialling CDNs in order to get static
media to our international customers faster, and likewise looking at other
ways we can improve performance.</p></li>
<li><p><em>Balancing feature growth with stability.</em> Being responsive to our
customers means being able to push out new features quickly. In some
companies, this causes a tension between developers who need to get code out,
and ops who are woken in the night by the consequences of a hasty change.
We&#8217;re attacking this problem from multiple angles: stronger acceptance testing
should give us better sanity checks on new code that goes out; feature
flipping allows us to incrementally role out new features to only a subset of
users; and finally, we&#8217;re working on further automation in order to allow our
developers to be more active in our infrastructure, meaning they can really
own a change from the moment it&#8217;s coded to the moment users see it in
production.</p></li>
</ol>


<h2>Watch this space</h2>

<p>This post has given an overview of our current stack, and some of the broad
challenges we face, but we&#8217;ve got a lot more to say about our development
style, and the things which make our culture. We&#8217;ve benefited greatly from the
open source community and the expertise of those who share their experiences.
Now that we&#8217;ve grown, we&#8217;re keen to give back a little too, in the hope that
others can benefit from what we&#8217;ve learned.</p>
]]></content>
  </entry>
  
</feed>
