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

 <title>Avand.</title>
 <link href="http://avandamiri.com/atom.xml" rel="self"/>
 <link href="http://avandamiri.com/"/>
 <updated>2024-11-01T06:56:42+00:00</updated>
 <id>http://avandamiri.com/</id>
 <author>
   <name>Avand Amiri</name>
   <email>avand@avandamiri.com</email>
 </author>

 
 <entry>
   <title>Write Less JavaScript</title>
   <link href="http://avandamiri.com/2014/12/15/write-less-javascript.html"/>
   <updated>2014-12-15T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2014/12/15/write-less-javascript</id>
   <content type="html">&lt;p&gt;How many lines of JavaScript code were used to create the following interface?&lt;/p&gt;

&lt;iframe src=&quot;//player.vimeo.com/video/114599646&quot; width=&quot;650&quot; height=&quot;420&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;At &lt;a href=&quot;http://mysteryscience.com&quot;&gt;Mystery Science&lt;/a&gt;, we recently released this feature to capture feedback after a teacher has taught a lesson. There are four possible screens or states:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Prompt (did you teach?)&lt;/li&gt;
  &lt;li&gt;Rating (stars)&lt;/li&gt;
  &lt;li&gt;Comments (open-ended feedback)&lt;/li&gt;
  &lt;li&gt;Done&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each state (except the last one) prompts and subsequently saves user input. The server knows I taught a lesson as soon as I click “yes.” The star rating and comments work the same way — all responses are submitted via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest&quot;&gt;XHR&lt;/a&gt;. &lt;strong&gt;How little JS code can we write to get this feature working?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first trick to writing less JS is to find the right abstractions.&lt;/strong&gt; Let’s explore the two key abstractions here. When a teacher submits a response, JS is advancing the interface’s state. This can be accomplished in any number of ways but at the end of the day some elements are being shown (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display: inherit&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#inherit&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;) and others are being hidden (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display: none&lt;/code&gt;). JS also has to send the response to the server, which in jQuery-terms eventually means a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$.ajax()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s wire this up:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Let&apos;s assume this feature lives inside &amp;lt;div class=&quot;lesson-feedback&quot;&amp;gt;.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.lesson-feedback&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// First, let&apos;s wire up the UI:&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.yes-control&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enterRatingState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.rating-control&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enterCommentsState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.no-control, .submit-comments-control, .skip-comments-control&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enterDoneState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Now, let&apos;s wire up the response submissions:&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;submitViaXHR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is a great start! This code is readable and there’s not much of it. But we’ve introduced some event handlers like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enterRatingState()&lt;/code&gt; that are not defined. Presumably, these functions will reach into the container and show and hide their respective elements. But given that each state has many elements, how can we do this without introducing a bunch of JS? Let’s introduce some CSS to do the heavy-lifting. &lt;strong&gt;This is the second trick to writing less JS: defer view logic to CSS whenever possible.&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.rating&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.visible-during-rating&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inherit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.prompt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.comments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.lesson-feedback.state-rating&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.hidden-during-rating&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s unpack this. Obviously, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.lesson-feedback&lt;/code&gt; is the container. We’ll modify the container with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.state-*&lt;/code&gt; classes to enter and exit the four states. This means there will also be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.state-prompt&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.state-comments&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.state-done&lt;/code&gt;. Each state needs blocks like the ones above. I’ve also included &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.visible-during-*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.hidden-during-*&lt;/code&gt; helper classes to control elements that span states (like the header and image). It may seem like a lot of CSS but once it’s there you shouldn’t need to change it unless you add or remove a state. Some of the repetition can also be reduced with a preprocessor like &lt;a href=&quot;http://lesscss.org&quot;&gt;LESS&lt;/a&gt; or &lt;a href=&quot;http://sass-lang.comx`&quot;&gt;SASS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enterRatingState()&lt;/code&gt; and the other state-related functions are really lightweight:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// You&apos;ll need a function like this for each state:&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enterRatingState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;enterState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rating&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enterState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;state-prompt state-rating state-comments state-done&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;state-&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s all we need to drive the interface; looking good! Now, let’s look at data submission. In the first code example, I introduced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submitViaXHR()&lt;/code&gt;. Let’s define that now.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;submitViaXHR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Remember, all the forms have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submitViaXHR()&lt;/code&gt; bound as an event handler on submit. Instead of submitting to the server with a traditional page refresh, jQuery steps in and submits the data via XHR instead — this is nothing new. The real elegance here is that they all submit the same way. There are not three different handlers for the prompt, rating, and comments forms. &lt;strong&gt;The third trick to writing less JS is to keep data in HTML.&lt;/strong&gt; Here’s an example of the HTML for the first state, prompt:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lesson-feedback state-prompt&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prompt&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;answer&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/viewings&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PUT&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;display: inline;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hidden&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewing[actually_taught]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Yes&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;yes-control button button-green&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/viewings&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PUT&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;display: inline;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hidden&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewing[actually_taught]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;No&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;no-control button button-red&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- And so on for the other states... --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are two really lightweight forms with hidden values that submit to the server. That’s all we need. The destination of the request (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/viewings&lt;/code&gt;), the HTTP verb (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt;), and the request data (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ viewing: { actually_taught: true} }&lt;/code&gt;) are all stored in the markup and that’s a good thing.&lt;/p&gt;

&lt;p&gt;So let’s recap. To write less JavaScript:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Find the right abstractions.&lt;/li&gt;
  &lt;li&gt;Defer view logic to CSS whenever possible.&lt;/li&gt;
  &lt;li&gt;Keep data in the HTML.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;p id=&quot;inherit&quot;&gt;1: &lt;code&gt;inherit&lt;/code&gt; is a better choice than &lt;code&gt;block&lt;/code&gt; for visible elements. This approach will allow inline elements to preserve their inline display type.&lt;/p&gt;
&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Calculated Attribute Pattern for Ruby Models</title>
   <link href="http://avandamiri.com/2014/11/26/calculated-attribute-pattern-for-ruby-models.html"/>
   <updated>2014-11-26T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2014/11/26/calculated-attribute-pattern-for-ruby-models</id>
   <content type="html">&lt;p&gt;Sometimes in a Rails application a model has attributes whose values need to be computed. For example, at &lt;a href=&quot;http://mysteryscience.com&quot;&gt;Mystery Science&lt;/a&gt;, we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Viewing&lt;/code&gt; model that is created when a lesson has been viewed. This model is associated with actions that a teacher took with a lesson (e.g., playing a video, entering full screen mode, etc.). If we want to know how much time the teacher spent watching the videos, we need to calculate the value:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Viewing&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds_spent_watching_videos&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@seconds_spent_watching_videos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;videos_played&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;duration&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It’s advisable to at least &lt;a href=&quot;http://www.justinweiss.com/blog/2014/07/28/4-simple-memoization-patterns-in-ruby-and-one-gem/&quot;&gt;memoize&lt;/a&gt; this attribute so it doesn’t have to be recalculated more than once for the same instance. But, when dealing with a collection of viewings, the calculation has to be performed on each one. That means querying is very expensive and can’t be done in SQL. Let’s store the value in the table instead:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AddSecondsSpentWatchingVideosToViewings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Migration&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;add_column&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:viewings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:seconds_spent_watching_videos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:float&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, you need a method to update that value. You might be inclined to write a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculate_seconds_spent_watching_videos&lt;/code&gt; method that you call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_validation&lt;/code&gt;. That approach works just fine but it clutters up your model; consider that there may be more other attributes like this one. Here’s a pattern that I’ve used that works really well in these cases:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Viewing&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds_spent_watching_videos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:reload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@seconds_spent_watching_videos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;videos_played&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;duration&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;read_attribute&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:seconds_spent_watching_videos&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here, I’m overwritting the attribute’s accessor method to take options. If you call it normally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;viewing.seconds_spent_watching_videos&lt;/code&gt;, you’ll get the value from the database. But if you call it with the reload option, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;viewing.seconds_spent_watching_videos(reload: true)&lt;/code&gt;, you’ll get the calculated value. You still need to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_attribute&lt;/code&gt; at some point — a callback may still be the right place for that — but I’m of the opinion that your “getter” shouldn’t double as a “setter.”&lt;/p&gt;

&lt;p&gt;I’ve used this pattern throughout my Rails applications and it’s been really useful. Hopefully, it’s useful for you as well.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>CSS Spinners</title>
   <link href="http://avandamiri.com/2014/08/21/spinners.html"/>
   <updated>2014-08-21T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2014/08/21/spinners</id>
   <content type="html">&lt;p&gt;Spinners are really easy to implement with animated GIFs. However, they don’t look great when overlayed on top of another image because GIFs only support &lt;a href=&quot;http://www.idux.com/2011/02/27/what-are-index-and-alpha-transparency/&quot;&gt;index transparency&lt;/a&gt;. If they’re on a solid background, you can match colors and they’ll look fine. Services like &lt;a href=&quot;http://ajaxload.info&quot;&gt;ajaxload.info&lt;/a&gt; make it easy to generate the appropriate image.&lt;/p&gt;

&lt;p&gt;To implement a spinner as an overlay requires another approach. &lt;a href=&quot;http://spiffygif.com&quot;&gt;SpiffyGif&lt;/a&gt; turned me onto the idea of using a &lt;a href=&quot;http://codepen.io/sdholbs/pen/GyEDw&quot;&gt;translucent PNG sprite spinner&lt;/a&gt;. This technique involves a PNG sprite with every frame drawn out. Some JavaScript code updates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;background-position&lt;/code&gt; of the sprite on an interval, which makes it appear to be spinning. Here’s the example they provide:&lt;/p&gt;

&lt;p data-height=&quot;268&quot; data-theme-id=&quot;0&quot; data-slug-hash=&quot;dxDmo&quot; data-default-tab=&quot;js&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/avand/pen/dxDmo/&quot;&gt;The Sprite Spinner&lt;/a&gt; by Avand (&lt;a href=&quot;http://codepen.io/avand&quot;&gt;@avand&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;
&lt;script async=&quot;&quot; src=&quot;//codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Initially, I was enamored with the idea but as I started to wire it up, I realized it was heavy-handed. There had to be a way to achieve the same affect without JS. I knew if I animated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform: rotate(360deg)&lt;/code&gt; declaration, I knew I could get the PNG to spin around but it looks awkward when the spokes of the graphic actually move. Then I remembered that the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/timing-function&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timing-function&lt;/code&gt;&lt;/a&gt; could be given as a number of steps (e.g, [&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;steps(n)&lt;/code&gt;]). Instead of drawing each frame of the animation, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;steps(n)&lt;/code&gt; breaks up the animation into n states. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;steps(2)&lt;/code&gt;, for example, would draw the animation when it’s 50% complete and then again at 100% ignoring the steps in between. If you set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; to match the number of spokes in your graphic, you’ll rotate the PNG in as many steps, just like a second hand might tick around a clock. Here’s a demo:&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;300&quot; src=&quot;http://jsfiddle.net/kpj68jox/4/embedded/result,html,css&quot; allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;You could take this idea further and actually generate the graphic with CSS too but personally I think the PNG works just fine.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Here and Now</title>
   <link href="http://avandamiri.com/2014/05/29/here-and-now.html"/>
   <updated>2014-05-29T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2014/05/29/here-and-now</id>
   <content type="html">&lt;p&gt;The here and the now are compelling destinations. People want to feel like they’re part of what’s happening now. They want to feel like now is happening where they are.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://stripe.com/checkout&quot;&gt;Stripe Checkout&lt;/a&gt; features &lt;a href=&quot;https://medium.com/ui-ux-articles/3d1b0a9b810e&quot;&gt;animations&lt;/a&gt; to communicate what the product is doing. They’re subtle but the product feels incomplete without them. These animations pull you into the present moment. You don’t have to wait for you text message to arrive, the product is waiting with you. It puts you here and now rather than disconnecting from you.&lt;/p&gt;

&lt;p&gt;Music is the sound of here and now. The harder you listen, the more there is to hear. Great artists don’t stop if they play the wrong note or sing the wrong word. They lead into the charge into the present moment. In turn, the audience idolizes the artist, putting them on a stage under all the lights. Sometimes it feels like you could follow them forever.&lt;/p&gt;

&lt;p&gt;Surfers ride on the crest of a wave, an incredibly fleeting moment where the past meets the future. Often it’s a perilous place. Disconnect for even a split second and you’re buried under a mountain of water. The practice of the present requires tremendous focus.&lt;/p&gt;

&lt;p&gt;We relax in places where here and now appear to slow down. By removing indicators that time is elapsing, it can feel like a moment lasts forever. On the beach, the sun appears to be hung high in the sky. The constant crash of the waves act like a metronome setting the pace. Even here, just an empty cocktail on the beach nudge our attention out of the now and onto what’s next.&lt;/p&gt;

&lt;p&gt;Of course, the ultimate irony is that the present tense is always available. Many people put it in front of them. Others claim it’s behind them. There’s always a here and now to tap into. In fact, that may be all there is.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Momentum</title>
   <link href="http://avandamiri.com/2013/11/20/momentum.html"/>
   <updated>2013-11-20T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2013/11/20/momentum</id>
   <content type="html">&lt;p&gt;Startups move fast. They’re young, loud, and disruptive—a room full of excited
twenty-somethings willing to burn the midnight oil to get a release out the door.
Startups are enticing playgrounds with more Apple hardware and beer on tap than
you can handle. When you’re tired, don’t go home. Stay. There’s still more work
to be done, the Backlog says so. The blind lead the blind in this “up and to the
left” landgrab.&lt;/p&gt;

&lt;p&gt;“Speed comes from precision,” says &lt;a href=&quot;https://twitter.com/RobRobbins&quot;&gt;Rob Robbins&lt;/a&gt;, an engineer at
&lt;a href=&quot;http://taskrabbit.com&quot;&gt;TaskRabbit&lt;/a&gt; and a seasoned musician. You don’t get fast by going faster,
you get fast through precise repetition. With each iteration, you discover, then
eliminate, imperfections that held you back. Though it’s said that “practice
makes perfect,” not all practice yields the same results.&lt;/p&gt;

&lt;p&gt;Psychologist &lt;a href=&quot;http://en.wikipedia.org/wiki/K._Anders_Ericsson&quot;&gt;K. Anders Ericsson&lt;/a&gt; has been a pioneer in the field of
&lt;a href=&quot;http://en.wikipedia.org/wiki/Practice_(learning_method)#Deliberate_practice&quot;&gt;“deliberate practice.”&lt;/a&gt; “The differences between expert performers
and normal adults reflect a life-long period of deliberate effort to improve
performance in a specific domain,” Ericsson says. Going through the motions is
not enough. In his book &lt;a href=&quot;http://amzn.to/1ivraIb&quot;&gt;The Talent Code&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/DanielCoyle&quot;&gt;Daniel Coyle&lt;/a&gt; says that
to practice well is to “look at the task as a whole…divide it into its smallest
possible chunks…[and then] play with time, slowing the action down, then
speeding it up.”&lt;/p&gt;

&lt;p&gt;When you practice something, you eliminate the frictions that impede you.
Practice is an accelerant. And the better you practice the more you accelerate.
Better practice can be achieved through “chunking,” like Coyle suggests. It can
also be improved simply through focus—obviously, you’ll practice better when
you’re not distracted.&lt;/p&gt;

&lt;p&gt;But deliberate practice isn’t the only way to improve. You can also just practice
more. I see this evidenced each week at &lt;a href=&quot;http://ga.co&quot;&gt;General Assembly&lt;/a&gt;, where I teach
&lt;a href=&quot;https://generalassemb.ly/education/front-end-web-development&quot;&gt;front-end web development&lt;/a&gt;. Some students stay moderately but consistently
focused for the duration of the 10-week course. And they match up with students
that practice more intensely but spend less time overall. The highest
performers practice both frequently and intensely. And perhaps unsurprisingly,
physical objects obey the same rules.&lt;/p&gt;

&lt;p&gt;To determine an object’s velocity, that is its speed in a given direction, we can
use the equation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v = u + at&lt;/code&gt;, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u&lt;/code&gt; is its initial velocity, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; is its
acceleration, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; is time. If you accelerate at 10 meters/second/second for
10 seconds, you’ll be moving at 100 meters/second. To double your speed, double
your acceleration, or double the time. But double both and velocity grows by a
factor of two.&lt;/p&gt;

&lt;p&gt;But velocity is only part of the equation. You can vigorously work on a triviality
for a lifetime only to be left with a triviality. To make a “dent in the universe”
(Steve Jobs) requires work of substance, matters of importance and mass. Impact
happens when velocity and substance meet.&lt;/p&gt;

&lt;p&gt;In physical terms, &lt;em&gt;impact is momentum&lt;/em&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Momentum&quot;&gt;“the product of the mass and velocity
of an object.”&lt;/a&gt; Momentum, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt;, is calculated by multiplying mass, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt;,
by velocity, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p = mv&lt;/code&gt;). A big idea with little action or execution doesn’t
have a significant impact. Similarly, considerable effort put towards a weak idea
also lacks impact. As &lt;a href=&quot;https://twitter.com/sivers&quot;&gt;Derek Sivers&lt;/a&gt; puts it, &lt;a href=&quot;http://sivers.org/multiply&quot;&gt;“ideas are just a
multiplier of execution.”&lt;/a&gt; And startups cluster at the fringes of this
spectrum, either working vigorously on trivial ideas or apathetically on big ones.&lt;/p&gt;

&lt;p&gt;It’s hard to make big things move fast—that’s just inertia. After 10 years of
classical piano, I’m able to play “Träumerei” or “Dreaming” by Robert Schumann.&lt;/p&gt;

&lt;p&gt;This one page of music represents years of practice. It’s not where I started.
Practice and time gave me velocity. And as my repertoire gained mass, I gained
momentum as a pianist.&lt;/p&gt;

&lt;p&gt;Now, I think to the future. Of course, I want my work to be meaningful. But dreaming
of the impact my work may have is just inspiration. Their impact will come from
years of practice. The things I work on today will collide into the things on
work on tomorrow, and one day, years from now, I’ll have the velocity and mass
to make a difference.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Canary</title>
   <link href="http://avandamiri.com/2013/08/01/canary.html"/>
   <updated>2013-08-01T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2013/08/01/canary</id>
   <content type="html">&lt;p&gt;The last product I built, &lt;a href=&quot;http://www.sqoot.com&quot;&gt;Sqoot&lt;/a&gt;, had a lot of moving parts. We
had three databases, a search server, an API, website, and a deal
importing system. It’s a marvel that it worked at all! The truth is
that it went down pretty frequently. Sadly, our customers were often
the first to find out even though we went to great lengths to
&lt;a href=&quot;/2011/04/28/building-an-app-to-monitor-your-app.html&quot;&gt;monitor our apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After Sqoot, I &lt;a href=&quot;http://techcrunch.com/2013/07/08/taskrabbit-confirms-layoffs-as-it-realigns-to-focus-on-mobile-and-enterprise/&quot;&gt;briefly&lt;/a&gt; worked at &lt;a href=&quot;http://www.taskrabbit.com&quot;&gt;TaskRabbit&lt;/a&gt;. Because we
had an operations team I didn’t have to think about whether or not
our code was running. But I did still have to worry about the code
itself: thousands of lines scattered across a bunch of apps. We
wrote lots of tests to prevent bugs. The slowest tests were our
integration tests. These tests actually boot up a server and clicked
around the site in a browser like a customer would. These tests were
so frustratingly slow that &lt;a href=&quot;https://twitter.com/RobRobbins&quot;&gt;Rob Robbins&lt;/a&gt; and I dreamt up
&lt;a href=&quot;https://github.com/robrobbins/specford&quot;&gt;Specford&lt;/a&gt;. And still anytime someone on my team wanted to push
a change, we’d wait 15-20 minutes for the tests to run. Our test
suite was the biggest adversary to our speed.&lt;/p&gt;

&lt;p&gt;Paradoxically, our code still broke in production. If you want to
know with 100% confidence that things are “up,” you just need to
check production. There are a few services that will do this kind of
monitoring for you but they’re either hard to use, expensive, or
both. I want a service that’s affordable and well designed. So I’m
building it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://canaryup.com&quot;&gt;Canary&lt;/a&gt; is an uptime monitoring service. Canary tells you when
things go wrong before anyone else does. Currently Canary will
monitor a URL and send an alert if the URL doesn’t respond or
responds unsuccessfully. There are no usage limits or tiered
subscriptions; $5/mo gets you everything.&lt;/p&gt;

&lt;p&gt;I’ve teamed up with my friend and previous co-founder,
&lt;a href=&quot;http://brandonweiss.me&quot;&gt;Brandon&lt;/a&gt;. We’ve built great things in the past and are really
excited to build out all the ideas we have for Canary.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://canaryup.com&quot;&gt;Try out Canary&lt;/a&gt; free for 14 days. I’d love hear your early
feedback.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Getting Close to Your Customers</title>
   <link href="http://avandamiri.com/2013/04/26/getting-close-to-your-customers.html"/>
   <updated>2013-04-26T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2013/04/26/getting-close-to-your-customers</id>
   <content type="html">&lt;iframe src=&quot;http://player.vimeo.com/video/64934455?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;700&quot; height=&quot;393&quot; frameborder=&quot;0&quot;&gt;
&lt;/iframe&gt;
</content>
 </entry>
 
 <entry>
   <title>Play Strength, a Rdio Feature Concept</title>
   <link href="http://avandamiri.com/2012/11/29/play-strength-a-rdio-feature-concept.html"/>
   <updated>2012-11-29T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2012/11/29/play-strength-a-rdio-feature-concept</id>
   <content type="html">&lt;p&gt;Music can make or break a party. And picking good music to play is hard. I think it should be easy.&lt;/p&gt;

&lt;p&gt;Here, I take a closer look at creating a great setlist with Rdio. I start with some back story about why I started thinking about this problem and why I think it’s important. Then I explore 10 potential design concepts, three of which have mockups. Finally, I’ll dive deep into one concept I’m calling Play Strength.&lt;/p&gt;

&lt;p&gt;Above all else, this is a design exercise to showcase how I think about problems and approach solving them. It should take about 10 minutes to read.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;back-story&quot;&gt;Back Story&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://rd.io/x/QD73K2EuYA&quot;&gt;Daft Punk Is Playing At My House&lt;/a&gt; was stuck in my head as soon as the bartender told me she had seen &lt;a href=&quot;http://rd.io/x/QD73LUI1MQ&quot;&gt;LCD Soundsystem&lt;/a&gt; at &lt;a href=&quot;http://www.orpheumtheatreboston.com&quot;&gt;The Orpheum&lt;/a&gt; in Boston. It must have woken the dormant DJ inside me because as soon as the party came home, it was queued up. And the jams didn’t stop there. Three hours of hitting Play Later left us with an &lt;a href=&quot;http://rd.io/x/QD73L1qYDg&quot;&gt;eclectic ambient mix&lt;/a&gt;. My favorites soon became my friends’ favorites, and the next day I used History to build a playlist, which I shared to our guests and on Facebook.&lt;/p&gt;

&lt;p&gt;Playing DJ for a night got me thinking. The mechanics of the Queue worked out fantastically. I would go searching for a few songs in Collection, rearrange the order, let the songs play out, and repeat. Rdio got out of my way and allowed me to focus on the music. But finding good music to play was still hard. I’d only find two or three new songs for every song that played. I was having a blast, so I wasn’t watching the clock, but I must have spent about a third of the night at my computer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there an easier way to build a great setlist?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;ten-different-perspectives&quot;&gt;Ten Different Perspectives&lt;/h2&gt;

&lt;p&gt;Apple follows a &lt;a href=&quot;http://buswk.co/ddUj6I&quot;&gt;10-3-1 design process&lt;/a&gt;, where designers rigorously explore three options from 10 concepts before settling on one strong decision. I fall in love easily, especially with my own ideas, so I force myself to follow this process.&lt;/p&gt;

&lt;p&gt;Here are 10 different ways to think about creating better setlists.&lt;/p&gt;

&lt;h3 id=&quot;1-radio-station&quot;&gt;1. Radio Station&lt;/h3&gt;

&lt;p&gt;Perhaps hand-selecting music is entirely unnecessary. I played music from Collection, so a station made up of that music is a great start. For more variety, the Heavy Rotation station would have introduced new music to the mix. But I was actually looking to keep to a theme. For example, &lt;a href=&quot;http://rd.io/x/QD73LUIQFg&quot;&gt;deadmau5&lt;/a&gt; is in my library but was a bad fit that night. With a radio station, the only control you have is to skip to the next track. And you can’t skip a song without breaking the groove.&lt;/p&gt;

&lt;h3 id=&quot;2-radio-station-with-smoother-cuts&quot;&gt;2. Radio Station with Smoother Cuts&lt;/h3&gt;

&lt;p&gt;Introducing smoother transitions between track cuts might cut down on interruptions. But doing it well is difficult and seems beyond the scope of Rdio; better suited for &lt;a href=&quot;http://serato.com&quot;&gt;Serato&lt;/a&gt; maybe. A simple cross-fade might help but, no matter what, skipping a track is still an auditory interruption.&lt;/p&gt;

&lt;h3 id=&quot;3-radio-station-with-better-suggestions&quot;&gt;3. Radio Station with Better Suggestions&lt;/h3&gt;

&lt;p&gt;Identify a theme by choosing a song, genre, or artist, and a Pandora-like radio station might be able to keep that vibe going. Each song is a gamble and “channel surfing” is still an interruption. But training the station with likes and dislikes does give users some control beyond just skipping the track.&lt;/p&gt;

&lt;h3 id=&quot;4-radio-station-with-more-control&quot;&gt;4. Radio Station with More Control&lt;/h3&gt;

&lt;p&gt;Manipulate a generated playlist based on your Collection or Heavy Rotation. When it gets close to the end, Rdio could add a handful of new tracks automatically.&lt;/p&gt;

&lt;p&gt;Now the DJ has more variety, can reorder tracks, and remove unwanted music before it plays. But it’s a subtractive process, which means less satisfaction for hand-selecting the next great track.&lt;/p&gt;

&lt;p&gt;This auto-generated-never-ending playlist could exist as a new section under Browse and/or Your Music in the left-column navigation. It shares some similarities to an iTunes Smart Playlist.&lt;/p&gt;

&lt;h3 id=&quot;5-remote-control&quot;&gt;5. Remote Control&lt;/h3&gt;

&lt;p&gt;I enjoyed the selection process but had to get off the couch to keep the tunes flowing. With better synchronization between devices, I could have added and rearranged music right from my phone. Great for convenience, terrible for social etiquette.&lt;/p&gt;

&lt;p&gt;Take this one step further and friends could add music to the queue from their phones.&lt;/p&gt;

&lt;p&gt;For what it’s worth, I started this exercise before version 2.0.0 of the Rdio iPhone app had been released.&lt;/p&gt;

&lt;h3 id=&quot;6-play-indicators&quot;&gt;6. Play Indicators&lt;/h3&gt;

&lt;p&gt;When you hear a song, you’re less likely to want to hear it again, especially at a party. The interface could indicate when a song has been played. I attempted unsuccessfully to achieve this with icons. Hourglasses were much too hard to read when scaled down and any other simple indicator, like a read/unread dot, lacked sufficient context. I used an opacity reduction instead. To avoid visual clutter, songs that are played together as part of a set would also fade in together. Because songs are tightly grouped by album, this opacity change could bubble up to the album level too. It’s a clever implementation but the opacity change still lacks context. Manipulating opacity is always a nuanced design choice and I don’t think it works well here.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://cloud.avandamiri.com/image/0f2t143k3C0B&quot; title=&quot;Rdio Play Indicator Mockup&quot; target=&quot;_blank&quot;&gt;
  &lt;img src=&quot;http://f.cl.ly/items/0X2j2D070z1t0N0I1s0f/Play%20and%20Fade.png&quot; title=&quot;Rdio Play Indicator Mockup&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;7-last-played&quot;&gt;7. Last Played&lt;/h3&gt;

&lt;p&gt;Most music libraries on the market today have a column for when a song was last played. But when sorting thousands of songs, the signal-to-noise ratio is low. For example, it’s hard to know why a song hasn’t been played in a while. Or you may play a song on your ride to work and want to hear it again at happy hour.&lt;/p&gt;

&lt;h3 id=&quot;8-popularity&quot;&gt;8. Popularity&lt;/h3&gt;

&lt;p&gt;While I was browsing more unfamiliar albums, it was hard to know which song to pick. I knew, for example, that I wanted to hear something off &lt;a href=&quot;http://rd.io/x/QD73PlnfZw&quot;&gt;Shrines&lt;/a&gt; by &lt;a href=&quot;http://rd.io/x/QD73LVdS-w&quot;&gt;Purity Ring&lt;/a&gt;, but I didn’t know which track. In this case, I’d be happy to default to the most popular option. Spotify does this in some places (&lt;a href=&quot;http://cloud.avandamiri.com/image/0T1d1P2x1b2V&quot;&gt;screenshot&lt;/a&gt;) but it’s less useful outside the context of an album.&lt;/p&gt;

&lt;h3 id=&quot;9-stars&quot;&gt;9. Stars&lt;/h3&gt;

&lt;p&gt;Starring serves the same utility as popularity but gives me more control. For example, I just re-listened to &lt;a href=&quot;http://rd.io/x/QD73Pl0efQ&quot;&gt;The 2nd Law&lt;/a&gt; by &lt;a href=&quot;http://rd.io/x/QD73Ldht&quot;&gt;Muse&lt;/a&gt; and &lt;a href=&quot;http://rd.io/x/QD73K0Iav8Q&quot;&gt;Unsustainable&lt;/a&gt; stood out as a token dubstep track. I’ll definitely be hunting it down again soon. It would be nice to call it out from the other songs on that album. On the other hand, stars add clutter and in other applications, like Gmail, they’re predominantly underutilized.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://cloud.avandamiri.com/image/3q0e2M1T3D46&quot; title=&quot;Rdio Stars Mockup&quot; target=&quot;_blank&quot;&gt;
  &lt;img src=&quot;http://f.cl.ly/items/1F350z270I463A3W0C36/Stars.png&quot; title=&quot;Rdio Stars Mockup&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;10-play-strength&quot;&gt;10. Play Strength&lt;/h3&gt;

&lt;p&gt;Perhaps the solution is more holistic. A great setlist takes into account when a song was played last, its popularity, how it relates to friends’ musical tastes, and similarity to music that’s currently playing. Rdio could compute a compound index, Play Strength, and expose it in the interface to help suggest the next tracks. You don’t have to explain how you computed the index, but the mechanics are interesting. Pandora does this when they explain why you’re hearing a particular song and it adds to the experience.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;play-strength-deep-dive&quot;&gt;Play Strength Deep Dive&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://cloud.avandamiri.com/image/2T1B0e2J0Z0V&quot; title=&quot;Rdio Play Strength Mockup&quot; target=&quot;_blank&quot;&gt;
  &lt;img src=&quot;http://f.cl.ly/items/2E3U3h2U340w0v0z0X39/Play%20Strength.png&quot; title=&quot;Rdio Play Strength Mockup&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Play Strength is a compound index computed for each song for each user based on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Number of times the user has played the song&lt;/li&gt;
  &lt;li&gt;When the user last played the song&lt;/li&gt;
  &lt;li&gt;Number of friends that have recently listened to the song&lt;/li&gt;
  &lt;li&gt;Popularity of the song in the community&lt;/li&gt;
  &lt;li&gt;Similarity of the song to other songs in the current setlist&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;play-count--last-played&quot;&gt;Play Count &amp;amp; Last Played&lt;/h3&gt;

&lt;p&gt;In every music library, plays are distributed over time organically based on the owner’s tastes. Every song’s play count  and last played will fall within some standard deviation of the library’s average. You may be able to tell if a song is being over or under played based on the standard deviation for these two values.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://f.cl.ly/items/1h33270t2w0430050B2e/Standard%20Deviation.jpg&quot; alt=&quot;Over and Underplayed Songs Based on Standard Deviation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In my mockup, I simply print last played and play count but it might be more interesting to actually tell the user, “you over/underplay this song” or “you have (not) played this song recently.”&lt;/p&gt;

&lt;p&gt;It’s also important to note that an overplayed song may actually be a great addition to a setlist. Songs with abnormally high play counts are probably the songs you like the most. In these cases, the Play Strength should get a big boost. But if the song was already included in the current set, the Play Strength should drop dramatically.&lt;/p&gt;

&lt;h3 id=&quot;friends&quot;&gt;Friends&lt;/h3&gt;

&lt;p&gt;Rdio already does an awesome job of leveraging my friends’ musical tastes to help me discover new music. But once music is in my library, it’s up to me to rediscover it. The more friends I have that are listening to a song, the higher its Play Strength should be. This is especially useful when my friends are listening to particular songs on an album more than others. And if you knew which Rdio users were listening to the current mix, Play Strength could be taken to a whole new level.&lt;/p&gt;

&lt;h3 id=&quot;popularity--similarity&quot;&gt;Popularity &amp;amp; Similarity&lt;/h3&gt;

&lt;p&gt;While building my setlist Saturday night, there were a few times where I knew what album or artist I wanted to hear but I had no idea which song to play. Albums can have a huge variance in tempo and mood so it’s easy to choose… &lt;a href=&quot;http://www.youtube.com/watch?v=Ubw5N8iVDHI&quot;&gt;poorly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Knowing which songs are popular across the entire music community is really helpful. &lt;a href=&quot;http://nextbigsound.com&quot;&gt;Next Big Sound&lt;/a&gt; has done some really interesting work in this area but it centers around artists. I imagine Rdio already has the data required to know which songs are being played more than others by album or artist across the ecosystem.&lt;/p&gt;

&lt;p&gt;A setlist is also bound to share acoustic themes. Songs that sound like what you’re currently playing should have a higher Play Strength. But knowing which songs sound like other songs programmatically is hard. &lt;a href=&quot;http://the.echonest.com&quot;&gt;The Echo Nest&lt;/a&gt; out of Boston has some API’s that could help but song similarity is part of a much larger music discovery problem.&lt;/p&gt;

&lt;p&gt;Songs within a genre share similar sounds, especially when they’re released around the same time. Rdio could boost the Play Strength for any song in a genre currently represented by the setlist.&lt;/p&gt;

&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing Remarks&lt;/h2&gt;

&lt;p&gt;Play Strength is a hard technical problem but is a simple solution for the end user. I think the last radio variant concept, i.e. the auto-generated-never-ending playlist, is also really interesting but it’s a specialized feature. Play Strength stays out of your way and consistently adds to the experience of browsing music.&lt;/p&gt;

&lt;p&gt;I also like Play Strength because it lends itself to iteration. The bar-style strength indicator, inspired by &lt;a href=&quot;http://angel.co&quot;&gt;AngelList&lt;/a&gt;, is not an invasive addition. At first, the callout that explains how Play Strength is computed could be left out. As the rules for computing Play Strength change, the callout evolves organically. This gives the feature a lot of room to grow.&lt;/p&gt;

&lt;p&gt;Finally, I like Play Strength because it’s comprehensive. It’s the type of feature I might grow to love and is hard to copy.&lt;/p&gt;

&lt;p&gt;Looking forward to your feedback in the comments.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Create Great Technical Interviews</title>
   <link href="http://avandamiri.com/2012/11/26/create-great-technical-interviews.html"/>
   <updated>2012-11-26T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2012/11/26/create-great-technical-interviews</id>
   <content type="html">&lt;p&gt;A technical interview or screening is a crucial part of reviewing a candidate
for an engineering position. It’s usually the second step in the review process
and is a prerequisite to an in-person interview. Here are some lessons I’ve
learned in the last few years of taking and giving a dozen or so interviews.&lt;/p&gt;

&lt;p&gt;You learn bits and pieces about the personality of a candidate throughout the
entire interview process. The technical interview is a chance for them to
highlight their expertise, aptitude, and style, not their charm, wit, or lack
thereof. I set aside an hour for technical interviews: 10 minutes for
introductions, 40 minutes to code, and 10 minutes at the end for Q&amp;amp;A.&lt;/p&gt;

&lt;p&gt;I start with a three to five minute summary of who I am and what I do. Humans
naturally &lt;a href=&quot;http://en.wikipedia.org/wiki/Mirroring_(psychology)&quot;&gt;mirror&lt;/a&gt; each other’s behavior. In an interview, I find this
to be amplified so I make sure to stick to the facts and ask the candidate to
do the same.&lt;/p&gt;

&lt;p&gt;If you’ve got a “Chatty Cathy,” keep your eye on the clock. Make sure chit-chat
doesn’t eat into their time to code. Interrupt your candidate politely by saying,
“I want to make sure you have enough time to get through the code so let’s come
back to this during Q&amp;amp;A.” Inversely, if the candidate is taciturn, have some
questions ready to open them up. What projects are they working on? What type
of role are they looking for? How do they stay current with technology?&lt;/p&gt;

&lt;p&gt;When it comes time to code, there are thousands of interview questions to choose
from. I look for a single problem that flexes several computer science muscles
like recursion, object-oriented programming, queues, or data structures. The more
ways there are to solve the problem, the better chance you’ll have to see how
the candidate thinks. I also prefer problems that start simply, build in complexity
and lend themselves to test-driven development (TDD).&lt;/p&gt;

&lt;p&gt;Practice explaining the problem clearly to avoid wasting time and encourage
candidates to think out loud. Most technical interview problems have a really
elegant and non-intuitive solution. Candidates often know this and can spin
their wheels trying to figure it out on the first pass. TDD helps alleviate
these symptoms. Remind candidates that you’re looking for thoughtfulness over
correctness to help them feel more comfortable.&lt;/p&gt;

&lt;p&gt;It’s crucial to see every keystroke. An engineer’s cursor is an extension of
her thought process. In the past, I’ve used Skype or Messages (formerly iChat)
to screen share. Besides being a little invasive, screen sharing can lead to
“rabbit holes,” especially during setup. For example, I’ve seen confused
candidates create entirely new Rails projects or bundle a gem when a single Ruby
file would have sufficed. The less wiggle-room the better. Google Docs works
but you really want an editor designed for code. I recommend &lt;a href=&quot;http://www.stypi.com/&quot;&gt;Stypi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the code. Engineers iterate on solutions by executing the code they’ve written.
I think it’s unfair to make anyone think through a whole problem in their head.
If you’re using a web-based editor, you may be able to pipe the code directly
to a local interpreter. The folks at Stypi made this easy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Just replace the URL (don&apos;t forget &quot;/raw&quot;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;--silent&lt;/span&gt; https://www.stypi.com/raw/avand/interviews/reverse_polish_notation.rb | ruby
Loaded suite -
Started
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Finished &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0.000427 seconds.

1 tests, 4 assertions, 0 failures, 0 errors, 0 skips&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Be helpful, engaged, and bail candidates out of sticky situations. It’s easy to
go into “spectator mode.” By actively following a candidate’s thought process
you’ll better understand how they think and keep the interview on track. To stay
engaged, introduce a big problem one small piece at a time, give examples of input
and output, and point out potential bugs or edge cases as they come up.&lt;/p&gt;

&lt;p&gt;Cut candidates off at the time limit, even if their work is unfinished. If
you made it clear up front that you’re not necessarily looking for the correct
answer, this should be easy. Change gears quickly to Q&amp;amp;A by asking them if they
have any questions for you and wrap up the call from there. Great candidates have
great questions that open up really interesting conversation. I like to indulge
in good conversation, especially if the coding exercise went well. It helps me
understand if the candidate would be a good mental and cultural fit.&lt;/p&gt;

&lt;p&gt;Pull the plug if a candidate is bombing. Like going on a blind date, you may
know within minutes that the candidate isn’t a good fit. I prefer to pull the
cord immediately when this happens. I’ll say, “this isn’t going as I expected”
and then site a reason (e.g., “we’re looking for folks that understand a language,
not framework” or “a solid understanding of these data structures is really
important to us”).&lt;/p&gt;

&lt;p&gt;Finally, If the candidate is a no-go, give a good reason why. “We don’t think
there’s a good technical fit” isn’t a real reason. Describing why a candidate
is or is not a fit is hard but it’s worth doing. It forces you to objectively
distill your thoughts, which will make it easier to discern other candidates.
And it’s great feedback for the candidates too as they, no doubt, will learn
from this experience.&lt;/p&gt;

&lt;p&gt;Creating great technical interviews is a key piece of growing an engineering
team. Doing it well means objectively screening candidates without tying up a
lot of resources. Having sat on both sides of the interview table, I’ve found
this approach to be a really good baseline. I look forward to reading your
thoughts in the comments.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Snappy Dashboards with Redis</title>
   <link href="http://avandamiri.com/2012/10/15/snappy-dashboards-with-redis.html"/>
   <updated>2012-10-15T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2012/10/15/snappy-dashboards-with-redis</id>
   <content type="html">&lt;p&gt;It seems that almost every application I’ve worked on has some sort of dashboard
component. It’s not usually the first feature but it often becomes the most useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But dashboards are hard to build.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They break resource-oriented design patterns and often rely on complicated one-off
SQL queries. Dashboards also usually feature graphs and activity streams, both of
which are not trivial to implement well.&lt;/p&gt;

&lt;p&gt;At &lt;a href=&quot;http://www.sqoot.com/&quot;&gt;Sqoot&lt;/a&gt;, a local deal API, we have a &lt;a href=&quot;http://f.cl.ly/items/141f053h2P3t0m1r3g2R/Image%202012.10.15%202:49:43%20PM.png&quot;&gt;simple dashboard&lt;/a&gt; for our
customers. Given a time frame, it tells developers how many deals they’ve served
(impressions), how many clicks they’ve driven, and how much affiliate revenue
they’ve earned (earnings). It might also be interesting to know how many API calls
they’ve made.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://f.cl.ly/items/141f053h2P3t0m1r3g2R/Image%202012.10.15%202:49:43%20PM.png&quot; alt=&quot;Sqoot Dashboard Screenshot&quot; title=&quot;Sqoot Dashboard Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All of these stats follow a pretty standard query pattern:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;USER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TIME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TIME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This works great for small collections or well-indexed relational tables. For example,
earnings are reported exactly like this. But enormous collections, especially when stored
in document-centric databases, become slow to query. This is especially true if you have
to join disparate data sources.&lt;/p&gt;

&lt;p&gt;So we developed another way to store the counts we need. It’s a thin Ruby wrapper around
Redis and we call it The Count (ah ah ah ah ah!). Here’s how it works.&lt;/p&gt;

&lt;p&gt;For every stat we’re interested in, we set a few keys:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;{stat}/year:{YYYY}
{stat}/year:{YYYY}/month:{MM}
{stat}/year:{YYYY}/month:{MM}/day:{DD}
{stat}/user:{id}/year:{YYYY}
{stat}/user:{id}/year:{YYYY}/month:{MM}
{stat}/user:{id}/year:{YYYY}/month:{MM}/day:{DD}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first three keys tell us totals for all users by year, month, and day. The last three
scope the same totals to one user. For example, if you want to know how many clicks user
5 drove in September:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;REDIS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;clicks/user:5/year:2012/month:09&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can also query across date ranges with the help of some Ruby:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;REDIS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;clicks/user:5/year:2012/month:06&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;clicks/user:5/year:2012/month:07&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;clicks/user:5/year:2012/month:08&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Every time an API call, impression, or click happens, we update all the relevant keys at
once:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;REDIS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;multi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;REDIS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;incr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If Redis isn’t available, for whatever reason, we could rebuild the gaps from the canonical
data in Mongo. We’ve never had to do this.&lt;/p&gt;

&lt;p&gt;Now, when our customers load their dashboard, we don’t need to go slogging through millions
of records. This makes our dashboards snappy. It’s also worth noting that this approach takes
up very little space. If we segment by day, each year for each stat only uses 375 keys per user
and another 375 for the aggregate data. The values are almost inconsequential since their just numbers. All our dashboard data is stored in this way with our friends at &lt;a href=&quot;http://redistogo.com&quot;&gt;Redis To Go&lt;/a&gt;
in a 20 MB instance.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Track Expenses in Google Docs via SMS</title>
   <link href="http://avandamiri.com/2012/05/14/track-expenses-in-google-docs-via-sms.html"/>
   <updated>2012-05-14T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2012/05/14/track-expenses-in-google-docs-via-sms</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://farm9.staticflickr.com/8145/7199153550_d3a50c9809_n.jpg&quot; alt=&quot;Track Expenses in Google Docs via SMS&quot; title=&quot;Track Expenses in Google Docs via SMS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tracking expenses is a pain in the butt. At &lt;a href=&quot;http://www.sqoot.com/&quot;&gt;Sqoot&lt;/a&gt;, we use Google Docs for almost everything, including expenses, but entering anything on the go is cumbersome. Today, I got frusted and decided to take an hour and hack something together.&lt;/p&gt;

&lt;p&gt;I wanted to be able to text something like this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“35 Burgers with the team”&lt;/li&gt;
  &lt;li&gt;“420.15 Hosting costs”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those text should become entries in a spreadsheet like this:&lt;/p&gt;

&lt;table style=&quot;width: 70%&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Description&lt;/th&gt;
    &lt;th&gt;Date&lt;/th&gt;
    &lt;th&gt;Amount&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Burgers with the team&lt;/td&gt;
    &lt;td&gt;5/14/2012&lt;/td&gt;
    &lt;td&gt;$35.00&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Hosting costs&lt;/td&gt;
    &lt;td&gt;5/12/2012&lt;/td&gt;
    &lt;td&gt;$420.15&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;h2 id=&quot;twilio&quot;&gt;Twilio&lt;/h2&gt;

&lt;p&gt;I had never worked with &lt;a href=&quot;http://twilio.com&quot;&gt;Twilio&lt;/a&gt; before but it was a cinch.&lt;/p&gt;

&lt;p&gt;I set up a new account and funded it. For $1.00/mo, I got myself a phone number that I could start texting. Twilio will POST to whatever URL you specify when a text comes into that number. So getting texts into my app was basically done.&lt;/p&gt;

&lt;p&gt;Eventually, I would also need to send back a confirmation text. Turns out that’s pretty trivial as well with the &lt;a href=&quot;https://github.com/twilio/twilio-ruby&quot;&gt;Twilio Ruby gem&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;TWILIO&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Twilio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;REST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;twilio-account-sid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;twilio-auth-token&quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;TWILIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;to:   &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;from-phone-number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;from: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;to-phone-number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;body: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Success!&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;google-drive-gem&quot;&gt;Google Drive Gem&lt;/h2&gt;

&lt;p&gt;After a little sleuthing, I found a &lt;a href=&quot;https://github.com/gimite/google-drive-ruby&quot;&gt;Google Drive gem&lt;/a&gt; that would let me interact with our expense spreadsheet with just a few lines of Ruby:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;google_drive&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GoogleDrive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;avand@sqoot.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;would-you-like-to-know&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spreadsheet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;spreadsheet_by_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spreadsheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;worksheets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;num_rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Burgers with the team&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;5/14/2012&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;35.00&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;worksheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This simply grabs the spreadsheet, opens up the worksheet, and adds a row with three columns to end.&lt;/p&gt;

&lt;h2 id=&quot;brioche&quot;&gt;Brioche&lt;/h2&gt;

&lt;p&gt;Finally, I wrapped up all this code into a very simple &lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt; app called &lt;a href=&quot;https://github.com/avand/brioche&quot;&gt;Brioche&lt;/a&gt;. It responds to a POST to /expenses and expects the parameters Twilio sends over. Brioche then parses the body of the text, connects to Google Docs, and adds a row to a worksheet. Finally, it composes a confirmation message and sends it back via the Twilio API.&lt;/p&gt;

&lt;p&gt;It doesn’t handle errors and you’ll need to set your Google password as an environmental variable on Heroku (shudder), but for an hour’s worth of work, it works pretty well!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Five Ways to Evaluate New Ideas</title>
   <link href="http://avandamiri.com/2012/02/18/five-ways-to-evaluate-new-ideas.html"/>
   <updated>2012-02-18T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2012/02/18/five-ways-to-evaluate-new-ideas</id>
   <content type="html">&lt;p&gt;It took six years for the novelty of building stuff to wear off. I’ve worked on huge failing corporate projects, cool weekend hacks, and successful startups. At a certain point, you’ve proved to yourself that you &lt;em&gt;can&lt;/em&gt; build it. Now, &lt;em&gt;what&lt;/em&gt; you’re building matters. So how do you become selective about the products you work on?&lt;/p&gt;

&lt;h2 id=&quot;real-fucking-problems&quot;&gt;Real Fucking Problems&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7068/6911108205_f5dfc9665e_m_d.jpg&quot; class=&quot;right&quot; height=&quot;179&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have some friends from the management consulting world. You’ve probably sat next to one on a plane. They have IBM ThinkPads and crunch Excel workbooks for a project that is invariably behind and over budget. They travel a lot. They’re paid well. And, it seems that all of them want to start something. Bright-eyed and bushy-tailed, they ogle at Facebook, Twitter, FourSquare, Pintrest, Path–whatever’s hot and on the first page of TechCrunch. They’ll attend a &lt;a href=&quot;http://startupweekend.org/about/&quot;&gt;StartupWeekend&lt;/a&gt; wearing the obligatory “idea guy”-colored T-shirt and pitch their idea: “I want to build a disruptive, mobile, social goal setting app”. Puke.&lt;/p&gt;

&lt;p&gt;Wake up and smell the dehydrated single-serving crap you call coffee! If you’re serious about building something, tackle a real fucking problem. Delve into your vast reservoir of corporate experience and drum up every complaint, grievance, and suggestion you can remember. Bribe HR for access to the comment box if you have to! Those are problems people deal with every day. They pay money for solutions. Real problems are well-defined; a constraint you need to build a good solution.&lt;/p&gt;

&lt;h2 id=&quot;elegant&quot;&gt;Elegant&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7062/6911122075_b4384aca8b_m_d.jpg&quot; class=&quot;right&quot; height=&quot;179&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Good design is as little design as possible.”&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.artsy.net/artist/dieter-rams&quot;&gt;Dieter Rams&lt;/a&gt;, &lt;a href=&quot;http://braun.com/&quot;&gt;Braun&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Real problems often have complex solutions but complexity isn’t something to be afraid of. Almost any time I’ve tried to explain how the web works, I’m stunned that it works at all. Sometimes to get this to go over there in that much time involves some wizardry. Don’t sweat it.&lt;/p&gt;

&lt;p&gt;But at 30,000 feet, an idea should be elegant. &lt;a href=&quot;http://twilio.com/&quot;&gt;Twilio&lt;/a&gt;: wrap up all the madness involved in sending texts and making calls behind a developer-friendly API. &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt;: make deploying a standard Rails app as simple as checking in your code. &lt;a href=&quot;https://www.uber.com/&quot;&gt;Uber&lt;/a&gt;: hail and pay for a black-car service from your phone. In mechanics, it’s possible to determine the &lt;a href=&quot;http://en.wikipedia.org/wiki/Two-body_problem&quot;&gt;motion of two bodies&lt;/a&gt; but the three-body problem cannot be solved. Reduce the number of variables and keep your product ridiculously simple and straightforward upfront.&lt;/p&gt;

&lt;h2 id=&quot;dough-from-day-one&quot;&gt;Dough from Day One&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7066/6911107821_174a002346_m_d.jpg&quot; class=&quot;right&quot; height=&quot;164&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“You have customers, they pay you money… you get profit!”&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://david.heinemeierhansson.com/&quot;&gt;David Heinemeier Hanson&lt;/a&gt;, &lt;a href=&quot;http://37signals.com/&quot;&gt;37Signals&lt;/a&gt;, at &lt;a href=&quot;http://www.youtube.com/watch?v=0CDXJ6bMkMY&quot;&gt;Startup School in 2008&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you haven’t thought about how your product will make money, your days are numbered. If “targeted advertising” or “freemium” are your biggest potential revenue streams, go back to the drawing board. It’s not that it can’t be done, but to succeed you need massive adpotion and engagement. Easier said than done. The glitz and glamor of bootstrapping wears off fast. When it does, have real money coming in the door.&lt;/p&gt;

&lt;p&gt;What about raising capital? Without a jaw-dropping team or massive traction, you’re too early for most investors you’d actually want to take money from. Accelerators don’t present much more favorably odds either. Over 1,500 folks applied to the last round of TechStars in New York. They accepted 15. We haven’t even factored in YC or all the other teams that didn’t apply. Even though a ton of capital is being dumped into startups, you and your idea are up against a shit load of competition. If you have to draw a line that goes up and to the right, make it revenue.&lt;/p&gt;

&lt;h2 id=&quot;scratch-your-own-itch&quot;&gt;Scratch Your Own Itch&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7056/6911107941_dedd6d4981_m_d.jpg&quot; class=&quot;right&quot; height=&quot;229&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Leverage yourself by solving a problem you have. When you really understand a domain you can spend more time building and less time gathering requirements.  “When it’s all in [your] brain, it’s a perfect feedback loop,” &lt;a href=&quot;http://vimeo.com/26335493&quot;&gt;says Jason Seats&lt;/a&gt;, co-founder of &lt;a href=&quot;http://www.slicehost.com/&quot;&gt;SliceHost&lt;/a&gt;. If you don’t use your own product, you’re completely reliant on feedback. “You have to construct artificial ways to get information.” You’re likely flying blind or moving too slowly.&lt;/p&gt;

&lt;h2 id=&quot;unfair-advantage&quot;&gt;Unfair Advantage&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7203/6911108115_0df8b59734_m_d.jpg&quot; class=&quot;right&quot; height=&quot;229&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The expression “life isn’t fair,” isn’t totally accurate. Life is only unfair fair if you’ve got the short end of the stick. When I was at &lt;a href=&quot;http://dreamitventures.com/&quot;&gt;DreamIt Ventures&lt;/a&gt; in 2010, &lt;a href=&quot;http://www.firstround.com/team/profile/josh_kopelman/&quot;&gt;Josh Kopleman&lt;/a&gt; of &lt;a href=&quot;http://www.firstround.com/&quot;&gt;First Round Capital&lt;/a&gt; gave us some tips on being better entrepreneurs. This was one of them. If you’re working on a big opportunity, so are others. Why you and not them? It may be someone you know, a patent you filed, or an exclusive contract you signed. You may simply have a killer team that can get shit done. Know your unfair advantages take full advantage of them.&lt;/p&gt;

&lt;p&gt;That’s it! These are the five rules I screen all new ideas with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pick real fucking problems,&lt;/li&gt;
  &lt;li&gt;Find an elegant solution,&lt;/li&gt;
  &lt;li&gt;Make dough from day one,&lt;/li&gt;
  &lt;li&gt;Scratch your own itch, and&lt;/li&gt;
  &lt;li&gt;Take advantage of being advantaged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As my good friend &lt;a href=&quot;http://michaeldwan.com/&quot;&gt;Michael Dwan&lt;/a&gt;, co-founder of &lt;a href=&quot;http://snapjoy.com/&quot;&gt;SnapJoy&lt;/a&gt;, once told me, “ideas are like the bus… you miss one, there’s another right behind it.” Don’t take it personally if your idea doesn’t make the cut. You’ll make it to your destination faster by being selective about how you get there.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Serving Different Robots.txt Using Rack</title>
   <link href="http://avandamiri.com/2011/10/11/serving-different-robots-using-rack.html"/>
   <updated>2011-10-11T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2011/10/11/serving-different-robots-using-rack</id>
   <content type="html">&lt;p&gt;While doing an SEO audit for the &lt;a href=&quot;http://www.sqoot.com/&quot;&gt;daily deal API&lt;/a&gt; I’m working on, the subject of the &lt;a href=&quot;http://www.robotstxt.org/&quot;&gt;robots.txt&lt;/a&gt; came up. In addition to our production environment (what you and everyone else see), we also use an “edge” environment. It’s a place we can push the latest and greatest changes and test them before they go live. Edge is an exact copy of production just running on a different domain. Since we didn’t want to get dinged with content duplication we had to disallow spiders from crawling our edge environment. Here’s how we serve different robots.txt files based on environment using Rack within Rails.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Move public/robots.txt to config/robots.txt. This is now your production robots.txt. Any other environment will disallow everything for all user-agents.&lt;/li&gt;
  &lt;li&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RobotsGenerator&lt;/code&gt; in lib&lt;/li&gt;
  &lt;li&gt;Point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/robots.txt&lt;/code&gt; to the generator in your routes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;lib/robots_generator.rb:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RobotsGenerator&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Use the config/robots.txt in production.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Disallow everything for all other environments.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;production?&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;config&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;robots.txt&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;User-agent: *&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Disallow: /&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Heroku can cache content for free using Varnish&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;text/plain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&apos;Cache-Control&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;public, max-age=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENOENT&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;text/plain&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;# A robots.txt is not configured&apos;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;config/routes.rb&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;robots_generator&apos;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;YourApplication&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/robots.txt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RobotsGenerator&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; &lt;em&gt;(Sept. 23, 2013)&lt;/em&gt;: Thanks to &lt;a href=&quot;https://twitter.com/michaelbaudino&quot;&gt;@michaelbaudino&lt;/a&gt; for pointing out that
routes.rb needs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require &apos;robots_generator&apos;&lt;/code&gt; since Rails 3 does not autoload files
in lib. Additionally, the request headers should always include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; to avoid
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::Lint::LintError&lt;/code&gt; error.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Make a 60 Sec Video Pitch in 500 Photos, $2 and 1 Day</title>
   <link href="http://avandamiri.com/2011/10/09/60-second-video-pitch-in-500-photos-2-dollars-1-day.html"/>
   <updated>2011-10-09T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2011/10/09/60-second-video-pitch-in-500-photos-2-dollars-1-day</id>
   <content type="html">&lt;p&gt;Often the hardest part of building a product is explaining it to people. If it seems complicated, most people just move along. A popular way to grab people’s attention is with a short video. They come in a bunch of flavors but the popular ones include 2D &amp;amp; 3D animations, screencasts and live action.&lt;/p&gt;

&lt;p&gt;If you have the budget, getting one of these videos made is easy. Just plunk down about $5k, create a script or storyboard and out comes a video. But the rest of us have to come up with something on our own. Here’s how I created this 60 second video explaining &lt;a href=&quot;http://thezippr.com/&quot;&gt;Zippr&lt;/a&gt; in about 6 hours with a laptop, markers, paper, $2.00 and the &lt;a href=&quot;http://grooveshark.com/#/album/Tron+Legacy+Reconfigured/5892109&quot;&gt;Tron Legacy Reconfigured&lt;/a&gt; album.&lt;/p&gt;

&lt;object width=&quot;400&quot; height=&quot;300&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=26607863&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=00adef&amp;amp;fullscreen=1&amp;amp;autoplay=0&amp;amp;loop=0&quot; /&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=26607863&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=00adef&amp;amp;fullscreen=1&amp;amp;autoplay=0&amp;amp;loop=0&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; width=&quot;400&quot; height=&quot;300&quot; /&gt;&amp;lt;/embed&amp;gt;&lt;/object&gt;

&lt;h2 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Markers&lt;/strong&gt;: Simple Crayola will do.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Paper&lt;/strong&gt;: 8.5” x 11”. The thicker the better. Loose leaf.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MacBook with iSight&lt;/strong&gt;: Photo Booth is about to become your friend.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;iMovie&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Patience&lt;/strong&gt;: Can be replaced with a great 3 hour playlist&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;External monitor, keyboard, &amp;amp; mouse&lt;/strong&gt;: Optional but highly recommended for your sanity&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tape&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;directions&quot;&gt;Directions&lt;/h2&gt;

&lt;p&gt;Before you dive into the video production:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Write a script&lt;/strong&gt;: You don’t have time to get into detail, so keep it short and sweet. Make sure you answer these questions for your customers: what’s in it for me, how does it work and what do I do next? Time yourself reading it outloud.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Create a storyboard&lt;/strong&gt;: Divide a 8.5’ x 11’ piece of paper into 9 quadrants and sketch each “scene.” Get a rough idea of how long each scene will take to narrate. Each scene will end up what you draw on one piece of paper.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the fun part:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Set up your computer so the webcam is about 10 inches from a plain white wall. Plugin an external monitor and hook up a mouse and keyboard do you can see what’s going on while your computer is in timeout.&lt;/li&gt;
  &lt;li&gt;Adjust the angle and position of the webcam such that when you hold a piece of paper against the wall it fills up the entire shot. Mark the wall at the corners of the paper with a pencil.&lt;/li&gt;
  &lt;li&gt;Ideally, you’re in a well lit room. Set up lamps around your computer to provide a nice bright shot. More importantly &lt;em&gt;don’t change the lighting once you start&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Start drawing. You’re going to draw a little bit (2-3 lines) then tape the picture up against the wall where you marked it earlier.&lt;/li&gt;
  &lt;li&gt;Take a picture.&lt;/li&gt;
  &lt;li&gt;Repeat steps 4 and 5 ~300 times. It sounds tedious because it is. Jamming out to a good playlist helps. This should take about 3 hours and I’d recommend doing it in one shot because ambient lighting can change. Verify your work after each scene to make sure you’re on track. Remember, you can’t go back and redo a scene without redrawing the entire page so take more pictures than you need.&lt;/li&gt;
  &lt;li&gt;Dump the photos into iMovie. Set all the clips to be ~0.1s. You should find that you have way more photos then you need.&lt;/li&gt;
  &lt;li&gt;Edit to your heart’s content. Delete clips, make certain clips longer, etc. Get it down to roughly the timeframe you set for your script.&lt;/li&gt;
  &lt;li&gt;Record the narrative. You can do this right from iMovie.&lt;/li&gt;
  &lt;li&gt;Spice it up with some music. My friend Darby pointed me towards &lt;a href=&quot;http://friendlymusic.com/&quot;&gt;Friendly Music&lt;/a&gt;. I searched for “whistle” and listened to about 20 songs before finding the Quirky by Benny Hawes. $2 later, I dragged the song into iMovie.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;nutritional-information&quot;&gt;Nutritional Information&lt;/h2&gt;

&lt;p&gt;That’s basically it. You can export from iMovie to whatever file format you’d like. Then upload it to YouTube, Vimeo, or whatever.&lt;/p&gt;

&lt;p&gt;Remember, your product will likely change (especially if you don’t have a budget for a “real” video). Stick to sketches and drawings instead of screenshots. Talk about benefits instead of features because features change. This way in 3 months when you’re doing something different, you don’t have to go create a whole new video.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Building an App to Monitor Your App</title>
   <link href="http://avandamiri.com/2011/04/28/building-an-app-to-monitor-your-app.html"/>
   <updated>2011-04-28T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2011/04/28/building-an-app-to-monitor-your-app</id>
   <content type="html">&lt;p&gt;Keeping a web application up and running usually requires lots of moving parts. Since these parts are all codependent, when the whole app goes down, the immediate question is: &lt;strong&gt;what broke?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I want to share with you the solution we came up with at &lt;a href=&quot;http://www.sqoot.com/&quot;&gt;Sqoot&lt;/a&gt;. Let’s dive right into the code and then talk about how we got here.&lt;/p&gt;

&lt;h2 id=&quot;diving-right-in&quot;&gt;Diving Right In&lt;/h2&gt;

&lt;p&gt;We start with a simple &lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt; web app:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;erb&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;sinatra&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;active_support&apos;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;PROCESSES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:solr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:memcached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:mongo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# ...can be anything&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Ask each process what its status is (e.g., { :solr =&amp;gt; true, ... })&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@process_statuses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PROCESSES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({})&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_up?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Set the response code to 200 if all the statuses are up&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@process_statuses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;503&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;erb&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then we just need a bunch of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_up?&lt;/code&gt; methods to do the checking, like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;httparty&apos;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solr_up?&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;solr_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;...&apos;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# replace with your Solr server&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;solr_host&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin/ping&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;success?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In addition to &lt;a href=&quot;http://lucene.apache.org/solr/&quot;&gt;Solr&lt;/a&gt;, we also make sure that &lt;a href=&quot;https://gist.github.com/950677&quot;&gt;Mongo&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/950680&quot;&gt;Memcached&lt;/a&gt; are running.&lt;/p&gt;

&lt;p&gt;Finally, we need a couple endpoints for &lt;a href=&quot;http://www.pingdom.com/&quot;&gt;Pingdom&lt;/a&gt; to hit (e.g, &lt;a href=&quot;http://health.sqoot.com/solr/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/solr&lt;/code&gt;&lt;/a&gt;) so that we can check each service independently:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;PROCESSES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@process&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@status&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_up?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@status&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;503&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;erb&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:process&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add a couple trivial views, some CSS3 awesome, and voilà, you’ve got &lt;a href=&quot;http://health.sqoot.com/&quot;&gt;health.sqoot.com&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&quot;taking-a-step-back&quot;&gt;Taking a Step Back&lt;/h2&gt;

&lt;p&gt;The first thing we did to monitor uptime was point &lt;a href=&quot;http://www.pingdom.com/&quot;&gt;Pingdom&lt;/a&gt; at &lt;a href=&quot;http://www.sqoot.com/&quot;&gt;Sqoot&lt;/a&gt;’s homepage. We would perform some trivial check and when the site went down we dealt with a deluge of errors we couldn’t do anything about (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timeout::Error&lt;/code&gt;). Since we use &lt;a href=&quot;http://hoptoadapp.com/&quot;&gt;Hoptoad&lt;/a&gt; to stay on top of application exceptions all these errors got really noisy. We also still didn’t know which dependency had gone down. We just knew the site was hosed.&lt;/p&gt;

&lt;p&gt;We had to be able to monitor each service independently. So we created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StatusesController&lt;/code&gt; in the app that had an action for every service we wanted to monitor. The good thing was that we could now really introspect the process (like above) to make sure it was OK. For example, we might want to know that search is running and there are a certain number of documents indexed too. Unfortunately, if the status of one service changed, they usually all changed (due to requests queuing up, etc.). So we still didn’t have great insight as to what broke.&lt;/p&gt;

&lt;p&gt;By creating a separate application that performed the checks, we were able to get detailed insight as to what services were running (or not). We can use Ruby to make each check meaningful and since it lives outside our app, it reports on each service exclusively.&lt;/p&gt;

&lt;p&gt;Boom!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Tests Pass. You Fail.</title>
   <link href="http://avandamiri.com/2011/03/29/tests-pass-you-fail.html"/>
   <updated>2011-03-29T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2011/03/29/tests-pass-you-fail</id>
   <content type="html">&lt;p&gt;Shit breaks. It’d be so much cooler if things just worked the way we expected, but they don’t. For better or worse, we live in a world where everything eventually fails. And software is definitely not an exception.&lt;/p&gt;

&lt;p&gt;So we write tests. If 1 + 1 should be 2, we make assertions that that’s &lt;strong&gt;always&lt;/strong&gt; the case. Seems like an all-upside no-brainer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But could your tests being doing more harm than good?&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;you-stop-looking-forward&quot;&gt;You Stop Looking Forward&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm6.static.flickr.com/5134/5575368800_3a1e157df1_m.jpg&quot; alt=&quot;Looking Forward Fail&quot; title=&quot;Looking Forward Fail&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just because your tests look back doesn’t mean you should. In fact the exact opposite is true. As a developer you have to keep your head up, scanning the horizon for opportunities. Ideally, you’re looking for opportunities to make your product better. But even if you’re not responsible for the decisions that create happier customers, babysitting your test suite is still probably not the best use of your time.&lt;/p&gt;

&lt;p&gt;If you’re interested in actually moving the needle, perhaps the better benchmark is not how often your tests pass, but how often they fail.&lt;/p&gt;

&lt;h2 id=&quot;you-lose-sight-of-your-customer&quot;&gt;You Lose Sight of Your Customer&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm6.static.flickr.com/5265/5574782175_e9b08ab39a_m.jpg&quot; alt=&quot;Focusing on Customer Fail&quot; title=&quot;Focusing on Customer Fail&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Passing tests are quite a high. Engineers are always looking for cold hard facts. Passing tests take the edge off: “I wrote code to solve a problem, and now this test I wrote &lt;strong&gt;proves&lt;/strong&gt; that I really solved the problem!”&lt;/p&gt;

&lt;p&gt;It can be a good thing. If the problem matters and the tests actually test the right things then it’s a great thing. But it’s easy to chase that high by writing tests that don’t test the right thing, test something that’s already tested or, worse, pass despite a feature that still doesn’t work correctly.&lt;/p&gt;

&lt;p&gt;Don’t lose sight of your customers in spite of your test coverage.&lt;/p&gt;

&lt;h2 id=&quot;you-fear-failure&quot;&gt;You Fear Failure&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm6.static.flickr.com/5253/5574803627_2129538b6c_m.jpg&quot; alt=&quot;Failing at Failing&quot; title=&quot;Failing at Failing&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The tolerance for failure is probably a lot higher than you imagine; your customer is probably much more forgiving than you (or your boss) think, especially if you &lt;a href=&quot;http://robots.thoughtbot.com/post/4191116705/updates-on-hoptoad&quot;&gt;handle it the right way&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OK, that’s not always true. If you’re engineering the rules for credit card approval, the launch sequence for a missle, or the internals of a pacemaker, most of this post is irrelevant. But if you’re like me, trying to break through to &lt;a href=&quot;http://en.wikipedia.org/wiki/Diffusion_of_innovations&quot;&gt;meaty part of the adoption curve&lt;/a&gt;, then isn’t the ultimate test simply feedback from your users?&lt;/p&gt;

&lt;p&gt;If you think about your product from that perspective code coverage suddenly becomes less important. Are users signing up? Are they coming back? Are they &lt;a href=&quot;http://www.amazon.com/Raving-Fans-Revolutionary-Approach-Customer/dp/0688123163&quot;&gt;raving fans&lt;/a&gt;? Is your product a vitamin or a pain-killer? Make &lt;strong&gt;those&lt;/strong&gt; tests pass.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;90% of coding is debugging. The other 10% is writing bugs&lt;/p&gt;

  &lt;p&gt;– &lt;a href=&quot;http://twitter.com/bramcohen/status/51714087842877440&quot;&gt;@bramcohen&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Show-stopping bugs are easy to prevent. At &lt;a href=&quot;http://www.sqoot.com&quot;&gt;Sqoot&lt;/a&gt; we use a few tools that I consider just as important as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake test&lt;/code&gt;. &lt;a href=&quot;http://github.com/avand/squawk&quot;&gt;Squawk&lt;/a&gt;, a gem I wrote that let’s our app tweet, gives us live feedback (good, bad and ugly). &lt;a href=&quot;http://pingdom.com&quot;&gt;Pingdom&lt;/a&gt; hits our endpoints every minute to ensure uptime. &lt;a href=&quot;http://hoptoadapp.com&quot;&gt;Hoptoad&lt;/a&gt; is invaluable to trap and report on errors.&lt;/p&gt;

&lt;p&gt;So I say release some bugs! The benefit of being 10-20% more nimble over the lifetime of a project totally outweighs the cost of breaking things from time to time.&lt;/p&gt;

&lt;h2 id=&quot;you-slow-down&quot;&gt;You Slow Down&lt;/h2&gt;

&lt;p&gt;No matter how lean and mean you think you are tests are a process and process can slow you down:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Chasing 100% coverage&lt;/strong&gt;: Once you start testing, you don’t want to stop. Untested code becomes a second-class citizen. But that’s fine! Not all code is created equal.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Calcification&lt;/strong&gt;: Deleting code is awesome, but when it’s tested, you think twice. This is especially true when you’re new to a project.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You become the customer&lt;/strong&gt;: Tests are one part of your app where the customers are other developers. It’s easy to get lost in a world of tools and process. Unless you’re GitHub, your product is probably not other developers.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;http://algeri-wong.com/yishan/engineering-management-process.html&quot;&gt;“New process is reluctantly introduced only right before the point where things tip into chaos”&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;– Yishan Wong on Facebook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;now-before-you-roast-me-on-hn&quot;&gt;Now, Before You Roast Me on HN…&lt;/h2&gt;

&lt;p&gt;By this point, I’ve probably ruffled some feathers. So let me be clear that testing isn’t all downside. There are several critical reasons you &lt;strong&gt;have&lt;/strong&gt; to test:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Implementation first thinking&lt;/strong&gt;: When you write tests you end up thinking about how other parts of your application will use that code. This means less refactoring down the line.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Free regression suite&lt;/strong&gt;: Rarely do engineers go back to test untested code, so it’s good to know that the feature you built works now and will forever. This is especially true for teams.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Framing the problem&lt;/strong&gt;: Originally for &lt;a href=&quot;http://piggyback.it/&quot;&gt;PiggyBack.it&lt;/a&gt;, I built some code that balanced debts between a bunch of people. To think about that problem conceptually would have taken me forever to solve. By laying out the expectations first, the solution came naturally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See, even I write tests!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Loaded suite /Users/avand/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..................................................................................................................................................................................................
Finished &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;5.778192 seconds.

194 tests, 290 assertions, 0 failures, 0 errors, 0 skips

Test run options: &lt;span class=&quot;nt&quot;&gt;--seed&lt;/span&gt; 50633
Loaded suite /Users/avand/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..............................................
Finished &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;13.691397 seconds.

46 tests, 56 assertions, 0 failures, 0 errors, 0 skips&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you’re saying to yourself “13 seconds to run 46 tests is slow,” you may want to re-read this post or double-down and check out &lt;a href=&quot;https://github.com/thumblemonks/riot&quot;&gt;riot&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;happy-customers-are-all-that-matters&quot;&gt;Happy Customers are All That Matters&lt;/h2&gt;

&lt;p&gt;I don’t enjoy writing &lt;a href=&quot;http://avandamiri.com/2010/02/08/getting-it-what-makes-a-great-software-engineer.html&quot;&gt;code for code’s sake&lt;/a&gt;. It’s ironic to think you might even evaluate a software engineer by the code he doesn’t write. Coding is fun, it’s addictive and it’s a bit hypnotic. So you have to be really careful that the code you’re writing actually matters!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are you making your customer happier?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the line of code you’re working on doesn’t answer that question with a huge “yes” then you’re probably wasting your time.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Managing Styles with Sass on Heroku</title>
   <link href="http://avandamiri.com/2010/09/15/managing-styles-with-sass-on-heroku.html"/>
   <updated>2010-09-15T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/09/15/managing-styles-with-sass-on-heroku</id>
   <content type="html">&lt;p&gt;I’ve generally found stylesheets to be the messiest part of any website. And I’m not surprised:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Cross browser support means kludgy code&lt;/li&gt;
  &lt;li&gt;Functionality usually takes the drivers seat to well thought out styles&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://video.google.com/videoplay?docid=-4101280286098310645&quot;&gt;It’s someone else’s job&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But organizing styles doesn’t have to be a mess and here’s one strategy that may make your life easier.&lt;/p&gt;

&lt;h2 id=&quot;but-first&quot;&gt;But First…&lt;/h2&gt;

&lt;p&gt;Since &lt;a href=&quot;http://edgeguides.rubyonrails.org/routing.html&quot;&gt;REST&lt;/a&gt; became the de facto way to design &lt;a href=&quot;http://rubyonrails.org&quot;&gt;Rails&lt;/a&gt; apps, I’ve focused on organizing stylesheets by the same patterns. It just seemed natural that if you had a folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/views/users/new.html.erb&lt;/code&gt; you should have a similiar folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/stylesheets/users/new.css&lt;/code&gt;. Back in 2008, I wrote a &lt;a href=&quot;http://avandamiri.com/2008/11/19/css-tricks-2-of-2-using-rails-to-manage-styles.html&quot;&gt;two part post&lt;/a&gt; on how to do this nicely with Rails. Three years later, I’m &lt;a href=&quot;http://2009.windycityrails.org/videos#8&quot;&gt;not the only one&lt;/a&gt; who thinks that this is a decent idea.&lt;/p&gt;

&lt;p&gt;But CSS has grown old and weary and is in desperate need of an &lt;a href=&quot;http://www.css3.info/&quot;&gt;update&lt;/a&gt;. &lt;a href=&quot;http://sass-lang.com&quot;&gt;Sass&lt;/a&gt; is clearly a more expressive way to define styles.&lt;/p&gt;

&lt;p&gt;So, it seemed like a great time to refresh the way I manage styles in my Rails apps.&lt;/p&gt;

&lt;h2 id=&quot;why-start-from-scratch&quot;&gt;Why Start from Scratch?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4124/4994576910_2986eef71b_m_d.jpg&quot; alt=&quot;Beware of Dog&quot; title=&quot;Beware of Dog&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Simply put, this was a pain in the ass. Why was it harder than it should have been?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;I’m masochistic&lt;/strong&gt;: I wanted it to work a certain way. I didn’t want to wrangle with a &lt;a href=&quot;http://compass-style.org/&quot;&gt;bloated framework&lt;/a&gt; or sacrifice on simplicity.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Heroku&lt;/strong&gt;: &lt;a href=&quot;http://www.heroku.com&quot;&gt;Heroku&lt;/a&gt; has a (&lt;a href=&quot;http://docs.heroku.com/constraints#read-only-filesystem&quot;&gt;mostly&lt;/a&gt;) read-only filesystem. &lt;a href=&quot;http://www.hulu.com/watch/19280/saturday-night-live-debbie-downer-birthday-party&quot;&gt;Waaa, waaa!&lt;/a&gt;. Since Sass needs to be compiled, this poses a bit of a problem. There are a &lt;a href=&quot;http://github.com/pedro/hassle&quot;&gt;few workarounds&lt;/a&gt; that involve serving CSS from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt;, but I didn’t want a hack.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Organization&lt;/strong&gt;: I resisted Sass for a long time. I think by just organizing your selectors you can get a lot of the same benefits. My new setup had to have the same clarity.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Packages&lt;/strong&gt;: &lt;a href=&quot;http://developer.yahoo.com/yslow/&quot;&gt;Everyone should know&lt;/a&gt; &lt;a href=&quot;http://code.google.com/speed/page-speed/&quot;&gt;by now&lt;/a&gt; that the HTTP overhead of requesting multiple CSS files degrades client performance. But you can’t just pile them all into one file because you need to separate styles for print, screen, IE, or mobile. This problem &lt;a href=&quot;http://synthesis.sbecker.net/pages/asset_packager&quot;&gt;had a solution&lt;/a&gt;, but not with &lt;a href=&quot;http://docs.heroku.com/git&quot;&gt;Git based deployments&lt;/a&gt; on Heroku and the &lt;a href=&quot;http://github.com/dim/sphere&quot;&gt;Amazon S3 workaround&lt;/a&gt; sounded like trouble.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Javascript&lt;/strong&gt;: Javascript and CSS are very very different. I wanted my solution to organizing styles to inspire the way I manage Javascript, not muddle it up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seriously, it shouldn’t be this god damn complicated.&lt;/p&gt;

&lt;h2 id=&quot;ftw&quot;&gt;FTW!&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Sass&lt;/strong&gt;: I was commited to porting to Sass, specifically because you don’t have to rewrite all your CSS to get started. &lt;a href=&quot;http://sass-lang.com/docs/yardoc/file.SASS_CHANGELOG.html&quot;&gt;Scss plays nice&lt;/a&gt;. It’s part of &lt;a href=&quot;http://haml-lang.com/&quot;&gt;Haml&lt;/a&gt;, so throw it in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;haml&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;3.0.18&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Migrate your CSS to Scss&lt;/strong&gt;: Using the command line tool &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sass-convert&lt;/code&gt; I migrated all my CSS to Scss. I know it needs a lot of refactoring to take advantage of Sass, but I’ll do that later.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; sass-convert source.css destination.scss&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Organize&lt;/strong&gt;: I wanted stylesheet packages to be derived by how styles were organized - not by a configuration file. So while it made sense to have the Sass files live next to my erb (remember, I have a one-to-one mapping of styles to my templates), &lt;a href=&quot;http://chrisjpowers.com/&quot;&gt;Chris Powers&lt;/a&gt; noted that it was cleaner to store them in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app/stylesheets/:package/&lt;/code&gt;. For me, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:package&lt;/code&gt;  was just “desktop.” Later, I can easily create packages called “mobile,” “print,” or “ie” if I need to. See?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4088/4994576870_31e45aceab_d.jpg&quot; alt=&quot;Template and Styles, Happily Ever After&quot; title=&quot;Template and Styles, Happily Ever After&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Use Rack to do all the heavy lifting&lt;/strong&gt;: Compiling Scss isn’t hard. Concatinating all the stylesheets isn’t hard either. &lt;a href=&quot;http://asciicasts.com/episodes/222-rack-in-rails-3&quot;&gt;Ryan Bates’ 222nd Railscast&lt;/a&gt; helped me write a Rack application that does the work:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AssetsApp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Metal&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rendering&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stylesheets&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&apos;&lt;/span&gt;

    &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/app/stylesheets/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/**/*.css*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sass_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:syntax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:scss&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sass_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:compressed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;development?&lt;/span&gt;

      &lt;span class=&quot;vi&quot;&gt;@output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;r&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sass_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Cache-Control&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;public, max-age=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;development?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;text/css&apos;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@output&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Add the route and reference it&lt;/strong&gt;: With Rack doing all the hard work, I just point to it:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Sqoot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/stylesheets/:package.css&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AssetsApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stylesheets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;stylesheets&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheets_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:package&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:desktop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;all-together-now&quot;&gt;All together now!&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Instead of 15-some stylesheets being downloaded at ~50 KB, now I send the client one 8 KB file.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No writing to disk!&lt;/strong&gt; So Heroku’s happy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.varnish-cache.org/&quot;&gt;Varnish&lt;/a&gt;&lt;/strong&gt; leverages HTTP to cache the compiled CSS.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;I can sleep again&lt;/strong&gt; because all my styles are now served in one tight bundle.&lt;/li&gt;
  &lt;li&gt;You get a nice free &lt;a href=&quot;http://gist.github.com/581728&quot;&gt;gist&lt;/a&gt; of the code to try for yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: I presented on the topics of this post at &lt;a href=&quot;http://www.meetup.com/ChicagoRuby&quot;&gt;Chicago Ruby&lt;/a&gt; and &lt;a href=&quot;http://www.refreshchi.org/&quot;&gt;Refresh&lt;/a&gt;. The &lt;a href=&quot;http://ontwik.com/javascript/simple-javascript-css-management-with-rack-by-avand-amiri/&quot;&gt;video&lt;/a&gt; and &lt;a href=&quot;http://avandamiri.com/slides/css-js-rack.html&quot;&gt;slides&lt;/a&gt; are now available online. (May 1st, 2011)&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Four Hour Sprint</title>
   <link href="http://avandamiri.com/2010/09/08/four-hour-sprints.html"/>
   <updated>2010-09-08T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/09/08/four-hour-sprints</id>
   <content type="html">&lt;p&gt;If you want to talk about themes that have dominated the last year of my life, “agile” has got to be one of the most popular. It seems that everyone wants to be agile, and there’s a lot of debate about what that means, &lt;a href=&quot;http://www.whattofix.com/blog/archives/2010/09/agile-ruined-my.php&quot;&gt;if anything&lt;/a&gt;. &lt;a href=&quot;http://agilemanifesto.org/&quot;&gt;Agile software development&lt;/a&gt; is a group of software development methodologies that are based on iterative and incremental development. It comes in a variety of flavors, the most popular being &lt;a href=&quot;http://en.wikipedia.org/wiki/Scrum_(development)&quot;&gt;Scrum&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re familiar with Scrum you know the common traits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Release often: Success if based on shipping working product.&lt;/li&gt;
  &lt;li&gt;Don’t release crap: Trim back the features and release something that works well, both for you and your customer.&lt;/li&gt;
  &lt;li&gt;Iterate: This week you’ll do X, next week you’ll do Y, even if that means undoing X.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mechanics of a successful agile team vary, commonly differentiated by the length of a sprint or iteration. After much tweaking I’ve found that the shorter the sprint the better. I’m currently working in four-hour sprints and here’s why you should too.&lt;/p&gt;

&lt;h2 id=&quot;incedental-reasons&quot;&gt;Incedental Reasons&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Four hours is about the amount of time you can spend in Starbucks without your ass going numb.&lt;/li&gt;
  &lt;li&gt;Four hours is about the amount of time you can actually focus. Hunger is usually my biggest distraction.&lt;/li&gt;
  &lt;li&gt;Four hours is about the amount of time your laptop battery will last without re-charging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;for-realzy-reasons&quot;&gt;For Realzy Reasons&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4154/4967913623_fd4868b07c_m_d.jpg&quot; alt=&quot;4 Hour Timer&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You have to manage scope: When you measure your sprints in hours - not days - you have no choice but to seriously question the scope of what you’re doing. You have to ship something! So, get your shit together.&lt;/li&gt;
  &lt;li&gt;You can’t write garbage code: Let’s face it, how much damage can you do to a codebase in four hours? If tests have to pass and a deployment has to happen you just don’t have time to fuck around.&lt;/li&gt;
  &lt;li&gt;You’ll get realistic: &lt;a href=&quot;http://gettingreal.37signals.com/ch03_Embrace_Constraints.php&quot;&gt;Constraints breed creativity&lt;/a&gt;. You’ll come up with &lt;a href=&quot;http://bit.ly/RAHz2P&quot;&gt;incredible solutions&lt;/a&gt; to deliver on your deadline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know, this won’t work for everyone. I’ve worked on projects where simply deploying was a four hour task in and of itself! That’s garbage. If this is you, put “&lt;a href=&quot;http://heroku.com&quot;&gt;make deployments easy&lt;/a&gt;” at the top of your to-do list. Maybe your part of a bigger team, where coordinating deployments can get tricky. Work towards building a team of &lt;a href=&quot;http://nvie.com/git-model&quot;&gt;branching ninjas&lt;/a&gt; that can compartmentalize features and releases.&lt;/p&gt;

&lt;p&gt;We’re very simple creatures. Most projects, probably the one you’re working on right now, go over budget and over time. That’s because, as humans, we grossly overestimate what we’re capable of actually accomplishing. Don’t fight it! &lt;a href=&quot;http://en.wikipedia.org/wiki/Getting_Things_Done&quot;&gt;Break things down into chunks&lt;/a&gt; you can actually handle.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>School's Out Forever</title>
   <link href="http://avandamiri.com/2010/02/17/schools-out-forever.html"/>
   <updated>2010-02-17T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/02/17/schools-out-forever</id>
   <content type="html">&lt;p&gt;Growing up, I was told that the most important ingredient for my future was an education. Do your homework, study hard and the road ahead will lead to a satisfying career and financial security. That was the promise, anyway. But as it turns out, in the kitchen of education, I cooked up concoction that would make even &lt;a href=&quot;http://www.travelchannel.com/TV_Shows/Bizarre_Foods&quot;&gt;Andrew Zimmern&lt;/a&gt; cringe.&lt;/p&gt;

&lt;p&gt;I went to high school at &lt;a href=&quot;http://www.bu.edu/academy&quot;&gt;Boston University Academy&lt;/a&gt;, a prep-school that essentially guaranteed a fast track through college if you just played by the book. I didn’t play by the book. In tenth grade I was held back and junior year wasn’t any more promising. My teachers begged me to study, explaining to my parents that I just wasn’t applying myself. On the night of my last and deciding final of 11th grade, I sealed my fate watching a Seinfeld marathon. Clearly, getting through high school was going to be more trouble than it was worth.&lt;/p&gt;

&lt;p&gt;When I came back from camp that summer, I was shipped to Chicago and the very next morning, in slacks, shirt and tie, reported for an internship at a financial company in the Loop. It was a complete correction of my downward spiral and the beginning of my career as a software engineer. I completed my GED and started taking night classes at &lt;a href=&quot;http://www.depaul.edu&quot;&gt;DePaul&lt;/a&gt;. By my sophomore year, I was in the top of my class.&lt;/p&gt;

&lt;p&gt;Everything seemed copacetic until I dropped out.&lt;/p&gt;

&lt;h2 id=&quot;when-school-works&quot;&gt;When School Works&lt;/h2&gt;

&lt;p&gt;It was an issue of motivation. When I’m told to do something, I ask why. If I don’t like the answer, I push back, and, depending on my conviction, will eventually just refuse. Turns out that up until college you don’t have much say in what you learn. Ask why and eventually the answer boils down: you don’t have choice.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2753/4365864058_9e9068b030_o.jpg&quot; title=&quot;Stubborn as an...&quot; alt=&quot;Ox&quot; class=&quot;left&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I think that’s bullshit. A lot of what I was told to learn was, in retrospect, totally practical. Study a language and you’re given the power of self-expression. The sciences teach you how to manipulate the world around you. History explores human behavior, geography and politics. These are the types of answers that may have satiated my interrogation of academia and could have motivated my intellectual curiosity.&lt;/p&gt;

&lt;p&gt;But reflecting on all the classes I’ve ever taken, there were many that were just arbitrarily required. Especially at $190/credit, it makes sense to keep you in class. School works when a student is motivated and motivation is fueled by purpose.&lt;/p&gt;

&lt;h2 id=&quot;when-it-doesnt&quot;&gt;When It Doesn’t&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2748/4365864084_dc06d529c8_o.jpg&quot; alt=&quot;Swiss Army Knife&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When I started working, the paradigm completely changed. Now, I was motivated by a paycheck, a career, and my peers. I enjoyed what I was doing and was solving real world problems. Everything I did became practical (although often equally pointless).&lt;/p&gt;

&lt;p&gt;It made sense to start taking classes again with this new found motivation and focus. I would spend two nights a week at DePaul, hacking away at a Computer Science degree. I was learning a lot but at a price.&lt;/p&gt;

&lt;p&gt;In the age of information, where a good (free) search can yield more about a topic than you can learn in an entire academic career, that becomes a steep sacrifice. Then there’s opportunity cost. My classes ate into precious time I would otherwise spend learning on my own projects. With no other obligations and boundless energy, these years are quite arguably the most valuable of my life.&lt;/p&gt;

&lt;p&gt;By the time my peers graduated, I had 4 years of work experience and was cashing in on it. I had come out ahead. I’ve never had a career opportunity jeopardized by an incomplete degree and I’m humbly optimistic that it never will.&lt;/p&gt;

&lt;h2 id=&quot;get-real&quot;&gt;Get Real&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4005/4365121309_896682da2c_o.jpg&quot; alt=&quot;Diploma&quot; class=&quot;left&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ask ten people in your office what their degree is in and I bet at least half of them admit to something completely irrelevant to their job. Now ask them if they’re really passionate about what they do.&lt;/p&gt;

&lt;p&gt;What if they had spent their four college years doing internships, traveling and searching the world for a calling that really fires them up? What if they had taken the fifty grand (or more) it took to graduate and had instead started a business, or two, or three? What if high school was an accelerated 3-year program followed by a 1 year intensive “real-life lessons” program covering topics like real estate, incorporation, financial management, insurance and law?&lt;/p&gt;

&lt;p&gt;Of the four-man engineer team I was last a part of, only one had a degree and was, fittingly, the weakest member of the team. That’s how it works in the world of software. It should work for other fields, too.&lt;/p&gt;

&lt;p&gt;There’s a lot of great things out there to learn, but theory is one thing and practice is another.&lt;/p&gt;

&lt;h2 id=&quot;what-about-you&quot;&gt;What About You?&lt;/h2&gt;

&lt;iframe height=&quot;250&quot; allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;width:100%;border:none&quot; src=&quot;http://avand.wufoo.com/embed/r7x3p9/&quot;&gt;&lt;a href=&quot;http://avand.wufoo.com/forms/r7x3p9/&quot; title=&quot;Schooling Survey&quot; rel=&quot;nofollow&quot;&gt;Fill out my Wufoo form!&lt;/a&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;update-august-1st-2010&quot;&gt;Update (August 1st, 2010)&lt;/h2&gt;

&lt;p&gt;Since writing, I’ve found several articles regarding the flaws in the academic system. &lt;a href=&quot;http://www.martynemko.com&quot;&gt;Marty Nemko&lt;/a&gt; of U.S. News describes one’s undergraduate education as &lt;a href=&quot;http://bit.ly/arKigs&quot;&gt;America’s most overrated product&lt;/a&gt;. I thought it was worth highlighting some of my favorite points:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“What percent of students would you guess graduate from college within six years? Forty percent. Six out of ten never graduate.”&lt;/li&gt;
  &lt;li&gt;On the social value of attending university: “Fact: 27% of all undergraduate students binge drink regularly”&lt;/li&gt;
  &lt;li&gt;“We need to capitalize on students’ desire to learn what they’re excited about and motivated to learn at that point in time. When kids are at eighteen or twenty, they’re at their most idealistic. It’s a great time to teach them about things that are going to foment that idealism. It’s a great time to teach them about relationships. It’s a great time to teach them about careers.”&lt;/li&gt;
  &lt;li&gt;“Colleges produce a shoddy, overpriced product and it’s time we held them accountable.”&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Getting It: What Makes a Great Software Engineer</title>
   <link href="http://avandamiri.com/2010/02/08/getting-it-what-makes-a-great-software-engineer.html"/>
   <updated>2010-02-08T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/02/08/getting-it-what-makes-a-great-software-engineer</id>
   <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I’ve been writing code for a while now and for about the last 2 years
there’s been a nagging question in the back of my head:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes a great software engineer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Call them “rockstars”, “ninjas”, “submarine pilots” or any other catchy
title you’d like. They exist, and they’re dangerously good at what they
do. Let’s emphasize &lt;em&gt;dangerous&lt;/em&gt; there, because right next to them is a
second bucket. You’ve probably hired them, or worked with them - there
might be one sitting right behind you. These guys know what they’re doing
but seem to be lacking something; somehow, everything they work on seems
incomplete.&lt;/p&gt;

&lt;p&gt;For lack of better semantics, my friend &lt;a href=&quot;http://michaeldwan.com&quot;&gt;Michael Dwan&lt;/a&gt; and I have always
said that the ninjas just “get it.” In suit, I think it makes sense to
refer to them, collectively, as the “get-its” and the latter as the
“get-nots.”&lt;/p&gt;

&lt;h2 id=&quot;wait-why-engineer&quot;&gt;Wait, Why Engineer?&lt;/h2&gt;

&lt;p&gt;engineer |ˌenjəˈni(ə)r|, noun: a person who designs, builds, or maintains
engines, machines, or public works.&lt;/p&gt;

&lt;p&gt;After reviewing the attributes I identified that make up a great software
engineer, I realized that they are in many ways common to all engineers.
And although software is my trade, I thought that abstraction warranted
exploring.&lt;/p&gt;

&lt;h2 id=&quot;code-for-codes-sake&quot;&gt;Code for Codes Sake&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2803/4338747142_58cd9768e3_o.png&quot; class=&quot;left&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Car analogies work really well to conversationally describe software
applications, but I’m going to use the metaphor of a carpenter to describe
our quintessential developer.&lt;/p&gt;

&lt;p&gt;Initially, you have your newbie, who barely knows how to
&lt;a href=&quot;http://www.wikihow.com/Use-a-Hammer-Safely&quot;&gt;hold a hammer properly&lt;/a&gt;. If you told him to build a house, he’d have
no choice but to defer. But an experienced carpenter, someone whose built a
few houses in his day, would be comfortable taking up a spot behind the
table saw and getting right to it.&lt;/p&gt;

&lt;p&gt;But there’s a third category - let’s call him “qualified.” He’s just as
comfortable as the expert behind the table saw. But he doesn’t quite get it.
He lacks the mastery of the expert and as a result mis-measures, recuts,
rebuilds, and so on until he’s got his shoddy house standing.&lt;/p&gt;

&lt;p&gt;Software is exactly the same - only worse. It’s &lt;em&gt;way&lt;/em&gt; easier to type
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails superfluous-app&lt;/code&gt; than to fire up the saw and cut a piece of wood.
And there’s a lot of get-not’s in the workshop, just keystrokes away from
leaving 100’s of lines of scraps strewn about the floor.&lt;/p&gt;

&lt;p&gt;The master knows that the best cut is no cut.&lt;/p&gt;

&lt;h2 id=&quot;drawing-a-line-between-done-and-done-right&quot;&gt;Drawing a Line Between Done and Done Right&lt;/h2&gt;

&lt;object width=&quot;384&quot; height=&quot;222&quot; class=&quot;right&quot;&gt;
  &lt;param name=&quot;movie&quot; value=&quot;http://www.hulu.com/embed/0trVsm_OdEX0qitmGaa_xg/i114&quot; /&gt;&amp;lt;/param&amp;gt;
  &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&amp;lt;/param&amp;gt;
  &lt;embed src=&quot;http://www.hulu.com/embed/0trVsm_OdEX0qitmGaa_xg/i114&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; width=&quot;384&quot; height=&quot;222&quot; /&gt;&amp;lt;/embed&amp;gt;
&lt;/object&gt;

&lt;p&gt;Now you’ve got your house built. Maybe it looks a bit like Ned’s after the
Simpson’s neighborhood chips in and rebuilds it, but hey, at least it’s standing.&lt;/p&gt;

&lt;p&gt;As with the carpenter, a software engineer can fall anywhere on the skill
ladder. Just go to your local Borders and spend a minute walking down the
“Computers” aisle. There’s no shortage of well written, opinionated instructions
on how to write code.&lt;/p&gt;

&lt;p&gt;This is where many of the get-nots thrive. They’ve got a site up, but instead
improving the experience, they migrate databases. They boast that their application
has 100% test coverage, but it’s not live. Their server clusters are capable of
handling gagillions of requests per second, yet actually respond a few times per day.&lt;/p&gt;

&lt;p&gt;The get-its, in contrast, focus on the finished product. A get-it will
systematically and holistically tackle each problem in the way of that goal,
tactfully &lt;a href=&quot;http://gettingreal.37signals.com/ch03_Embrace_Constraints.php&quot;&gt;embracing the constraints&lt;/a&gt; and imperfections along the way.&lt;/p&gt;

&lt;h2 id=&quot;changing-the-future&quot;&gt;Changing the Future&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4040/4334975797_b83fb49cab_o.png&quot; class=&quot;left&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Think about the last time you saw a master at work. Someone that’s just qualified
goes through often obvious and intuitive steps to get the end goal. But the masters
ways are much more enigmatic, maybe skipping steps or starting with something that
seems like it logically belongs at the end.&lt;/p&gt;

&lt;p&gt;That’s how the get-its work. They’ll read a simple feature request and think through
the ramifications it has on the whole project. A get-it will think through a problem
and solve it quickly with an eye for what else is going on and what might be soon to
come. I read somewhere that the most successful people don’t manage their time, but
their priorities. A get-it can always answer the question: what is the next most
important thing?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2762/4334835361_205d573287_m.jpg&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Get-its don’t just challenge the products their working on. They also challenge their
tools. If it sucks, they build a new one. If they don’t like the way so-and-so library
handles bla-bla-bla, they make it better and then share it with their peers. They’ve
got their heads up, listening to other get-its, and are always a little uncomfortable
because they understand that the only definite is that something’s about to change.
The best of them are the catalyst for that change.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Integrating Twitter Authentication with Rails</title>
   <link href="http://avandamiri.com/2010/01/13/integrating-twitter-authentication-with-rails.html"/>
   <updated>2010-01-13T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/01/13/integrating-twitter-authentication-with-rails</id>
   <content type="html">&lt;p&gt;I’m working on a project called &lt;a href=&quot;http://piggyback.it/&quot; title=&quot;Piggy Back&quot;&gt;Piggy Back&lt;/a&gt;, a simple service where friends can keep track of debts between one another. To encourage user registration, I’m lowering the barriers, allowing users to sign up their &lt;a href=&quot;http://twitter.com&quot; title=&quot;Twitter&quot;&gt;Twitter&lt;/a&gt; and &lt;a href=&quot;http://facebook.com&quot; title=&quot;Facebook&quot;&gt;Facebook&lt;/a&gt; accounts. I’d like share with you how I got this functionality into this Rails app. A shout out to &lt;a href=&quot;http://twitter.com/chrisjpowers&quot;&gt;Chris Powers&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/nevernormal1&quot;&gt;Jeff Talbot&lt;/a&gt; for their feedback along the way.&lt;/p&gt;

&lt;h2 id=&quot;eliminating-plugin-magic&quot;&gt;Eliminating Plugin Magic&lt;/h2&gt;

&lt;p&gt;I needed to get my hands into the authentication code if I was going to allow Twitter and Facebook integration. I was using &lt;a href=&quot;http://github.com/binarylogic/authlogic/&quot; title=&quot;GitHub: binarylogic/authlogic&quot;&gt;Authlogic&lt;/a&gt; and could have extended it with other plugins to give me this support, but I wanted the process for my users to be as seamless as possible. I knew this would probably involve some Piggy Back specific customizations.&lt;/p&gt;

&lt;p&gt;Furthermore, I was actually only using about 20% of the functionality Authlogic provides. I had “magic columns” (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_logged_in_at&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;failed_login_count&lt;/code&gt;, etc.) because they were free, but I didn’t actually need them.&lt;/p&gt;

&lt;p&gt;Finally, making it possible for users to sign up with their Twitter accounts meant a user record with no email or password, fields &lt;a href=&quot;http://github.com/binarylogic/authlogic/&quot; title=&quot;GitHub: binarylogic/authlogic&quot;&gt;Authlogic&lt;/a&gt; required. There were likely workarounds available, but that meant hacking &lt;a href=&quot;http://github.com/binarylogic/authlogic/&quot; title=&quot;GitHub: binarylogic/authlogic&quot;&gt;Authlogic&lt;/a&gt;, not working on my app.&lt;/p&gt;

&lt;h2 id=&quot;hand-rolling-authentication&quot;&gt;Hand Rolling Authentication&lt;/h2&gt;

&lt;p&gt;Authentication isn’t complicated. I liberated the heavy lifting cryptography algorithms from Authlogic. Obviously, it was important for me to use the exact same algorithm in my own system. Then I got inspired with &lt;a href=&quot;http://github.com/jamis/bucketwise&quot;&gt;Jamis Buck’s Bucketwise project&lt;/a&gt; and prepped my user to be authenticated.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://gist.github.com/276329&quot; title=&quot;GitHub Gist: Hand Rolled Authentication&quot;&gt;See the code!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authlogic encourages you to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserSession&lt;/code&gt; model which lends itself to restful design, but I found it much easier to just create two actions on my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SiteController&lt;/code&gt; that simply responded to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; requests. Originally, I had used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require_authentication&lt;/code&gt; as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_filter&lt;/code&gt;, so I ported those over to the new system as well. Check it all out in the &lt;a href=&quot;http://gist.github.com/276329&quot; title=&quot;GitHub Gist: Hand Rolled Authentication&quot;&gt;gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;now-lets-get-twitter-up-in-there&quot;&gt;Now, Let’s Get Twitter Up in There!&lt;/h2&gt;

&lt;p&gt;Twitter supports &lt;a href=&quot;http://oauth.net&quot;&gt;OAuth&lt;/a&gt; authentication. It’s a little trickier to implement than basic HTTP authentication, but isn’t terribly complicated. Your application, the consumer, gets a couple tokens, which you exchange for request tokens. Then you use the request tokens to do what you will with Twitter, including obtaining access tokens to, well, access users accounts.&lt;/p&gt;

&lt;p&gt;There’s a lot that OAuth does and I wasn’t prepared to start from scratch, so I installed the &lt;a href=&quot;http://oauth.rubyforge.org/&quot;&gt;oauth Ruby gem&lt;/a&gt; and included it into my application. I also added 4 columns to my users table to store the Twitter information, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter_id&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter_handle&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter_token&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter_secret&lt;/code&gt;. My user validation rules adapted to this change to, permitting users without emails or passwords in favor of these attributes.&lt;/p&gt;

&lt;p&gt;You need two actions to support Twitter OAuth. One to start the request and the other, known as the callback, to finish it. In examples, these actions are nestled in among other controllers, but I decided for clarity to create a standalone &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TwitterController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It’s a bit too large to embed here, but you can still &lt;a href=&quot;http://gist.github.com/276329#file_twitter_controller.rb&quot; title=&quot;GitHub Gist: TwitterController&quot;&gt;take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TwitterController&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The trickiest part was actually making the workflow seamless for all the users. I’m referencing comments in the &lt;a href=&quot;http://gist.github.com/276329#file_twitter_controller.rb&quot; title=&quot;GitHub Gist: TwitterController&quot;&gt;TwitterController&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;A new users comes to Piggy Back and creates an account by logging in to Twitter. (C)&lt;/li&gt;
  &lt;li&gt;An existing user comes back to Piggy Back and logs in via Twitter, but:&lt;/li&gt;
  &lt;li&gt;Piggy Back doesn’t now about their Twitter account and the two must be linked (B) or&lt;/li&gt;
  &lt;li&gt;Piggy Back knows about their Twitter account and logs them in (A).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To get this split behavior, I simply altered the callback URL that Twitter uses to return flow back to the application. This was simple enough with two named routes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user_action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;create&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;twitter_map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;twitter_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;twitter_oauth&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/twitter/oath/:user_action&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:twitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:oauth&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;twitter_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;twitter_callback&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/twitter/callback/:user_action&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:twitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:callback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To handle the case where accounts may be linked, I store the users Twitter attributes in session for a moment, while I redirect to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SiteController#login&lt;/code&gt; action. Here, the user is asked to login specifically to link their account to Twitter. Jeff Talbot offered great feedback about this workflow, suggesting that anywhere there’s a “Sign in with Twitter” link, it should just seamless create a users account. This creates a problem for existing users, however, where they could easily end up with two accounts. To solve this, I’m adding a big button to this login page, “Don’t Have an Account, Create One Instantly.”&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So many web apps need to do exactly what I spent Monday doing, so hopefully you can reuse some of the strategies I implemented here.&lt;/p&gt;

&lt;p&gt;Chris Powers asked if I thought this could be pulled out into a plugin, and I’m sure the answer is yes. However, it’s not a lot of code and there’s a lot of customizations your app will need within the areas I commented out. I’m not a control freak (I did, after all, convert from C# and ASP.net), but I do believe there is value in controlling your apps code.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://github.com/jnunemaker/twitter/&quot;&gt;jnunemaker/twitter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://github.com/tardate/rails-twitter-oauth-sample/&quot;&gt;tardate/rails-twitter-oauth-sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Instantly Losing a Customer</title>
   <link href="http://avandamiri.com/2010/01/11/instantly-losing-a-customer.html"/>
   <updated>2010-01-11T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2010/01/11/instantly-losing-a-customer</id>
   <content type="html">&lt;p&gt;A while ago, I wrote a &lt;a href=&quot;/2009/06/08/the-pursuit-of-happiness-through-outstanding-customer-service.html&quot;&gt;post about great customer service&lt;/a&gt;, where it’s coming from and where to find more of it. Today, I’d like to take a look in the other direction and talk about the biggest mistake a business can make: losing a customer.&lt;/p&gt;

&lt;p&gt;I’ve used 1-800-flowers.com for several orders over the past few years. Although the majority of the orders were unfulfilled or late, I sympathized with the company’s position. They’re stuck as the liaison between me, the over expecting customer, and any number of questionable florists. Every time there was an error, I was able to get my money back, although I often had to fight for it. I would never expect them to get every order right, but as you’ve probably experienced, it’s so easy to win back a customer whose had a bad experience with stellar customer service. 1-800-flowers.com certainly left something to be desired.&lt;/p&gt;

&lt;p&gt;I wasn’t planning on using them again. I’m single now, so I have no immediate floral emergencies. But today, I’m vowing to never again use their service, no matter how long I’m in the dog house. Today, marks the decisive end of my business with 1-800-flowers.com. Today, they crossed the line between business and consumer that I once thought was far less demarcated. Today, I received this in the mail:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4061/4266183499_82010da51a.jpg&quot; alt=&quot;Scam Letter&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At first, I thought, interesting, perhaps they caught an error in the last transaction I had with them and were sending me, much to my surprise and satisfaction, a check to correct the error. I opened it, still skeptical that it was likely a scam, yet was lured even further into believing they were in fact sending me cash. For all intents and purposes it looked exactly like a real check. And it was. Except that when you deposit this check you’re actually purchasing a membership. To make matters worse, it’s a membership in a 1-800-flowers.com &lt;em&gt;affiliate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2714/4266944920_e73bb25483_o.png&quot; alt=&quot;Fine Print&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I was appalled. I don’t expect stellar customer service from every company, but this absolutely crosses an ethical boundary. My mother often calls me to ask how she can claim her prize for being the 1,000,000 visitor to a website. If she had received this piece of mail, she would have cashed that check. There’s no way she would have caught the fine print, or would have even been able to read it.&lt;/p&gt;

&lt;p&gt;The poor service and lack of customer care I can tolerate - maybe even expect - but this is the first customer interaction I’ve ever witnessed that &lt;em&gt;proactively&lt;/em&gt; lost a customer.&lt;/p&gt;

&lt;p&gt;Often the line is not so clear. Take, for instance, the placement of ads on a website. Most consumers have come to tolerate a moderate amount of advertising in their lives. Ads often do pay for the subsistence of many sites on the web. But it’s crucial to constantly ask: does what I’m doing make the life of my customer better. Forget about how much you can get away with. Certainly dismiss any idea that could possibly drive a customer away!&lt;/p&gt;

&lt;p&gt;It’s a honor that your existing customers even work with you! Appreciate their contribution to your business and rather than kill the golden goose, focus on getting the next one.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Big Bang Rewrite (Part 3): Authentication, Authorization, and Tests</title>
   <link href="http://avandamiri.com/2009/12/20/the-big-bang-rewrite-part-3-auth.html"/>
   <updated>2009-12-20T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/12/20/the-big-bang-rewrite-part-3-auth</id>
   <content type="html">&lt;p&gt;One of the biggest deficiencies in the old application was being able to lock down access to the site based on users. Originally, there were two special users, Admin and Guest. The former had complete control, the later had none. Anyone else was a normal user and had the same level of access.&lt;/p&gt;

&lt;p&gt;Since we have an opportunity to build this right from the ground up, we explored 3 levels of access control:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Authentication: Actions behind this layer of protection, first, require a user to be authenticated.&lt;/li&gt;
  &lt;li&gt;Authorization: These actions assume a user has been authenticated but determine whether they have access to perform the requested actions.&lt;/li&gt;
  &lt;li&gt;Permissions: Assuming the first two layers pass, does the current user have permission to perform that action to that object?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ll go into the details of each section, then describe our testing strategy.&lt;/p&gt;

&lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;/h2&gt;

&lt;p&gt;Step one: plug in Authlogic. This did a huge majority of the heavy lifting for us to ensure that a user session was persisted request to request.&lt;/p&gt;

&lt;p&gt;Let’s take a look at some of the helpers in our base controller, ApplicationController:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;require_authentication&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Exceptions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Security&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AuthenticationRequired&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenticated?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authenticated?&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Our custom exception &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Exceptions::Security::AuthenticationRequired&lt;/code&gt; is systematically caught and returns a HTTP 401. Piece of cake. To lock down a controller now, we simply add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_filter&lt;/code&gt; to the actions we’d like restricted to users that are logged in.&lt;/p&gt;

&lt;h2 id=&quot;authorization&quot;&gt;Authorization&lt;/h2&gt;

&lt;p&gt;Authentication was easy, but now that we know we have a user, should they be able to hit that action? To the end user, or a business analyst these may seem like the same question, but as a developer I think it makes sense to separate the concerns.&lt;/p&gt;

&lt;p&gt;Because we followed REST conventions in this application, the abstraction for authorization was self apparent: restrict access on a controller/action basis. So we created roles which stored sets of controller action pairs. Then add another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_filter&lt;/code&gt; just like only a bit different than our authentication layer.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;require_authorization&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Exceptions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Security&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AuthorizationRequired&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authorized?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authorized?&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# authorized_for just checks to see if that key value pair exists for that user based on their role&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;authorized_for?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;controller_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;action_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Just like authentication, we add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_filter&lt;/code&gt; and catch the AuthorizationRequired exception, returning a HTTP 403 response to the client.&lt;/p&gt;

&lt;h2 id=&quot;permissions&quot;&gt;Permissions&lt;/h2&gt;

&lt;p&gt;Our entire authorization system now covers us up to the controller action. But there’s still one more step. Does that user have permission to do that action &lt;em&gt;on a particular object&lt;/em&gt;. In our case, can a user edit a specific business?&lt;/p&gt;

&lt;p&gt;What we have actually looks a lot like &lt;a href=&quot;http://github.com/ryanb/cancan&quot;&gt;Ryan Bate’s CanCan plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;

&lt;p&gt;My feelings on testing are a subject for another discussion, but in a nutshell, I believe it’s crucially important to test permissions. I think the reasons are obvious. But testing permissions can be a real pain in the neck.&lt;/p&gt;

&lt;p&gt;We use Shoulda to assist our testing process for two reasons. Firstly, we enjoy the dry-ness and organization of contexts. Beyond organization, however, the macros allow your tests to be very expressive while staying super clean - this is especially true of controllers. As you can see in the samples below, however, we avoid the stresses surrounding assertion readability with breadcrumbs (e.g. a User unit test might read, “validations &amp;gt; first_name”).&lt;/p&gt;

&lt;p&gt;As discussed above, each user belongs to a role. To satisfy our authorization layer, a role then specifies which controllers and actions may be accessed. So we need to be able to systematically hit all the controllers and actions that require authorization with each role and assert the appropriate behavior.&lt;/p&gt;

&lt;p&gt;This could easily get out of hand:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsersControllerTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TestCase&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;GET to show &amp;gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;as an admin &amp;gt;&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;login_as&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:show&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
      &lt;span class=&quot;n&quot;&gt;should_do_all_sorts_of_great_stuff&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;as a business owner &amp;gt;&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;login_as&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:business_owner&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:show&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
      &lt;span class=&quot;n&quot;&gt;should_do_all_sorts_of_great_stuff&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There’s a few issues here. First of all, there’s a lot of duplication. More importantly, we duplicate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt;, which is really a common procedure to all these tests. Secondly, we’re retesting that this action &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;should_do_all_sorts_of_great_stuff&lt;/code&gt; and binding those assertions to the setup of the test. Gross.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionController/Macros.html&quot;&gt;Shoulda controller macros&lt;/a&gt; encourage you to avoid duplicating the setup block over and over again, so I dove into creating a custom macro, designing it by implementation first:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsersControllerTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TestCase&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;GET to show &amp;gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;login&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:show&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;should_authenticate&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;should_authorize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:business_owner&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;should_do_all_sorts_of_great_stuff&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, much better! But how to make that work?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ActionController::TestCase&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;should_authenticate&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;authenticate&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;assert_response&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:unauthorized&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;should_authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;role_names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;role_names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;role_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;authorize &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;role_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;role_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;response_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:forbidden&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Very cool, but if you’ve been paying close attention there’s one more method I haven’t touched on yet, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login&lt;/code&gt;. Let’s take a look at the test_helper.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@skip_next_login&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require_authentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require_authorization&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stubs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:role_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@skip_next_login&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This helper is probably the most robust part of the entire test. If you pass nothing in, as we do in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup&lt;/code&gt; block, it will simply fake it. This is great because the assertions become oblivious to the authorization mechanism. Sweet. But the authentication and authorization assertions do care, so we give ourselves the option to login as a specified role. Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;should&lt;/code&gt; blocks utilize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:before&lt;/code&gt; option to perform the login before anything else happens. Importantly, though, it sets a flag so the second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login&lt;/code&gt; call (the one in the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup&lt;/code&gt; block) doesn’t then screw things up.&lt;/p&gt;

&lt;p&gt;Go back to &lt;a href=&quot;/2009-12-07-the-big-bang-rewrite-first-ask-why.html&quot;&gt;part one&lt;/a&gt; or &lt;a href=&quot;/2009/12/13/the-big-bang-rewrite-part-2-api-first.html&quot;&gt;two&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Big Bang Rewrite (Part 2): API First</title>
   <link href="http://avandamiri.com/2009/12/13/the-big-bang-rewrite-part-2-api-first.html"/>
   <updated>2009-12-13T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/12/13/the-big-bang-rewrite-part-2-api-first</id>
   <content type="html">&lt;p&gt;As I discussed in my &lt;a href=&quot;/2009-12-07-the-big-bang-rewrite-first-ask-why.html&quot;&gt;previous post&lt;/a&gt;, rebuilding Fave was motivated entirely by the desire for better data. The core focus was not rapid front facing development, but almost entirely back end work. In essence, we started with our API.&lt;/p&gt;

&lt;p&gt;One of the features Rails boasts as an application framework is that out of the box, it lends itself to API support. Every controller/action that is generated includes responses for XML based requests. I would challenge most applications to try and publicize an API using the default Rails setup. It’s likely not even close to the end result you’d expect. But that’s OK - no application framework should satisfy that expectation.&lt;/p&gt;

&lt;p&gt;At first, our API, was &lt;code&gt;script/console&lt;/code&gt;. But, of course, that only got us so far. With our new data model, objects that used to be represented as one were now two three or four different objects. We had normalized our data - aware of the penalties and overhead that would haunt us along the way.&lt;/p&gt;

&lt;p&gt;As a result of this normalization, we make heavy use of virtual attributes. It had to be possible to create a Business with one HTTP POST. Phone numbers on businesses, for example, work like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Business&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_writer&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:phone_numbers_attributes&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# [{ :area_code =&amp;gt; 312, :exchange =&amp;gt; 123, :suffix =&amp;gt; 3333 }, ...]&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;before_validation&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:set_phone_numbers_from_virtual_attribute&lt;/span&gt;
  
  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_phone_numbers_from_virtual_attribute&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@phone_numbers_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phone_number_attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone_numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PhoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phone_number_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@phone_numbers_attributes&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In some places take advantage of &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt;, however, we found it wouldn’t play nicely with polymorphic associations and were uncomfortable with unknowns it introduced. We’ve found it’s best to write it yourself first, then find abstractions and helpers on a need by need basis.&lt;/p&gt;

&lt;p&gt;The controllers, all the meanwhile, have remained “skinny” in spite of complexity. We’ve rigorously moved logic down into the model layer so that the various security components would be the only core responsibility for the controllers. I will go into detail with our approach to security in the next post.&lt;/p&gt;

&lt;p&gt;We needed to get data into the application as quickly as possible. As a result, we spent time on an application to simply wrap up the HTTP side of things. It enabled us to create a hash on one end that represented the structure we desired, make the post to the server, and end up with a usable object on the other end. In some ways it is a lot like ActiveResource, and in fact we made enormous progress simply using ActiveResource. But again, our needs grew.&lt;/p&gt;

&lt;p&gt;For the longest time, the views of the new site were simply a wrapper to the API. The majority of the teams effort was building the API and other scripts/applications that consumed it. This made for quite a refreshing approach to views, which I’ll discuss in more detail in a later post. The API had forced us to think about what data inputs and outputs were core to the application. It satisfied all the application’s needs first. We no longer had to include messy scripts into our application that relied on directly interfacing with our models to import data. Everything consumed the API. Even the views simply consumed that core data.&lt;/p&gt;

&lt;p&gt;All things considered, the API first approach is not one I would recommend to everyone. At Fave, our data is completely core to our business and as a result it seemed appropriate and has paid us in dividends. A site like &lt;a href=&quot;http://piggyback.it&quot;&gt;Piggy Back&lt;/a&gt; has far simpler data structures with the user interface demanding much more focus. In this case an “API first” approach would likely be the wrong choice. Although even there I will note that through the process of making the interface more accessible, for example from an iPhone or mobile device, I was forced to clean up my controller and think harder about what data they should and should not be passing in and out. It’s an exercise that every developer should practice and one that has become our regiment at Fave.&lt;/p&gt;

&lt;p&gt;Go back to &lt;a href=&quot;/2009-12-07-the-big-bang-rewrite-first-ask-why.html&quot;&gt;part one&lt;/a&gt; or read &lt;a href=&quot;/2009/12/13/the-big-bang-rewrite-part-3-auth.html&quot;&gt;part three&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Big Bang Rewrite (Part 1): First Ask Why</title>
   <link href="http://avandamiri.com/2009/12/07/the-big-bang-rewrite-first-ask-why.html"/>
   <updated>2009-12-07T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/12/07/the-big-bang-rewrite-first-ask-why</id>
   <content type="html">&lt;p&gt;When it comes to building something, be it a building, a car, or software, there are always imperfections. The first iteration is usually something simple, but eventually as features are added and requirements made more complex, the system starts to become bloated. Even with great agility and the most stubborn resistance to scope creep, technology changes so rapidly that immediately, often even before its conception, a product is out of date. It’s a fact of product development; it’s a fact of life. Change is the only constant.&lt;/p&gt;

&lt;p&gt;This frustrating realization means that a &lt;em&gt;tabula rasa&lt;/em&gt; is a rare find indeed. Realistically, the majority of our time is spent just making sure that progress doesn’t break what already works. This curve is exponential, such that eventually the smallest of alterations is painful, time consuming, and dangerous. The alternative, a rebuild, does not offer a much better promise as it consumes massive amounts of resources, with little front facing change.&lt;/p&gt;

&lt;p&gt;So, when do you know to start over?&lt;/p&gt;

&lt;p&gt;At Fave, I was faced with this same question with the development of getfave.com. The product, architecture and design requirements are simple but, when handling massive amounts of data, represent unique technological challenges. The site has also seen an enormous growth in traffic, straining the application to its limits. However, the application was weakest in the face of the company’s own desire to innovate. We wanted to push the envelope farther than our competition and offer more value to the consumer. The current product just wasn’t good enough.&lt;/p&gt;

&lt;p&gt;We had to ameliorate the situation and it came down to a tough call: start from scratch, or plow on with what we had? This decision hinged on how we defined “better.” If the current site was deficient, what was it missing and what did it need to be complete? Initially, these answers were elusive - amazingly, you can ride out “better” for a while. We continued with the old application, deploying changes iteratively in the pursuit of minor progress. Frustrations mounted and eventually we pushed against the stakeholders hard enough to solidify a tangible goal. We finally could sum up it with two words: better data.&lt;/p&gt;

&lt;p&gt;Although Fave relies on outside vendors for the bulk of our data, we’ve come to realize that its integrity is of utmost priority. We wanted to open our arms to as much of it as possible, but know that it is the most accurate in our market. This meant a major refactor to our data model - every core structure had to drastically change. This also meant exposing the data model to outside vendors in the form of an API. With the greater exposure would also come the need for tighter security. Each action on the site had to be locked down to specific roles. We of course, had much of this support already, but it left much to be desired. If our data was going to be accurate, we would have to have fine control over who was changing it. Better data also meant we had to track changes to businesses over time with a versioning system and human review process. Finally, if we had great data we had to be able to find it - our search engine, too, fell in the cross hairs.&lt;/p&gt;

&lt;p&gt;As we filled a whiteboard with requirements, it started to become apparent that we were standing in the shadow of an enormous endeavor. Everything hinged on many very invasive changes to the structure of the data which represented huge risks to the stability of the site. It was no longer a technical change, but a much more fundamental change in focus for the whole company. With a clear goal of superior data, we start shedding extraneous features. Soon the concept of starting from scratch became manageable.&lt;/p&gt;

&lt;p&gt;Read &lt;a href=&quot;/2009/12/13/the-big-bang-rewrite-part-2-api-first.html&quot;&gt;part two&lt;/a&gt; or &lt;a href=&quot;/2009/12/13/the-big-bang-rewrite-part-3-auth.html&quot;&gt;three&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Rebuilding a Brand. Avand.</title>
   <link href="http://avandamiri.com/2009/11/22/rebuilding-a-brand-avand.html"/>
   <updated>2009-11-22T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/11/22/rebuilding-a-brand-avand</id>
   <content type="html">&lt;p&gt;Once again, it’s been months since my last post. I’ve been taking some good and some bad classes at DePaul for the last 10 weeks and as a result haven’t really had much time to invest in myself. Even Piggy Back has taken the back burner. The one personal priority I did get around to was my new website avandamiri.com. I thought I would take a moment and reflect on the motivations, goals, and end results of the process.&lt;/p&gt;

&lt;h2 id=&quot;motivations&quot;&gt;Motivations&lt;/h2&gt;

&lt;p&gt;I’ve always wanted a web presence for myself. Unfortunately, I suffered from the same shortsightedness that many of the clients I’ve worked for have had in the past: simply wanting a website isn’t enough. From day one I broke my own rule to start with content first.&lt;/p&gt;

&lt;p&gt;Back in the day, I had a Blogger account, “Simple Things.” The process of posting was frustrating and I never liked the look of the template I had. It worked for my posts but it said absolutely nothing about me. It also annoyed me that all my posts were out in some database somewhere. I didn’t feel like I had control of my content. So, I migrated to my own hosted Wordpress account. The writing process improved tremendously, but I hit another self-expression road block, biting my tongue for several months with a pretty cool, simple, clean template.&lt;/p&gt;

&lt;p&gt;Then I finally caught myself. This entire time I was just shifting sand around. I was spending less time writing and more time reconfiguring the site and throughout the entire process had said absolutely nothing about myself. I made a promise to myself to build a site that accomplished exactly what I wanted.&lt;/p&gt;

&lt;h2 id=&quot;goals&quot;&gt;Goals&lt;/h2&gt;

&lt;p&gt;Describing one’s self is possibly one of the most difficult challenges. I decided to approach the problem systematically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Who am I?&lt;/li&gt;
  &lt;li&gt;What do I do the majority of my time?&lt;/li&gt;
  &lt;li&gt;What do I do with the rest?&lt;/li&gt;
  &lt;li&gt;What things I like most?&lt;/li&gt;
  &lt;li&gt;What values do I espouse?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It became instantly apparent that I wasn’t building a blog at all. I was building a brand: my brand. So I started answering some of those questions for myself.&lt;/p&gt;

&lt;p&gt;My birth name is “Avand Amiri,” although I have gone all my life by “Andy.” I decided that I wanted to stay true to my heritage and make the switch. It’s been hard to get my friends to call me “Avand,” change my old accounts, and track down all the old references, but I think I’m mostly there. Because “Avand” is so unique, I decided to build my entire “brand name” off of it. It became the cornerstone of this site.&lt;/p&gt;

&lt;p&gt;I’m fortunate to say that I love what I do. I spend my days building websites and I have for some time. Sometimes the line between “work and play” is a little ambiguous for me, but that’s OK. I decided that my work was a major focal point who I am and that my site had to reflect that.&lt;/p&gt;

&lt;p&gt;With every iteration of the old site, I was frustrated that I never expressed myself. I didn’t want an “About Me” page. In fact, I didn’t want any text at all. I had to find something important about myself that could become part of the “Avand” brand. I finally realized that cycling was a huge part of my life and I felt comfortable sharing that part of me with the world.&lt;/p&gt;

&lt;p&gt;Finally, I needed the site to subtly explain myself through the atheistic. This was the most fun part because the only question I had to answer is “what do I like?” Red, black and white are my favorite colors because they’re so pure. I embrace simplicity and minimalism in my life, and I integrated those concepts right into the design.&lt;/p&gt;

&lt;h2 id=&quot;getting-there&quot;&gt;Getting There&lt;/h2&gt;

&lt;p&gt;I decided to completely ignore the implementation details at first. I forced myself to focus on content. I knew that I wanted my best work to be featured as well as explained through my resume. The site also had to host my blog, featuring my latest blog post on the first page. There had to be a way to get in touch with me as well as find me through the various social networks I’m a part of. Finally, it needed tell a little bit more about me: my love of bikes, design, fashion, and cars.&lt;/p&gt;

&lt;p&gt;I had spent so much time self reflecting that the site actually came together quickly. I did all my drafting in Photoshop, with the exception of exploring some designs with pencil and paper.&lt;/p&gt;

&lt;p&gt;Although I had no preference of where the site was hosted, I did know that I wanted full control of the content. &lt;a href=&quot;http://vandev.com&quot;&gt;Chris Vanpelt&lt;/a&gt; had once mentioned &lt;a href=&quot;http://wiki.github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; to me and I decided it was perfect me. Instead of coming to the table with bulky features than simply distract (searching, comments, drafts, etc.) it gave me the perfect blank slate to build just what I wanted.&lt;/p&gt;

&lt;p&gt;I migrated each post to a markdown based text file and wrote a basic script to copy the files up to a cheap HTML hosting account with GoDaddy. &lt;a href=&quot;http://wufoo.com&quot;&gt;Wufoo&lt;/a&gt; allowed me to fulfill the “Talk to Me” component without the need for any server side scripting, although getting it to look just right has been a bit time consuming.&lt;/p&gt;

&lt;p&gt;Finally, I embraced iterative development. I published the PSD for friends to explore so I could get feedback instantly. I deployed early, while major functionality was still pending, and often, to make sure I was always moving forward. Today, I migrated the remaining posts from my old Wordpress account and added syndication, celebrating this major milestone with a fresh post about the process.&lt;/p&gt;

&lt;p&gt;Ultimately, I’m really satisfied with the end result. I feel like I actually accomplished what I set out to do a long time ago, and that’s really gratifying. At the same time, I’m prepared for the changes to come. I know that what I do, and who I am will develop over time. I look forward to reflecting on those developments here at &lt;a href=&quot;http://avandamiri.com&quot;&gt;avandamiri.com&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Race to a Beta Launch: The Trials and Tribulations of Piggy Back</title>
   <link href="http://avandamiri.com/2009/07/16/piggy-back-launch-trials-and-tribulations.html"/>
   <updated>2009-07-16T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/07/16/piggy-back-launch-trials-and-tribulations</id>
   <content type="html">&lt;p&gt;I haven’t posted in a while, and here’s why: &lt;a href=&quot;http://www.piggyback.it&quot;&gt;Piggy Back&lt;/a&gt;;. If you follow me on &lt;a href=&quot;http://www.twitter.com/avand&quot;&gt;Twitter&lt;/a&gt;, or are friends with me on &lt;a href=&quot;http://www.facebook.com/avand&quot;&gt;Facebook&lt;/a&gt;, you’ve probably seen the updates crawling by.&lt;/p&gt;

&lt;p&gt;Piggy Back is a web site that helps users manage debts between each other. It was inspired while I was consulting at &lt;a href=&quot;http://www.echo.com&quot;&gt;Echo Global Logistics&lt;/a&gt;, where Rob Freas, Bryan Dougherty, Antuan Kinnard and I were constantly going out for lunch. One of us invariably didn’t have cash, and to make things simpler one person would just always pay. We shared out a spreadsheet and whoever paid would update it.&lt;/p&gt;

&lt;p&gt;The pain: with every new record we added we had to go through the mental anguish of actually figuring out who owed what to whom. Piggy Back was born from that concept. Initially code named “Balancr,” in true Web 2.0 style, Piggy Back takes debts between people and nets them out. If Rob owes Bryan and Bryan owes me, well then Rob just owes me. It really is “the shortest distance between two wallets.”&lt;/p&gt;

&lt;p&gt;I whipped something together over a year ago, using it as more of a sandbox for Ruby on Rails wizardry than an actual product, then shelved it for quite some time as I pursued other endeavors. I finally decided to revisit the project about 3 weeks ago with a commitment to launching it, and here’s my story:&lt;/p&gt;

&lt;p&gt;##Focusing on What Matters##&lt;/p&gt;

&lt;p&gt;When I cracked open the source code again, there was a lot that had to change. Some were some obligatory upgrades, but in order to take this site from “no” to “pro” the amount of work was a bit overwhelming.&lt;/p&gt;

&lt;p&gt;So I decided to focus on only what mattered and that was the balancing algorithm. At the core Piggy Back had to be able to net out debts and find the simplest way for money to exchange hands. I started work on this part of the project solely with tests. Using &lt;a href=&quot;http://www.thoughtbot.com/projects/shoulda&quot;&gt;Shoulda&lt;/a&gt; I created a sea of nested contexts describing every possible debt situation I could think of, then I tweaked the algorithm, which was already pretty solid, to make the tests pass.&lt;/p&gt;

&lt;p&gt;Then I started pounding it as a test user, building up more and more complicated scenarios. As was expected, but not hoped for, the algorithm buckled. Something was clearly wrong, so I went back to the drawing board.&lt;/p&gt;

&lt;p&gt;I created more test cases and found the bug, but now, paranoid that there were other errors, I decided to map out every possible debt scenario I could think of… on paper:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4125753470/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2584/4125753470_557ae0236e_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4124984705/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2766/4124984705_cacdf056a2_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There was so many more fun things to work on. I wanted to build the bells and whistles that make it fun to use, pretty, and more useful. But I kept catching myself: no one would use it if it didn’t crunch the numbers correctly, including me. Two more late nights, and I was ready to move on to the fun stuff, with my mind at ease that Piggy Back could do the math right, although I’m still keeping my fingers crossed.&lt;/p&gt;

&lt;p&gt;##Racing to Production##&lt;/p&gt;

&lt;p&gt;After that little problem was over and done with, it became a sprint to get it live. No marathons here. I got an account with &lt;a href=&quot;http://www.slicehost.com&quot;&gt;Slicehost&lt;/a&gt;, and knocked out all the little annoying things that had to happen before going live: user registration workflow, invitations, &lt;a href=&quot;http://www.hoptoadapp.com&quot;&gt;error handling with Hoptoad&lt;/a&gt;, &lt;a href=&quot;http://www.google.com/analytics&quot;&gt;Google analytics&lt;/a&gt;, hosting, and ultimately deployment. Boom, it was live!&lt;/p&gt;

&lt;p&gt;There was so much more that had to happen, but at least it was up and running and I was accountable to my users and immediately started getting feedback.&lt;/p&gt;

&lt;p&gt;##Feedback is Deafening##&lt;/p&gt;

&lt;p&gt;Just like holding a microphone up to a speaker, the feedback started pouring in: where’s the remember your password button, can I create private debts, why is this over here, etc., etc., etc. I guess it’s really easy to criticize something.&lt;/p&gt;

&lt;p&gt;At times I got annoyed, sitting back and taking the attitude of, “well, if you want it to work that way, why don’t you build it!” Then I caught myself. These are &lt;em&gt;my&lt;/em&gt; users. This is exactly what I had been working so hard to achieve. I can’t swear them off just yet!&lt;/p&gt;

&lt;p&gt;##Build it to Use It##&lt;/p&gt;

&lt;p&gt;Piggy Back was inspired by a pain that I felt. I was tired of curbing my own generosity because I was afraid I’d never get paid back. I want Piggy Back to have a mobile interface to make it easier to add debts, for me first and foremost. Having worked on a lot of different projects, it’s really refreshing to really feel the need of the user and be able to act on it.&lt;/p&gt;

&lt;p&gt;##Build it to Use It, Again##&lt;/p&gt;

&lt;p&gt;Apparently the way I use software, and the way others use software is totally different: make no assumptions about user behavior. Given a text box that says “Name” I type “Avand Amiri,” while others type “ben” or “G.” When I click a link and it takes a second to load, I look to the browser’s status bar to see if browser is loading something. Other’s just give up.&lt;/p&gt;

&lt;p&gt;I’ve spent a few hours talking to people, and looking over people’s shoulders to see how they move their mouse, and ask them “why’d you do that?” Pay attention to how people phrase questions, and how many they’re asking.&lt;/p&gt;

&lt;p&gt;##Testing##&lt;/p&gt;

&lt;p&gt;For the technical people out there, how well is this application tested? Not really. The part that matters, Debt#balance, is heavily tested, but everything else really hasn’t been a priority. There’s 73 tests with 81 assertions, and absolutely zero controller testing.&lt;/p&gt;

&lt;p&gt;How does that make me feel? Not great. But it’s been eye opening to test what actually matters. If I don’t test that user’s have many debts, I guess I don’t really care, because the application will disintegrate if that becomes the case. Seriously, when was the last time a developer on a whim said, “meh, this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_many&lt;/code&gt; declaration can’t be that important.” It doesn’t happen. At the end of the day, my tests are the product of necessity. Some new functionality I’m releasing, requires my user registration to be much more robust, and I’m a little scared of the edge cases, so I’ll test them.&lt;/p&gt;

&lt;p&gt;So going back then, I guess I’d rather have a product that I use that has a few bugs, than a fully tested product that has yet to ship.&lt;/p&gt;

&lt;p&gt;##Conclusion##&lt;/p&gt;

&lt;p&gt;All things considered I’m having a lot of fun building Piggy Back and I think that’s because it directly impacts me. It’s fun to be user number 1, and it’s fun to see user number 10. Getting feedback has been huge, because it’s made me think about things I didn’t consider important or necessary. More than anything, it’s dynamic. Don’t get too comfortable with Piggy Back, just yet, there’s a lot more to come.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Outstanding Customer Service and Where It's Coming From</title>
   <link href="http://avandamiri.com/2009/06/08/the-pursuit-of-happiness-through-outstanding-customer-service.html"/>
   <updated>2009-06-08T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/06/08/the-pursuit-of-happiness-through-outstanding-customer-service</id>
   <content type="html">&lt;p&gt;&lt;em&gt;For best results, read while on hold with your favorite ISP.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Is anyone else seeing what’s happening here? I’m not sure where it’s coming from, but companies are becoming obsessed with excellent customer service.&lt;/p&gt;

&lt;p&gt;I witnessed it a little here and a little there at first, but then, after reading last month’s Inc. magazine’s article on &lt;a href=&quot;http://www.inc.com/ss/how-to-make-customers-love-you&quot;&gt;Tony Hsieh and Zappos&lt;/a&gt;, I started to notice it everywhere.&lt;/p&gt;

&lt;p&gt;First, I ordered shoes from Zappos. Got them next day with free shipping and returned two pairs with no issue. I haven’t had to call in yet, and don’t think I’ll ever have to because that company has their shit together. Did you know they can get an order into a box and ready to be shipped within 8 minutes of you pressing &quot;buy?&quot; That’s impressive for a 800,000 square foot warehouse. Hsieh isn’t trying to build a store where you buy shoes, though, as the article describes. He’s building a store where you buy happiness.&lt;/p&gt;

&lt;p&gt;At first I thought it was just Zappos, but then I found &lt;a href=&quot;http://www.bonobos.com&quot;&gt;Bonobos&lt;/a&gt;. Who would buy pants online? Well when you make it so easy, I think the question becomes who wouldn’t buy pants online. I have yet to use these guys, but my next pair is coming from that site.&lt;/p&gt;

&lt;p&gt;A short aside: how long will it take for these apparel sites to build a “if you’re an 11.5 in &lt;a href=&quot;http://www.zappos.com/product/7400255&quot;&gt;Kangaroos&lt;/a&gt;, you’ll be an 11 &lt;a href=&quot;http://www.zappos.com/product/7384367/color/173925&quot;&gt;Puma&lt;/a&gt;” feature.&lt;/p&gt;

&lt;p&gt;So I started to notice a trend, although &lt;a href=&quot;http://twitter.com/singfoom&quot;&gt;some people&lt;/a&gt; say it takes three occurrences of something to become a real pattern.&lt;/p&gt;

&lt;p&gt;I manage a website for a &lt;a href=&quot;http://www.wlcamp.org&quot;&gt;summer camp up in New Hampshire&lt;/a&gt; that I went to as a kid. Great place, by the way. I get copied on all the form submissions from the site; usually it’s just spam or a parent curious about tuition. Then I read this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hello,&lt;/p&gt;

  &lt;p&gt;I work for Garmin GPS. I received a complaint from one of our customers on how our unit guided him to your camp. He said it took at least one unsuitable dirt road (almost a trail).&lt;/p&gt;

  &lt;p&gt;I am going to try to get this fixed. May I ask a question since you know the area and I do not? When routing to the camp from the south, should the route involved 109A and then Federal Corner up to the camp? Our units seem to want to approach from the other side (via HWY 171 from the northeast). I think that may be the problem–that Federal Court is awful between 171 and camp but is okay between camp and 109A? I may be guessing wrong. Any help appreciated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It just so happens that I’ve &lt;em&gt;been down that trail&lt;/em&gt;, and I &lt;em&gt;was&lt;/em&gt; lost. Of course, that was back when &lt;a href=&quot;http://www.mapquest.com&quot;&gt;MapQuest&lt;/a&gt; ruled the world (proof that you can take down the market leader with a &lt;a href=&quot;http://maps.google.com&quot;&gt;better product&lt;/a&gt;… &lt;a href=&quot;http://gmail.com&quot;&gt;twice&lt;/a&gt;. &lt;a href=&quot;http://www.gastevich.com/&quot;&gt;Goin’ back though&lt;/a&gt;, how cool is it for a GPS company to take such ownership of their product?&lt;/p&gt;

&lt;p&gt;So what’s the deal? If an online shoe company can figure it out, what’s Comcast’s problem? Or AT&amp;amp;T’s for that matter. It’s a good thing I asked, because I’ll tell you: &lt;em&gt;constraints&lt;/em&gt;. When you’ve got your &lt;a href=&quot;http://tcrn.ch/Vvo6yM&quot;&gt;customers by the balls&lt;/a&gt; you don’t have to be nice. But when you’re selling a product that people &lt;em&gt;have&lt;/em&gt; to try before they buy, you do.&lt;/p&gt;

&lt;p&gt;An &lt;a href=&quot;http://www.popsci.com/scitech/article/2008-12/machine-might-save-world&quot;&gt;article from Popular Science a few months back&lt;/a&gt; talked about the work two desktop printer engineers are doing in the development of a nuclear fusion generator. They’re competing with the International Thermonuclear Experimental Reactor, a consortium of seven governments sinking billions of dollars into decades worth of research. And they’re doing it with 2 million bucks in an office park.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“It’s pretty basic, boring stuff,” he says. “Look in your car. There’s no superconducting magnet in there. There’s pipes and pistons and tubes. That’s what I want. I want to make a fusion machine at a sort of car level. And that’s why we can make it for $50 million and they” – government and university coalitions – “make it for $20 billion. That’s the difference.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s survival of the fittest. So look for innovation, whether it be the cure for cancer, a solution to the world’s energy problems, how to get to space more cheaply, or just how to get a great pair of shoes, from the underdogs. Because when the only other option is straight up failure, it’s amazing what people are capable of.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The New York Subway System. Holy Crap.</title>
   <link href="http://avandamiri.com/2009/06/01/the-new-york-subway-system-holy-crap.html"/>
   <updated>2009-06-01T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/06/01/the-new-york-subway-system-holy-crap</id>
   <content type="html">&lt;p&gt;I was recently in New York to visit a friend. Flew into La Guardia and called him up to tell him I was taking public transportation into Manhattan. He sounded puzzled but I didn’t really feel like spending $60.00 getting to West Village. Plus, there’s something to be said for pulling out the machete and blazing through uncharted lands. And by machete, I mean iPhone; and by lands I mean tunnels.&lt;/p&gt;

&lt;p&gt;After taking a &lt;em&gt;few&lt;/em&gt; wrong turns, I made it over the bridge onto 125th street, but I was definitely lost, and decided, “you know what, it’s late - maybe a cab is the right move.” Nope - apparently New York has these “black” cabs competing against the trusty yellow ones. I think they’re just there to freak out tourists.&lt;/p&gt;

&lt;p&gt;Back to public transportation - and this time I’m going underground.&lt;/p&gt;

&lt;p&gt;Without the aid of my iPhone underground, I had to memorize some of the key stops for my journey. I got an MTA card from a touch screen kiosk (why those things are so complicated I have no idea - don’t even get me started on the ones in CA.) When I finally got on the platform and got my bearings I was blown away. The New York subway system is absolutely incredible.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.mta.info/nyct/maps/sub1a.gif&quot; width=&quot;462&quot; height=&quot;299&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When you decide below the streets, there’s not 1, or even two layers of trains, there’s sometimes 3. And each level contains up to 3 rails. May not seem like such a big deal, but then you remember that above you is one of the biggest cities in the world - behemoth towers of steel and concrete  growing above these arteries. I was really blown away.&lt;/p&gt;

&lt;p&gt;Then I got lost… again. And here’s why:&lt;/p&gt;

&lt;p&gt;##Why I Got Lost##&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4123339056/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2788/4123339056_db81bed53a_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4123338572/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2524/4123338572_047e16c4d9_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4122566789/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2611/4122566789_ac9013ddd6_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Why is the word “Exit” on a red background? Does following the arrow mean you’re going to the exit? The red divides the routes on the right from the arrow. I was unsure whether following the arrow meant the exit, those lines, or both.&lt;/li&gt;
  &lt;li&gt;What does this mean: “Local to Bay Ridge-95 St. Late nights N to 36 St, Bklyn for R” ?&lt;/li&gt;
  &lt;li&gt;I actually like the alphanumeric dots of color, but why mix them into the language? At a glance it should be obvious what trains are coming to the platform your standing at.&lt;/li&gt;
  &lt;li&gt;Once you’re underground, which way is North? South? When you’re spun around, it can be very confusing. Don’t look to the signs; unless you know the city they won’t help you. I was amazed that even the transit maps (not pictured) while telling you “you’re here” failed to point out which way you were going. Unless you traced the route to the last stop - and even that wasn’t consistent.&lt;/li&gt;
  &lt;li&gt;Pay-to-turn bidirectional revolving steel doors? I for one find those things scary as hell. They remind me of one of those elaborate cave traps Indian Jones gets stuck in in the Temple of Doom. To make matters worse, they turn both ways on some ratcheting system. Not enjoyable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##What I Found Comforting##&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4123338944/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2544/4123338944_a3182ce32d_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4122568283/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2637/4122568283_45d9eeabbb_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The students playing a concerto in the walkways. Really good stuff.&lt;/li&gt;
  &lt;li&gt;The electronic signageon some of the subways. They give a bright and clear indication of direction of travel, make it obvious which stop you’re at, and dynamically show only the pertinent information like what stops are coming, not those that have passed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lack of conventions, obscure abbreviations, and unclear signage made for a fairly confusing night ride. Might not seem bad reading it at your laptop, but three stories underground, with trains whizzing by and no access to the outside world makes it pretty daunting.&lt;/p&gt;

&lt;p&gt;Compare that to Chicago, granted a much simpler subway system (I feel inadequate even linking to a picture of the subway map):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/amiriav/4122568451/&quot;&gt;
  &lt;img src=&quot;http://farm3.staticflickr.com/2776/4122568451_dd30ec56e0_n.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lines have clear names, and the construction emphasizes the route (red line = red steal girders). While maybe redundant, the signs are explicit (“Board here”) bringing the commuting experience down to the lowest common denominator. Maybe that says something about a difference between East Coasters and Midwesterners.&lt;/p&gt;

&lt;p&gt;But I think it says more about design: know your audience. A public transit system has to serve everyone from the battle hardened city warrior, to the foreign tourist. Just the dependence on full English sentences describing routes throughout the NY transit system seems like a huge design deficiency to me.&lt;/p&gt;

&lt;p&gt;Compare their websites, too: &lt;a href=&quot;http://www.transitchicago.com/&quot;&gt;Chicago&lt;/a&gt; vs &lt;a href=&quot;http://www.mta.info/&quot;&gt;New York&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But one can’t be too harsh, just take a close up look at their &lt;a href=&quot;http://www.mta.info/nyct/maps/submap.htm&quot;&gt;subway map&lt;/a&gt; and you’ll see it’s really incredible.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Adventures with Ad Delivery in Rails</title>
   <link href="http://avandamiri.com/2009/05/28/adventures-with-ad-delivery-in-rails.html"/>
   <updated>2009-05-28T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/05/28/adventures-with-ad-delivery-in-rails</id>
   <content type="html">&lt;p&gt;It’s always hard to find the line between buy vs. build - or as it’s known in the open-source world, buy vs. “borrow.” I find this to be more true in Rails than in any other application framework. You want authentication, you got it; you need paging, done. Before you know it you’ve got an application that does almost everything you need, almost everything you don’t and you’re stuck in the middle.&lt;/p&gt;

&lt;p&gt;Now, it’s time to &lt;em&gt;actually&lt;/em&gt; write code.&lt;/p&gt;

&lt;p&gt;At GetFave.com, we had a problem on our hands. We needed to deliver ads from our own inventory - space on the site that our sales team sells to our clients. I immediately asked - how can we do this without writing anything. You can anticipate the complexity that comes from adding a feature like that: find ads contextually, figure out which one to show, show it, track that it was shown, all while not slowing down the page. We take performance very seriously at GetFave.com&lt;/p&gt;

&lt;p&gt;So we tried on &lt;a href=&quot;https://www.google.com/admanager/&quot;&gt;Google AdManager&lt;/a&gt; for size. It seemed to be the right fit. First off, it’s Google, so it’s gotta be good (debatable, I think). Secondly, it promised to do all the heavy lifting for us: tracking impressions, click-throughs, reporting, delivery, impression distribution, inventory management, and more. They even worked with us to open up an advanced custom attribute targeting system. The only known draw back was that it wasn’t going to work with other ad network APIs. Plus, it was a drop in replacement for AdSense - so we had nothing to loose.&lt;/p&gt;

&lt;p&gt;A few weeks later, a day before one of our clients ads had been promised to be delivered, AdManager has yet to perform as we’ve expected. The interface is clunky and convoluted. I can’t blame them, they’ve built a behemoth catch-all advertising management system. But most importantly it wasn’t delivering the ads we needed to satisfy our customers (I later discovered that AdManager requires several weeks for custom targeting data to propagate and effectively deliver ads.)&lt;/p&gt;

&lt;p&gt;With our lovely &lt;a href=&quot;http://lindsayinchicago.wordpress.com/&quot;&gt;sales director&lt;/a&gt; popping her head in to make sure we on target for ads to be delivered, I found myself between a rock and a hard place. Then it occurred to me: “wait, I know how to write code!”&lt;/p&gt;

&lt;p&gt;Queue Pandora. I started with a basic ActiveRecord model and stubbed out what I thought we’d need - borrowing heavily from my experience on the Google side of the wall. The biggest issue was performance and although I was reluctant to have ad delivery happen synchronously, I decided to go with it (we’d have some time to refactor before we had enough inventory to slow things down). I had already written a nifty tracking class to help me keep track of the context of the page such as keywords and geography. In an afternoon I had the whole thing done.&lt;/p&gt;

&lt;p&gt;Pretty soon it was in production and getting feedback from sales people and customers. There were bugs, as was to be expected, but we’ve since worked them out in addition to adding several new features. Shameless plug: All you small business owners out there may be interested in our new geo-targeted ad product.&lt;/p&gt;

&lt;p&gt;The moral of the story was that sometimes - I’ll say maybe even the majority of the time - it pays just to write it yourself. To borrow from my friend &lt;a href=&quot;http://twitter.com/MichaelDwan/status/1928071321&quot;&gt;Michael Dwan&lt;/a&gt;, and then in turn &lt;a href=&quot;http://www.loudthinking.com/&quot;&gt;DHH&lt;/a&gt;, “don’t use code you couldn’t write yourself.”&lt;/p&gt;

&lt;p&gt;Next up, Google Analytics.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Data Driven Development (DDD)</title>
   <link href="http://avandamiri.com/2009/01/15/data-driven-development-ddd.html"/>
   <updated>2009-01-15T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2009/01/15/data-driven-development-ddd</id>
   <content type="html">&lt;p&gt;In the world of software, methodologies rule. It isn’t about the code, it’s all about the process. And when it comes to processes, there’s a lot to choose from; developers have a habit of over thinking this stuff. So as one, I figured I’d throw in my two cents, too.&lt;/p&gt;

&lt;p&gt;Test Driven Development has been a buzz word in the Rails community for a some time. It certainly deserves the credit, too. The peace of mind that comes with a solid test framework is unparalleled. But there’s a component of testing that I think is ignored. To write a good test, you need good test data.&lt;/p&gt;

&lt;p&gt;You have a couple options when it comes to data:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Fixtures: In Rails, you can use static YAML files to represent the data in your database. Once your migrated, just load the fixtures and you’ve got some data to work with. The downside here is that to get a lot of data, you have to do a lot of typing. Additionally, as your data becomes more and more complex, it becomes really tough to keep track of the dependencies and associations between objects.&lt;/li&gt;
  &lt;li&gt;SQL: Aa SQL dump from another machine or production is a great fast way to get tons of data, but is incredibly fragile. As your database changes, the migrations and schema may deviate machine to machine, and it only takes one change to invalidate an entire SQL dump. They’re a pain to work with as most text editors crash on such large files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Recently, however, another option has become available: generate it! I was really inspired after watching the &lt;a href=&quot;http://railscasts.com/episodes/126-populating-a-database&quot;&gt;Populator Railscast by Ryan Bates&lt;/a&gt;, in which he demonstrates using Ruby to spin up a few hundred database rows in a few minutes. With simple models, it’s a totally painless process. So what happens when you outgrow the out of the box Rails application?&lt;/p&gt;

&lt;p&gt;Well, I say you stay disciplined. When you embrace TDD, it becomes weird not to write the test cases first. Same thing here, for what I’m calling Data Driven Development. Write the tests, migration, model, and a data generator in one process. Change your model? Change the data, and change the test. Every model should have tests. Every model should have a data generator.&lt;/p&gt;

&lt;p&gt;Using the &lt;a href=&quot;http://populator.rubyforge.org&quot;&gt;populator&lt;/a&gt; and &lt;a href=&quot;http://faker.rubyforge.org&quot;&gt;faker&lt;/a&gt; gems was a great way to get started. In a few places you have to do some work directly with ActiveRecord, when relationships become complicated, but it’s relatively painless. I wrote the following method that I call at the beginning of each generator to deal with dependency issues that helped me quite a bit:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Given a set of class names, will require objects of those types to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# have been populated.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Usage: depends_on(User, Post, Comment)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;any?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zero?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pluralize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Depends on &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sentence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; to populate data.&quot;&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;underscore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pluralize&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.all&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This not only helped declaratively define my dependencies, but also sets up whatever instance variables (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@users&lt;/code&gt;) to help you out with the generator.&lt;/p&gt;

&lt;p&gt;As far as testing goes, factories come in really handy. It’s just like using a generator, but knowing that the output will be the same each time. For my tests I completely rely on &lt;a href=&quot;http://github.com/thoughtbot/factory_girl/tree/master&quot;&gt;factory_girl&lt;/a&gt;. Not only can they run much faster as many tests don’t even need to hit the database, they allow each test to declaratively set up exactly the conditions you need.&lt;/p&gt;

&lt;p&gt;Ultimately, the approach gives you more peace of mind. Loose your database? No problem: migrate, then generate. Need more data? Generate millions of fake records while you grab a cup of coffee. Good deal.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>In-n-Out Burger: Consistency, Animal Style</title>
   <link href="http://avandamiri.com/2008/12/23/in-n-out-burger-consistency-animal-style.html"/>
   <updated>2008-12-23T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/12/23/in-n-out-burger-consistency-animal-style</id>
   <content type="html">&lt;p&gt;I recently took a trip out to California and had my first dinning experience with In-n-Out Burger. I really reveled in the experience, because they’ve really nailed, what in my mind, makes a great product.&lt;/p&gt;

&lt;p&gt;Immediately In-n-Out Burger’s menu jumped out at me. In my day to day operations I’m often tasked with conveying information quickly. The web is my domain, but regardless of medium, the most easy to convey information is also simple information. I’ve commented before on how Apple has been successful following this mantra. So when I walked into In-and-Out, expecting to become quickly stressed with an overload of options, sizes, and extras, I was pleasantly surprised to find this instead:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2598/4122576419_67c1c80661_o.jpg&quot; alt=&quot;In-n-Out Burger Menu&quot; /&gt;&lt;/p&gt;

&lt;p&gt;No tricks here. A simple set of options, listed by price. A whopping 34 possible menu options by my count. Which seems pretty easy when I compare it to any other fast food places - yeah, that’s right, no salads here. Even the option I found most delicious - “animal style”, is unlisted on the menu. Talk about restraint and compromise.
So, we sit down to eat and I’m anxious. I’ve heard good things, and am happy thus far, but just because they have a simple menu, doesn’t say anything about the food. Fresh ingredients: crunchy lettuce, a thick tomato wedge you can actually sink your teeth into, tasty sauce, and real beef, all on a toasted buttery bun. French fries, cut from whole potatoes right before your eyes. Delicious.&lt;/p&gt;

&lt;p&gt;First experience was a huge success. But what was really inspiring were the subsequent visits (I tallied 6 charges on my credit card statement after the trip). In-and-Out Burger, beyond making delicious burgers, wins because they’re consistent. The deliver the same experience every meal at every location. The menus, burgers, fries, outfits, tile, floor-plan, receipts, toilet paper - all, exactly the same from store to store. It’s like someone came through with a &lt;a href=&quot;http://en.wikipedia.org/wiki/CH-47_Chinook&quot;&gt;Chinook&lt;/a&gt; and just airdropped them into a lot. This serves the customers, while most not as detail obsessed as I, in making the experience more familiar and completely reliable. And it serves the franchise; just think how much money was saved not having to re-hash every detail.&lt;/p&gt;

&lt;p&gt;I was really impressed, and will think back to my experiences there while working in my domain. But first… something to eat.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CSS Tricks (2 of 2): Using Rails to Manage Styles</title>
   <link href="http://avandamiri.com/2008/11/19/css-tricks-2-of-2-using-rails-to-manage-styles.html"/>
   <updated>2008-11-19T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/11/19/css-tricks-2-of-2-using-rails-to-manage-styles</id>
   <content type="html">&lt;p&gt;For the second half of my CSS “tips n’ tricks” tutorial, I’d like to take some time and discuss how Rails can help manage stylesheets. As you start out any Rails application, there are some huge conventions you follow within the ‘app’ folder. I think these conventions make it much easier for developers to find, maintain and create code. But when it comes to stylesheets I find there to be a notable absence of these conventions.&lt;/p&gt;

&lt;p&gt;My web applications have, in the past, began as one stylesheet called “default.css” or “application.css” and placed in the stylesheets folder. I’d try and arrange similar styles in similar places, and use comments to help organize it. Pretty soon I had a 800 line CSS file on my hands and was hunting to find styles on various pages. I knew there had to be a better way, and thanks to Rails and some conventions I’ve started following, I think I’ve got a decent system. It involves 3 basic components: using controllers and actions as CSS selectors; many shorter CSS files; and Rails stylesheet caching.&lt;/p&gt;

&lt;p&gt;##1. Controllers and actions as CSS selectors##&lt;/p&gt;

&lt;p&gt;Depending on the application, you’ll be using some kind of layout in the views/layouts. I usually stick with something like views/layouts/application.html.erb early on in the game. The first thing I do is make whatever div I have wrapping my main content area adopt the current controller and action names as CSS classes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wrapper&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;controller_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;action_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This means that now in any stylesheet I have full control over what gets rendered and no style can step on the feet of another. For example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;#wrapper&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;/* insert styles common to all controllers here */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;#wrapper&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;/* insert common styles for all user actions here */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;#wrapper&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.users.index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;/* insert users#index specific styles here */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The key is to religiously obey these prefixes. In &lt;a href=&quot;/2008/09/18/css-tricks-1-of-2-first-get-down-with-the-oop.html&quot;&gt;Part 1 of this CSS series&lt;/a&gt; I talked about being as specific as possible with CSS selectors, and this is why. If you’re not, you’ll spend hours trying to figure out why something is rendering a certain way only to find that it’s inheriting something entirely irrelevant. So once you have that sorted you can then make…&lt;/p&gt;

&lt;p&gt;##2. Many shorter CSS files##&lt;/p&gt;

&lt;p&gt;So if you have a controller like UsersController, you’ll have a folder, views/users. Within that you’ll have files that respond to each action. Do the same thing for your styles. Create a folder public/stylesheets/users and create a stylesheet for each view that warrants its own styles. To follow the example above, you can now take any CSS that starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;div#wrapper div.users.index&lt;/code&gt;, and place it in public/stylesheets/users/index.css. Same thing for every other action, and partials too… hell, I even prefix those files with an underscore. I try and make the files stylesheets folder mirror the views.&lt;/p&gt;

&lt;p&gt;You have to get a little more creative when it comes to common styles (those that span multiple controllers or actions). For styles spanning multiple actions, simply create a common.css inside the controllers folder. For styles that span multiple controllers, chances are that a layout exists for that part of the application. For example, navigation that may be common to administration would go in public/stylesheets/admin.css to correspond to app/views/layouts/admin.html.erb. &lt;/p&gt;

&lt;p&gt;This process, actually works really well with javascripts too. It may seem ridiculous to include so many stylesheets into the final HTML that gets rendered, but fortunately you can send it all down as one.&lt;/p&gt;

&lt;p&gt;##3. Rails stylesheet caching##&lt;/p&gt;

&lt;p&gt;This is where it all comes together. With one simple command we can get the web server to concatenate all these files into one sheet that gets sent to the client:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;application&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;users/index&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;users/new&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;users/common&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;cached/users&apos;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In some cases I’ll just bundle every CSS file I create into one sheet, or if the application is a bit more stratified you can create sets of caches. Usually the structure of your layouts will determine how you set these up.&lt;/p&gt;

&lt;p&gt;This set up means you as a developer don’t have to loose time trying to find the styles that correspond to their respective view HTML, can save time when debugging by eliminating accidental style inheritance, and still send one file to the client. Enjoy.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>CSS Tricks (1 of 2): First, Get Down with the OOP</title>
   <link href="http://avandamiri.com/2008/09/18/css-tricks-1-of-2-first-get-down-with-the-oop.html"/>
   <updated>2008-09-18T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/09/18/css-tricks-1-of-2-first-get-down-with-the-oop</id>
   <content type="html">&lt;p&gt;##Introduction##&lt;/p&gt;

&lt;p&gt;I recently stumbled upon an &lt;a href=&quot;http://www.evoart.info/&quot;&gt;interesting web design blog&lt;/a&gt; that featured an article about some &lt;a href=&quot;http://www.evoart.info/10-essential-considerations-when-designing-a-website&quot;&gt;CSS “essentials”&lt;/a&gt; and commonly used &lt;a href=&quot;http://www.evoart.info/7-essential-css-code-snippets&quot;&gt;CSS code snippets&lt;/a&gt;. I read it with a great amount of interest and found that I had a few tricks and tips up my sleeve that I’d like to contribute as well. So this is the first in a two part post about how to improve your CSS and make the design process more fun and less stressful.&lt;/p&gt;

&lt;p&gt;I immediately found that a lot of my tricks don’t actually have anything to do with visual design or CSS at all, but more about structure and design patterns. Funny, how that sort of thing happens when you learn how to code first. I’ve found that you can bring a lot of the organization and philosophies that come from structuring application code right into the presentation layer. Here’s what I’ve learned…&lt;/p&gt;

&lt;p&gt;##Embrace a Convention Through and Through##&lt;/p&gt;

&lt;p&gt;Seriously, if you’re not using some kind of structure when it comes to building an application, you should probably &lt;a href=&quot;http://failblog.org&quot;&gt;go read some other blog&lt;/a&gt;. I’m somewhat infatuated with the MVC pattern these days, but for the sake of what we’re doing here I don’t know that it matters.&lt;/p&gt;

&lt;p&gt;The idea is that you have various objects or models throughout your code. You may have some Users, Products, or Messages. The problem is that by the time they get to the view part of your application, their meaning has been diluted. Distill it.&lt;/p&gt;

&lt;p&gt;You have a fairly &lt;a href=&quot;http://en.wikipedia.org/wiki/Create,_read,_update_and_delete&quot;&gt;common set of tasks for any object&lt;/a&gt;: List (index), view (show), create (new), update (edit), and delete (destroy). Almost all of those require a presentation of some kind, with the exception of delete, usually. There’s an obvious Ruby slant in these snippets, but I think you can handle it:&lt;/p&gt;

&lt;p&gt;Users#index&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;users&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Derive this from the controller --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@users&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Users#show&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Users#new&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erb&quot; data-lang=&quot;erb&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Key off this in the CSS (i.e. #user form input) --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With this kind of structure, your CSS stays organized and follows much of the meaning defined by the business objects themselves. I would encourage designers to try and think as much like this as possible.&lt;/p&gt;

&lt;p&gt;Instead of reinventing names for classes and ID’s look to the structure of the application code first and let it drive the front end.&lt;/p&gt;

&lt;p&gt;##Don’t Over Refactor CSS##&lt;/p&gt;

&lt;p&gt;Just like with code, your CSS can become overly abstract. If you need to style a single element on a single page, start with inline styles. An ASP.NET developer once told me, “never use inline styles - everything needs to have corresponding class or ID.” That attitude is part of what’s contributed to my career switch to Ruby on Rails. Don’t create a class for it until you see commonalities start to evolve.&lt;/p&gt;

&lt;p&gt;An example: You may find that you’re putting a paragraph that needs a particularly attention grabbing look. Start with a paragraph and set its style attribute. Make it look just the way you need to for that one instance. As you continue to work on the site you may find that you want a link to actually look similar to that paragraph, maybe they’re both a specific shade of red. Go back to that paragraph, remove the color property, and create a class called .red, which you can now apply to both. The growth is now organic and maintainable.&lt;/p&gt;

&lt;p&gt;##Tame the CSS File##&lt;/p&gt;

&lt;p&gt;Whether it be in a Controller, Stored Procedure, or CSS, it’s not OK for files to just grow to thousands of lines without taking a step back and saying, “woah”, what just happened here? To avoid this little conundrum I like to use the &lt;a href=&quot;http://www.cssnewbie.com/css-import-rule&quot;&gt;CSS @import function&lt;/a&gt;. Group common styles together and import them when the page renders to make the developers lives easier.&lt;/p&gt;

&lt;p&gt;I know what you’re going to say. There’s a significant performance hit for this, and I hear you. It’s not OK to go to production using @import, because each file will require &lt;a href=&quot;http://developer.yahoo.com/performance/rules.html&quot;&gt;another HTTP request, which isn’t cool&lt;/a&gt;. But, if you’re doing anything serious, you’ll have a deployment process and you should let that piece of the puzzle take care of grabbing the CSS and compiling it all together into one file.&lt;/p&gt;

&lt;p&gt;###Be #as .Specific .as:Possible##&lt;/p&gt;

&lt;p&gt;It’s very easy to be lazy with CSS and end up with thousands of styles that conflict with one another. You also may not realize that there is common styling between elements that could be “refactored.”&lt;/p&gt;

&lt;p&gt;Let your CSS selectors follow the DOM as closely as possible. If you look back to the index example above you could easily just style off of .user, but that’s exactly the type of laziness I’m talking about. Use #users .user instead. It will make life easier in the long run, and isn’t that what development is all about?&lt;/p&gt;

&lt;p&gt;##Conclusion and What’s to Come…##&lt;/p&gt;

&lt;p&gt;The approaches here are pretty high level, but in the &lt;a href=&quot;/2008/11/19/css-tricks-2-of-2-using-rails-to-manage-styles.html&quot;&gt;next part of this post&lt;/a&gt; (Part 2, for those you playing at home), I’ll talk with about more concrete examples on a line-by-line basis.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>People and Process</title>
   <link href="http://avandamiri.com/2008/09/07/people-and-process.html"/>
   <updated>2008-09-07T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/09/07/people-and-process</id>
   <content type="html">&lt;p&gt;Over the last couple of days I’ve come to an astounding realization. While I had always considered that the culture of a company - its people and practices - made a difference in its day-to-day operations, the scope had eluded me.&lt;/p&gt;

&lt;p&gt;This month’s issue of Inc. magazine featured an article about a law firm that is changing the way they do business. After noticing depreciating morale, and low outcome they revolutionized the way their office was run by implementing a strategy known as &lt;a href=&quot;http://www.inc.com/magazine/20080801/making-it-work.html&quot;&gt;ROWE, a results-only work environment&lt;/a&gt;. Standing up against the “tried and true” 8-5, more hours is better, work hard play hard, meeting frenzied corporate culture, this approach seems insane. Forget about classic work culture for a moment and think just about how to get work done effectively. It might actually make sense to work when it’s most convenient for you, balance your personal affairs the way you need to, and set your own deadlines. These are all practices that ROWE embodies, even down to the receptionists. It’s the results that matter, not the logistics. Of course, it requires some discipline, but wait a second, do you want to employee people that need a schedule to be productive? That doesn’t really jive with having “passionate” employees, does it?&lt;/p&gt;

&lt;p&gt;37Signals, of course, has tooted this horn for quite some time now. &lt;a href=&quot;http://www.37signals.com/svn/posts/893-workplace-experiments&quot;&gt;4 day weeks&lt;/a&gt;, they say, has boosted productivity, catapulted morale skyward, and absolutely energized their company. It’s all about working “fresh;” maximizing your personal time to explore new opportunities and expand the mind to bring to work your absolute best.&lt;/p&gt;

&lt;p&gt;Of course, &lt;a href=&quot;http://www.google.com/support/jobs/bin/static.py?page=about.html&amp;amp;amp;about=top10&quot;&gt;Google&lt;/a&gt;, is the ultimate example of this.&lt;/p&gt;

&lt;p&gt;What is interesting to me is that none of these approaches is domain specific. A law firm, a software company, and a search engine, all practicing new approaches to corporate policy, all claiming increased productivity and performance. It doesn’t really matter what you do, but how you do it - the &lt;em&gt;process&lt;/em&gt; behind it.&lt;/p&gt;

&lt;p&gt;When I was working at &lt;a href=&quot;http://wlcamp.org/&quot;&gt;William Lawrence Camp&lt;/a&gt; as a counselor, I remember being a part of the tradition of &lt;a href=&quot;http://wlcamp.org/boys-summer-camp-other-programs.asp&quot;&gt;“Beach Day.”&lt;/a&gt;. It’s a pretty grueling process for the staff, but the kids really enjoy pilling into buses, driving an hour and a half to the beach, and pilling on sun screen. When we get back, we always close the day out with a barbecue. I’ve always enjoyed grilling, and when we got back from one such trip, I jumped at the opportunity to help out on the grill. The head counselor, who was keeping an eye on things walked over to me and said, very simply, “Andy, you’re doing a great job, and thanks a lot for your help.” Buried in a billow of smoke and charcoal, I thanked him and noticed that instantly I wanted to help out even more. The urge was overwhelming.&lt;/p&gt;

&lt;p&gt;It’s the amazing power of positive reinforcement. I think the tendency is to think that these philosophies don’t really apply in the “real world.” After all, we’re all adults here, and we have to put on our work clothes and just “get the job done.” That’s what it’s called, right? “Work.” So many “work” cultures are just that: a place where it’s not about being a part of a team but just producing, however that needs to happen.&lt;/p&gt;

&lt;p&gt;I’m very fortunate to be involved in the career of my choice, something that I am tremendously passionate about, and I can understand that a lot of people, from a lot of walks of life, don’t share similar circumstances, but I doubt that it would matter very much. My point is that &lt;em&gt;what&lt;/em&gt; you do, is far less important to &lt;em&gt;how&lt;/em&gt; you do it and &lt;em&gt;who&lt;/em&gt; you do it with.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://4.bp.blogspot.com/_EgF6v5WqT_g/SMRN-Zm4MzI/AAAAAAAAAEI/F3j9Y_m3_AU/s200/Iwo+Jima.jpg&quot; alt=&quot;picture&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The image from Iwo Jima, for me, conjures up the emotion of the later. That tremendous feeling of camaraderie. It’s the root of patriotism, and could be, arguably, the root of U.S.A’s strength. Imagine a business running on that fuel.&lt;/p&gt;

&lt;p&gt;And as for how, I think back to companies like the ones I mentioned above. It’s a common theme of bringing employees closer together, while renouncing micromanagement and promoting quality results. Within my field of software development, “agile” processes come to mind, and I’m sure each industry has its own parallel.&lt;/p&gt;

&lt;p&gt;This is of course more a science than I may be suggesting, but can’t it be measured through emotion? Think again about the feeling that photo conjures. Do you feel like that at work and don’t you think you’d get a lot more done if you did?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Bravo 37Signals for Phasing out IE 6!</title>
   <link href="http://avandamiri.com/2008/09/02/bravo-37signals-for-phasing-out-ie-6.html"/>
   <updated>2008-09-02T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/09/02/bravo-37signals-for-phasing-out-ie-6</id>
   <content type="html">&lt;p&gt;It’s been a long time coming…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2665/4123348110_13e9dbc1c7_o.jpg&quot; alt=&quot;Basecamp Phasing out IE 6 Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Too much time has gone by with developers forced to limit their imaginations, creativity and ability to support the &lt;a href=&quot;http://37signals.blogs.com/products/2008/07/basecamp-phasin.html&quot;&gt;rusty weight of IE 6&lt;/a&gt;. But most websites have been afraid to stick their neck out.&lt;/p&gt;

&lt;p&gt;So, kudos to you, 37Signals, for doing your part to rid the world of IE6.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Enigmo: A Shower of Entropy</title>
   <link href="http://avandamiri.com/2008/08/01/enigmo-a-shower-of-entropy.html"/>
   <updated>2008-08-01T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/08/01/enigmo-a-shower-of-entropy</id>
   <content type="html">&lt;p&gt;Since I got my iPhone 3G, I’ve downloaded, that is paid, for exactly 3 games. The best - by a long shot - is &lt;a href=&quot;http://www.pangeasoft.net/enigmo&quot;&gt;Enigmo, from Pangea Software&lt;/a&gt;. For those of you who don’t know it, it’s basically a puzzle game where you have a certain set of tools on each level that you need to use to somehow route a bunch of droplets of liquid from point A to point B. Sounds lame, right? Maybe this will clear things up:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://toucharcade.com/wp-content/uploads/2008/03/enigmo.jpg&quot; alt=&quot;Enigmo Screenshot&quot; title=&quot;Enigmo Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not so lame anymore, huh? Yeah, that’s what I thought.&lt;/p&gt;

&lt;p&gt;Anyway, this game, besides just blatantly robbing my time, has actually spoken to me on a deeper level (think wading pool). For those of you who may know me, I’m a bit of a perfectionist. I find myself constantly balancing my idealism against productivity and efficiency. Enigmo helps me practice this. You’re trying to get all of these little droplets over to one place, but soon realize that things are just a bit more chaotic than you accounted for. In almost all the levels, much to my dismay, you just can’t get every droplet into the pot. It’s all about getting “good enough.”&lt;/p&gt;

&lt;p&gt;And that’s OK! Because there’s a countdown racing to zero, and the goal isn’t to get all the droplets into the pots, but rather to get as many points as possible by finishing quickly. And even then, you only need to fill fast enough for them not to evaporate. The best way to get big points: just do it. It doesn’t have to be beautiful or ideal; there’s no “grand scheme” to the game, and there’s definitely more than one solution&lt;/p&gt;

&lt;p&gt;So if you, like me, suffer from “entrophobia”, pick up this game asap and start embracing the insanity.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Computer 1, Andy 0 and I Couldn't Be Happier</title>
   <link href="http://avandamiri.com/2008/07/25/computer-1-andy-0-and-i-couldnt-be-happier.html"/>
   <updated>2008-07-25T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/07/25/computer-1-andy-0-and-i-couldnt-be-happier</id>
   <content type="html">&lt;p&gt;In my own time, I’ve been dabbling with some pretty hardcore machine learning. Trying to answer the question of how a computer can create a relationship between two things, blocks of text in this case. Turns out with a few matrix transpositions, single value decompositions, cosine similiarities, latent semantic index, and a &lt;a href=&quot;http://www.igvita.com/2007/05/23/bayes-classification-in-ruby/&quot;&gt;naive Baysian filter&lt;/a&gt; to boot, you can get pretty close. And I was just &lt;em&gt;dabbling&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I was blown away by how accurately the computer, when told what &lt;em&gt;kinds&lt;/em&gt; of things to look for, could create associations between data for itself. I had to force myself to avoid using my head to solve the problem, and pass the buck to the machines. But this is nothing new - Google has been doing it for a while - and it seems to be a trend, if not a revolution, &lt;a href=&quot;http://www.wired.com/science/discoveries/magazine/16-07/pb_theory&quot;&gt;according to WIRED&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem with this whole movement is that unless you’re a math Ph.D., it’s completely counterintuitive. You’ve spent 20-60 years training your brain, and here comes a computer (or a whole bunch of them it turns out) that knows more than you do in the span of a few minutes. How is this possible?&lt;/p&gt;

&lt;p&gt;Well, isn’t in the end your brain doing pretty much the same thing, maybe with a dash of evolutionary preprogramming? If you subscribe to theory of &lt;a href=&quot;http://en.wikipedia.org/wiki/Tabula_rasa&quot;&gt;tabula rasa&lt;/a&gt;, we’re not much further along than a blinking terminal window when we’re born. It’s just a little unnerving that a machine can go from infant to prophet in minutes where it takes humans years. But, hey, we’ve had other problems to deal with, too (balance, speech, survival, etc.) - take that Mr. Fancy Computer.&lt;/p&gt;

&lt;p&gt;But this isn’t even about computers. It’s just raw math; the type of math I hope to someday wrap my head around, if only slightly. Humans are selfish, egotistical, and prideful - all things that math could not care less about. You don’t “solve for x” with empathy. And it’s that stark, cold, unforgiving nature of a white board filled head to toe with equations that makes us layman turn to each other and say “pish posh - I’m a &lt;em&gt;human&lt;/em&gt;, I’ll &lt;em&gt;always&lt;/em&gt; know better than an equation.” But, like I said, in my dabbling, I’ve found that nothing could be further to the truth, and if that  means the computer wins, I’m OK with that.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>target="_blank" Convention</title>
   <link href="http://avandamiri.com/2008/07/10/target-blank-convention.html"/>
   <updated>2008-07-10T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/07/10/target-blank-convention</id>
   <content type="html">&lt;p&gt;I’ve been building websites for a while now, and each time I do it, I run into a couple areas where I sit back in my chair for a second, scratch my head, and ponder conventions. One great thing about &lt;a href=&quot;http://www.rubyonrails.org&quot;&gt;Ruby on Rails&lt;/a&gt; is the way it enforces convention in many areas, but yet there are still a number of things up for debate. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target=&quot;_blank&quot;&lt;/code&gt; is one such convention that has yet to be settled it seems.&lt;/p&gt;

&lt;p&gt;I guess it’s a two sided issue. When do you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target=&quot;_blank&quot;&lt;/code&gt;, and how do you indicate that behavior to the user?&lt;/p&gt;

&lt;p&gt;I think the first one is fairly simple. One obvious rule I follow is whenever you’re changing domains the target should be in a new window. Just because someone wants to read a little background behind
a hyperlink, shouldn’t mean their done reading the rest of the text on this page. And I usually extend that same principle to other areas, too. For example, I recently built a site that had an editing form, and you could just repeatedly save changes as you went on. I added a “View” link that targeted a new window so that if you wanted to see the changes you’ve made you could without being taken away from editing. So as far as I’m concerned this issue is pretty straight forward.&lt;/p&gt;

&lt;p&gt;This one isn’t: giving the user feedback that the link is actually opening in a new window. I can’t seem to find anything that is blatantly obvious. I’ve tried appending “(opens in a new window)”, to the link, but that messes up the design. I thought about changing the color of the link, or using a dashed underline, instead of a solid one, but your basic web user isn’t going to pick up something that subtle. I was also suggested by a colleague to just put text in the title. But the chances of someone waiting that long before their finger slams the mouse is slim. And using JavaScript to load something more instantly, seems bloated.&lt;/p&gt;

&lt;p&gt;The most obvious technique I’ve found I saw for the first time with &lt;a href=&quot;http://www.mantisbt.org/&quot;&gt;Mantis&lt;/a&gt;, a bug tracking system, which was to append a “[^]” to the end of every link. The link, itself would always open in the same window, but if you clicked on that little character, it would open in a new window. But then, why not just right click and let your browser handle it (“Open in a New Window,” or “Open in a New Tab”, Ctrl + Click, etc.).&lt;/p&gt;

&lt;p&gt;Ultimately, I think the best solution would be totally default settings that the browser could pick up. Just like a link default is by default blue and underlined. Even then, I suppose it’s a browser setting, but we’d be closer to a consistent solution. Or everyone could just agree to something, which I suppose I’d be OK with…&lt;/p&gt;

&lt;p&gt;…as long as I’m part of the conversation.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Deploying a Site via DNS - "That was Easy!"</title>
   <link href="http://avandamiri.com/2008/06/05/deploying-a-site-via-dns-that-was-easy.html"/>
   <updated>2008-06-05T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/06/05/deploying-a-site-via-dns-that-was-easy</id>
   <content type="html">&lt;p&gt;I launched a site today for &lt;a href=&quot;http://www.northpointhorizons.com&quot;&gt;Northpoint Horizons&lt;/a&gt;, and it was seriously one of the simplest deployments I’ve ever experienced.&lt;/p&gt;

&lt;p&gt;We’ve been working on the site for months on the future (now current) production server. We’ve used it for the client to review the site, to perform testing, everything you’d do with you traditional development environment. All the meanwhile, the DNS for northpointhorizons.com has been pointing at some sandbox with an “under construction” banner. So after rigorously reviewing the “staged” site with the client and completely approving it for launch, we just flicked a switch pointing the DNS right to our environment and everything just worked.&lt;/p&gt;

&lt;p&gt;I can’t imagine deploying a website, at least v1.0, any other way.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>AJAX Form Validation for Rails</title>
   <link href="http://avandamiri.com/2008/05/06/ajax-form-validation-for-rails.html"/>
   <updated>2008-05-06T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/05/06/ajax-form-validation-for-rails</id>
   <content type="html">&lt;p&gt;Last Saturday at the &lt;a href=&quot;http://chicagoruby.org/&quot;&gt;Chicago Ruby User Group&lt;/a&gt; I gave a short presentation on Rails and AJAX. For part of the presentation I decided to solve a problem that’s haunted me as a web developer for some time – form validation.&lt;/p&gt;

&lt;h2 id=&quot;heres-the-dilemma&quot;&gt;Here’s the dilemma:&lt;/h2&gt;

&lt;p&gt;You start with server side validation, then build your form. To validate the inputs, you have to make a round trip to the server, and re-render the entire page with the validation messages. Not the smoothest process, given the bar set by Web 2.0. But at the same time, if you try to engage the user more, you find yourself writing the same validation in JavaScript for the client – not fun.&lt;/p&gt;

&lt;h2 id=&quot;heres-the-solution&quot;&gt;Here’s the solution:&lt;/h2&gt;

&lt;p&gt;Again, start with server side validation and a form. Then use JavaScript not to validate the data, but to facilitate an AJAX request to the server, where you there validate the field and send simple feedback to the user.&lt;/p&gt;

&lt;p&gt;I started by searching for solutions for this. As it appears, I’m not the only developer in the room who wants AJAX validation. Here’s what I found:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.davidjrice.co.uk/articles/2006/11/29/inline-ajax-form-validation-plugin-for-ruby-on-rails&quot;&gt;http://www.davidjrice.co.uk/articles/2006/11/29/inline-ajax-form-validation-plugin-for-ruby-on-rails&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.ineightydays.com/archives/validating-an-ajax-form-in-ruby-on-rails&quot;&gt;http://www.ineightydays.com/archives/validating-an-ajax-form-in-ruby-on-rails&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.bigsmoke.us/ajax-validation-on-rails/&quot;&gt;http://www.bigsmoke.us/ajax-validation-on-rails/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I opted, for the sake of practice, to use these as inspiration to my own solution, which goes something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;error_message_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tag_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_validator&quot;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# generate javascript for AJAX request and field observation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;new Ajax.Request(&apos;/users/validate?field=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;value=&apos; + value, {&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;method: &apos;get&apos;,&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;onSuccess: function(transport) {&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;element = document.getElementById(&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tag_id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;);&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;var output = transport.responseText;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;var css_class = &apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:error_css_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;if (output.length == 0) {&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;output = &apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;css_class = &apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:success_css_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;}&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;element.innerHTML = output;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;element.setAttribute(&apos;class&apos;, css_class)&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;}&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot; });&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;js&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;observe_field&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# generate html for placing error message&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hint_css_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;js&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I wanted my solution to be equally elegant as &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/ActiveRecordHelper.html#M001005&quot;&gt;Rails’ non-Ajax solution&lt;/a&gt;, so I created a method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error_message_for&lt;/code&gt;, which takes the model, field name, and various options. First, it creates the JavaScript I’ll need with &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M000966&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;observe_field&lt;/code&gt;&lt;/a&gt;, wiring up the Ajax request to the field we’re monitoring. Then, using &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#M001033&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content_tag&lt;/code&gt;&lt;/a&gt; produces an empty tag which will serve as our feedback placeholder. It returns all that HTML/JS to the browser. But, we haven’t done any validation yet. For that we need a validate action that can be called on whatever model you’re working with (in this case I’m working with a User):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;validate&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;valid?&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# trigger the errors hash to be filled&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;titleize&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;titleize&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sentence&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, we’re cooking. As the user moves from field to field, the AJAX request we wrote is created, firing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt;. Validate then uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valid?&lt;/code&gt; method to populate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;errors&lt;/code&gt; collection on our model which in turn allows us to return the same error messages Rails would if we were using &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/ActiveRecordHelper.html#M001005&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error_message_on&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we just implement it. Call our new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error_message_for&lt;/code&gt; method right after the input field like so and that’s a wrap. The HTML and JS is returned to the browser when the page renders the first time. When focus leaves a particular field, its value is sent down to the server for validation, and the server replies with whatever applicable error messages, which are displayed in the originally empty HTML generated to begin with.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;text_field&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;error_message_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:hint&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Your email must be formatted properly.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:success&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Looking good!&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You may have noticed some code in there referring to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:success&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:hint&lt;/code&gt;. I figure, while we’re in there let’s add support for a hint to be displayed before any validation occurs, and a success message to display when validation is passed.&lt;/p&gt;

&lt;p&gt;The best part of the whole thing, is it’s really DRY (Don’t Repeat Yourself), and therefore simple. Change your validation rules, and the UI updates dynamically. In addition the same approach can be used on any form that has an underlying model associated with it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://cloud.avandamiri.com/3L1z1Y0U2f3P&quot;&gt;Download an example from GitHub.&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Peeling Up</title>
   <link href="http://avandamiri.com/2008/04/15/peeling-up.html"/>
   <updated>2008-04-15T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/04/15/peeling-up</id>
   <content type="html">&lt;p&gt;I’m not sure when exactly it happened, but drop shadows and rounded corners struck the web with a vengeance. Then it was the reflections. It seems like those persnickety designers are looking for anyway to make our lives as developers harder. But they have a fairly noble goal, anyway - to give a 2D fairly boring web page &lt;em&gt;depth&lt;/em&gt;. I’m a big fan.&lt;/p&gt;

&lt;p&gt;But at the same time, I find it very frustrating. Both rounded corners and drop shadows make dynamic widths a nightmare. Then there’s the issue of a drop shadow spanning two background colors with full translucency support. Solving any of these problems elegantly is a challenge. So recently I’ve
been looking for &lt;em&gt;simple&lt;/em&gt; ways to evoke the same illusion of depth. I think I’ve found two, but I’ll talk about one here.&lt;/p&gt;

&lt;p&gt;Every since I signed up for &lt;a href=&quot;http://www.linkedin.com&quot;&gt;LinkedIn&lt;/a&gt;, I’ve been dying for them to do a redesign. After logging in I felt totally inundated with information, and found it very challenging to navigate. Aside from the fact that a few months back they totally overhauled the design, they added
a really slick design paradigm I’ve never seen before and I was really impressed. I’m referring to this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2562/4169458440_fcd4a28052_o.png&quot; alt=&quot;LinkedIn Peeling Up Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Do you see what I’m referring to? It’s the peeling up effect below the “Add Connections” button. It doesn’t solve &lt;em&gt;all&lt;/em&gt; the problems, but it definitely makes it easier than extending a drop shadow all the way up one side of that floating box. They actually call the class on that div “sticky-box” which I think embodies that “peel up” perfectly. Bravo LinkedIn!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Skepticism Happens {Here}</title>
   <link href="http://avandamiri.com/2008/03/11/skepticism-happens-here.html"/>
   <updated>2008-03-11T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/03/11/skepticism-happens-here</id>
   <content type="html">&lt;p&gt;I attended Microsoft’s 2008 Product Launch Event, &lt;a href=&quot;http://www.microsoft.com/heroeshappenhere/default.mspx&quot;&gt;Heroes Happen {Here}&lt;/a&gt;, today and I think my suspicions have been officially confirmed.&lt;/p&gt;

&lt;p&gt;My interest in Microsoft products has been waning as of late. Nevertheless, attending a Microsoft launch event is a good reason to get free schwag, and they do a decent job of highlighting what to look for in their new products.&lt;/p&gt;

&lt;p&gt;Products? Let’s take a minute to dissect what that means.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;http://www.freakonomics.com&quot;&gt;Freakonomics&lt;/a&gt;, Stephen D. Levitt talks about the simple law of incentives. Real estate brokers, he argues, don’t stand much to gain by selling your house for a few thousand dollars more. By the time they get their commission, that few grand is only a few hundred dollars. In fact, to that point, they could make far more, by selling another house with the time and effort it might take to “wait it out.” Understanding this incentive is the golden key for sifting through potential B.S.&lt;/p&gt;

&lt;p&gt;What does that have to do with Microsoft?&lt;/p&gt;

&lt;p&gt;Well, Microsoft is selling a product after all. They make money when you buy VisualStudio 2008, SQL Server 2008, and Windows Server 2008. And that’s really only the beginning. Once you’re hooked (I walked away with a free copy of each), then they &lt;em&gt;really&lt;/em&gt; take you for a wild ride with production licensing.&lt;/p&gt;

&lt;p&gt;Now, &lt;em&gt;I’m not saying that is bad&lt;/em&gt;. To the contrary. Your business needs paper, staplers, and desks, too. It needs all kinds of tangibles that someone makes money by supplying. It’s an awesome system that pretty much drives commerce.&lt;/p&gt;

&lt;p&gt;But at the same time, when I see the same UpdatePanel demo in the developer track that I saw &lt;a href=&quot;http://www.cnug.org/Default.aspx?tabid=31&quot;&gt;last year at the Chicago .NET User Group&lt;/a&gt;, I become skeptical. When Split View, one of the most prominent features evangelized at the conference, brings my friend to say “uh, duh, Dreamweaver,” I become skeptical. And what about LINQ? Try on &lt;a href=&quot;http://wiki.rubyonrails.org/rails/pages/ActiveRecord&quot;&gt;ActiveRecord&lt;/a&gt; for size - it’s free. Silverlight? Ever heard of Flash? And how about instead of banking on the drag and drop AJAX Toolkit, you actually &lt;em&gt;learn&lt;/em&gt; JavaScript. You are after all a web developer, right?&lt;/p&gt;

&lt;p&gt;But it wasn’t all bad. JavaScript debugging and JS IntelliSense are very cool. The load tests also seem cool.&lt;/p&gt;

&lt;p&gt;I just want to keep it simple. In one of the presentations, a speaker referred to JavaScript as one of the “bane of a web developer’s existence;” and you might say an UpdatePanel is the &lt;em&gt;definition&lt;/em&gt; of simple. But to who? A dilettante or a developer?&lt;/p&gt;

&lt;p&gt;If you want to do anything there’s a learning curve. If you embrace that curve you’ll find that there are simple, cheap, even free tools that replace the Microsoft suite, backed by hundreds of smart people who did the same.&lt;/p&gt;

&lt;p&gt;And knowing that, it’s hard for me to bank on the guy &lt;a href=&quot;http://en.wikipedia.org/wiki/Bill_Gates&apos;_house&quot;&gt;counting all his cash&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Best Tool for the Job</title>
   <link href="http://avandamiri.com/2008/03/05/best-tool-for-the-job.html"/>
   <updated>2008-03-05T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/03/05/best-tool-for-the-job</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.codinghorror.com/blog/archives/001065.html&quot;&gt;The religious wars go on&lt;/a&gt;. Microsoft vs. the rest of the world, it seems. On and on, ad infinitum.&lt;/p&gt;

&lt;p&gt;But does it ever really matter? Is there definitively a platform of choice? Or more to the point, is that question even valid? Can there be a definite? As Jeff Atwood points out, every technology flexes different strengths and exposes certain weaknesses. Knowing the pros and cons will help you determine the best tool for the job.&lt;/p&gt;

&lt;p&gt;I recently started re-reading parts of Marshall Goldsmith’s &lt;a href=&quot;http://www.amazon.com/What-Got-Here-Wont-There/dp/1401301304&quot;&gt;What Got you Here, Won’t Get You There&lt;/a&gt;. Goldsmith, an organizational psychologist, describes a terribly negative characteristic common among successful people dubbed as the “need to win.” Developers have got a serious case of it.&lt;/p&gt;

&lt;p&gt;Looking for a feeding frenzy better than &lt;a href=&quot;http://dsc.discovery.com/convergence/sharkweek/sharkweek.html&quot;&gt;Shark Week&lt;/a&gt; on the Discovery Channel? Go into a room of shark, oops, I mean &lt;em&gt;sharp&lt;/em&gt;, developers and ask what’s the best way to refactor some classes to support an MVC architecture. Before you know it, you’ve got 100 ways to solve the same problem. How do you pick?&lt;/p&gt;

&lt;p&gt;Keep it simple, stupid. You don’t need a sledgehammer to hang a picture (although it might be fun). You don’t perform brain surgery with a chainsaw (I’m looking at you, &lt;a href=&quot;http://en.wikipedia.org/wiki/Quentin_Tarantino&quot;&gt;Tarantino&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Unfortunately for software developers, knowing which tools to keep in that tool belt can be daunting. Each platform presumably exists for some reason or another. They don’t just write 300 page, $50.00 software text books for fun. So it’s got &lt;em&gt;something&lt;/em&gt; going for it (or at least it did), even if it might not be much. Some guy, just as smart as you, probably smarter, was on the other side of your criticism when he built the damn thing. Unlike other industries, where there may be a definitive right way to execute, technologists grapple with hundreds of choices and decisions. So to really be able to know which tool is best for the job takes years of exposure, education, and error.&lt;/p&gt;

&lt;p&gt;So take it upon yourself to constantly challenge the risk/reward of a given platform - arm yourself with an arsenal of tools that suits the job you need to accomplish. Picking sides, after all, violates the whole spirit of software development. So let’s stop arguing already and build something &lt;a href=&quot;http://www.stanthecaddy.com/sounds-sidra-theyre-real-and-spectacular.html&quot;&gt;spectacular&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>A Look Back at Windows Mobile 6.0 and ActiveSync</title>
   <link href="http://avandamiri.com/2008/02/12/a-look-back-at-windows-mobile-6-0-and-activesync.html"/>
   <updated>2008-02-12T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2008/02/12/a-look-back-at-windows-mobile-6-0-and-activesync</id>
   <content type="html">&lt;p&gt;While I was walking home from work today, checking my email on my iPhone, something very strange occurred to me. Once upon a time, I was a Windows Mobile junkie. Not just a standard user but an all out fan boy. I would  talk to whoever was willing to listen about how awesome my Treo 750 was and how awesome of a job ActiveSync did at keeping everything, well, synced. So I started to wonder what happened?&lt;/p&gt;

&lt;p&gt;A little background might help here. I made the conversion to Apple (iPhone, iPod, MacBook Pro) about 7 months ago. Before that I was all Windows, all the way. The conversion was sparked by two things. My interest in Ruby on Rails, a very rapid web development framework, which works best on Mac OSX and, the topic of conversation here, my desire to separate work from play. I was blown away.&lt;/p&gt;

&lt;p&gt;ActiveSync, which requires an Exchange Server, is awesome. Loose your phone? No problem, your calendar, contacts, email, it’s all synced. Out of sight, out of mind. It also syncs really fast, with almost no lag from the minute something happens in Outlook to when it hits your phone.&lt;/p&gt;

&lt;p&gt;But I wanted to separate work from play and I couldn’t seem to do it. Microsoft sells products, and as a result, no matter how awesome the product is, it’s limitations are in MSFT’s hands. So I switched to a more “open source” solution.&lt;/p&gt;

&lt;p&gt;Now I’ve got both work and personal email happily IMAP’ing to my phone, contacts syncing to my Mac, along with the gigs of video and audio I have as well. No, my calendar doesn’t sync over the air. No, I can’t accept meeting invitations but I think I’m OK with that. The things it does do well, it does amazingly let alone the interface of the iPhone. It’s stable, which is a lot more than any Windows Mobile device can say. Every time a call came through it was like my Treo was having an aneurism. It really tried to keep up, but always seemed a few steps behind. Meanwhile the iPhone “just works.” Incoming call during a song? Music fades out, call fades in. It’s beautiful.&lt;/p&gt;

&lt;p&gt;So all in all, I’m happy I made the switch. More than anything, I’m glad that my personal stuff is out of my corporate account. But hey, the phone’s cool too.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introduction to this Blog</title>
   <link href="http://avandamiri.com/2007/07/22/introduction.html"/>
   <updated>2007-07-22T00:00:00+00:00</updated>
   <id>http://avandamiri.com/2007/07/22/introduction</id>
   <content type="html">&lt;p&gt;Throughout my life, I’ve always had a knack for design. As a kid, I grew up in a house surrounded by fine art and lots of art classes. In my teens, I spent my Saturdays at the Museum of Fine Arts in Boston. However, along the way, I also feel in love with technology. I love computers, gadgets, iPhones, the internet, and especially web design.&lt;/p&gt;

&lt;p&gt;So throughout my day to day trials and tribulations, I come across things that pique my interest. Design and usability flaws that are so minor that most people steam right over them. Some might call them insignificant, but I believe it’s important to be picky. It’s what ultimately separates the wheat from the chafe.&lt;/p&gt;

&lt;p&gt;Simple things like why a refrigerator ice dispenser doesn’t revert back to “Water” after a few minutes of inactivity? Why North Face stores don’t have a coat racks? Why a brand new OS might have a wonderful animation library of fades and shadows but then abruptly blink to life when waking up. Why certain applications are huge successes, and others fall to the curb?&lt;/p&gt;

&lt;p&gt;These are all questions that interest me, and that I hope to explore with this blog. The theme has a long chain to roam on but will stay within the intersection of design and technology, with a few usability and user experience tangents along the way.&lt;/p&gt;

&lt;p&gt;I hope you enjoy it,&lt;/p&gt;

&lt;p&gt;Avand&lt;/p&gt;
</content>
 </entry>
 

</feed>
