<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.avandamiri.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Avand.</title>
 
 <link href="http://avandamiri.com/" />
 <updated>2012-02-20T10:44:11-08:00</updated>
 <id>http://avandamiri.com/</id>
 <author>
   <name>Avand Amiri</name>
   <email>avand@avandamiri.com</email>
 </author>
 
 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.avandamiri.com/avand" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="avand" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><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-07: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='http://www.sqoot.com/'&gt;daily deal API&lt;/a&gt; I&amp;#8217;m working on, the subject of the &lt;a href='http://www.robotstxt.org/'&gt;robots.txt&lt;/a&gt; came up. In addition to our production environment (what you and everyone else see), we also use an &amp;#8220;edge&amp;#8221; environment. It&amp;#8217;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&amp;#8217;t want to get dinged with content duplication we had to disallow spiders from crawling our edge environment. Here&amp;#8217;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&gt;RobotsGenerator&lt;/code&gt; in lib&lt;/li&gt;

&lt;li&gt;Point &lt;code&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;RobotsGenerator&lt;/span&gt;
  &lt;span class='c1'&gt;# Use the config/robots.txt in production.&lt;/span&gt;
  &lt;span class='c1'&gt;# Disallow everything for all other environments.&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;call&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;production?&lt;/span&gt;
      &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;root&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;config&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;robots.txt&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;User-agent: *&lt;/span&gt;&lt;span class='se'&gt;\n&lt;/span&gt;&lt;span class='s2'&gt;Disallow: /&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='c1'&gt;# Heroku can cache content for free using Varnish&lt;/span&gt;
    &lt;span class='n'&gt;headers&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Cache-Control&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;public, max-age=&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;year&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;seconds&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;200&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;headers&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;
  &lt;span class='k'&gt;rescue&lt;/span&gt; &lt;span class='no'&gt;Errno&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ENOENT&lt;/span&gt;
    &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;404&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{},&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;# A robots.txt is not configured&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;config/routes.rb&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;YourApplication&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;routes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# ...&lt;/span&gt;

  &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/robots.txt&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;RobotsGenerator&lt;/span&gt;

  &lt;span class='c1'&gt;# ...&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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-07: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&amp;#8217;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&amp;#8217;s how I created this 60 second video explaining &lt;a href='http://thezippr.com/'&gt;Zippr&lt;/a&gt; in about 6 hours with a laptop, markers, paper, $2.00 and the &lt;a href='http://grooveshark.com/#/album/Tron+Legacy+Reconfigured/5892109'&gt;Tron Legacy Reconfigured&lt;/a&gt; album.&lt;/p&gt;
&lt;object height='300' width='400'&gt;&lt;param name='allowfullscreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;param name='movie' value='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' /&gt;&lt;embed src='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' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='300' width='400' /&gt;&lt;/object&gt;
&lt;h2 id='ingredients'&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&amp;#8221; x 11&amp;#8221;. 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='directions'&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&amp;#8217;t have time to get into detail, so keep it short and sweet. Make sure you answer these questions for your customers: what&amp;#8217;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&amp;#8217; x 11&amp;#8217; piece of paper into 9 quadrants and sketch each &amp;#8220;scene.&amp;#8221; 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&amp;#8217;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&amp;#8217;re in a well lit room. Set up lamps around your computer to provide a nice bright shot. More importantly &lt;em&gt;don&amp;#8217;t change the lighting once you start&lt;/em&gt;.&lt;/li&gt;

&lt;li&gt;Start drawing. You&amp;#8217;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&amp;#8217;d recommend doing it in one shot because ambient lighting can change. Verify your work after each scene to make sure you&amp;#8217;re on track. Remember, you can&amp;#8217;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&amp;#8217;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='http://friendlymusic.com/'&gt;Friendly Music&lt;/a&gt;. I searched for &amp;#8220;whistle&amp;#8221; 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='nutritional_information'&gt;Nutritional Information&lt;/h2&gt;

&lt;p&gt;That&amp;#8217;s basically it. You can export from iMovie to whatever file format you&amp;#8217;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&amp;#8217;t have a budget for a &amp;#8220;real&amp;#8221; 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&amp;#8217;re doing something different, you don&amp;#8217;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-07: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='http://www.sqoot.com/'&gt;Sqoot&lt;/a&gt;. Let&amp;#8217;s dive right into the code and then talk about how we got here.&lt;/p&gt;

&lt;h2 id='diving_right_in'&gt;Diving Right In&lt;/h2&gt;

&lt;p&gt;We start with a simple &lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt; web app:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;erb&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;active_support&amp;#39;&lt;/span&gt;

&lt;span class='no'&gt;PROCESSES&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:solr&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:memcached&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:mongo&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='c1'&gt;# ...can be anything&lt;/span&gt;

&lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# Ask each process what its status is (e.g., { :solr =&amp;gt; true, ... })&lt;/span&gt;
  &lt;span class='vi'&gt;@process_statuses&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;PROCESSES&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inject&lt;/span&gt;&lt;span class='p'&gt;({})&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;memo&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;memo&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;_up?&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;memo&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='c1'&gt;# Set the response code to 200 if all the statuses are up&lt;/span&gt;
  &lt;span class='n'&gt;status&lt;/span&gt; &lt;span class='vi'&gt;@process_statuses&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all?&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;v&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;v&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='p'&gt;?&lt;/span&gt; &lt;span class='mi'&gt;200&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;503&lt;/span&gt;

  &lt;span class='n'&gt;erb&lt;/span&gt; &lt;span class='ss'&gt;:index&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then we just need a bunch of &lt;code&gt;_up?&lt;/code&gt; methods to do the checking, like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;httparty&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;solr_up?&lt;/span&gt;
  &lt;span class='n'&gt;solr_host&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span class='c1'&gt;# replace with your Solr server&lt;/span&gt;
  &lt;span class='no'&gt;HTTParty&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;http://&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;solr_host&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/admin/ping&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;success?&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In addition to &lt;a href='http://lucene.apache.org/solr/'&gt;Solr&lt;/a&gt;, we also make sure that &lt;a href='https://gist.github.com/950677'&gt;Mongo&lt;/a&gt; and &lt;a href='https://gist.github.com/950680'&gt;Memcached&lt;/a&gt; are running.&lt;/p&gt;

&lt;p&gt;Finally, we need a couple endpoints for &lt;a href='http://www.pingdom.com/'&gt;Pingdom&lt;/a&gt; to hit (e.g, &lt;a href='http://status.sqoot.com/solr/'&gt;&lt;code&gt;/solr&lt;/code&gt;&lt;/a&gt;) so that we can check each service independently:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;PROCESSES&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@process&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;process&lt;/span&gt;
    &lt;span class='vi'&gt;@status&lt;/span&gt;  &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;process&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;_up?&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

    &lt;span class='n'&gt;status&lt;/span&gt; &lt;span class='vi'&gt;@status&lt;/span&gt; &lt;span class='p'&gt;?&lt;/span&gt; &lt;span class='mi'&gt;200&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;503&lt;/span&gt;

    &lt;span class='n'&gt;erb&lt;/span&gt; &lt;span class='ss'&gt;:process&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Add a couple trivial views, some CSS3 awesome, and voilà, you&amp;#8217;ve got &lt;a href='http://status.sqoot.com/'&gt;status.sqoot.com&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id='taking_a_step_back'&gt;Taking a Step Back&lt;/h2&gt;

&lt;p&gt;The first thing we did to monitor uptime was point &lt;a href='http://www.pingdom.com/'&gt;Pingdom&lt;/a&gt; at &lt;a href='http://www.sqoot.com/'&gt;Sqoot&lt;/a&gt;&amp;#8217;s homepage. We would perform some trivial check and when the site went down we dealt with a deluge of errors we couldn&amp;#8217;t do anything about (e.g., &lt;code&gt;Timeout::Error&lt;/code&gt;). Since we use &lt;a href='http://hoptoadapp.com/'&gt;Hoptoad&lt;/a&gt; to stay on top of application exceptions all these errors got really noisy. We also still didn&amp;#8217;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&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&amp;#8217;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-07:00</updated>
   <id>http://avandamiri.com/2011/03/29/tests-pass-you-fail</id>
   <content type="html">&lt;p&gt;Shit breaks. It&amp;#8217;d be so much cooler if things just worked the way we expected, but they don&amp;#8217;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&amp;#8217;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='you_stop_looking_forward'&gt;You Stop Looking Forward&lt;/h2&gt;
&lt;img title='Looking Forward Fail' class='right' src='http://farm6.static.flickr.com/5134/5575368800_3a1e157df1_m.jpg' alt='Looking Forward Fail' /&gt;
&lt;p&gt;Just because your tests look back doesn&amp;#8217;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&amp;#8217;re looking for opportunities to make your product better. But even if you&amp;#8217;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&amp;#8217;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='you_lose_sight_of_your_customer'&gt;You Lose Sight of Your Customer&lt;/h2&gt;
&lt;img title='Focusing on Customer Fail' class='right' src='http://farm6.static.flickr.com/5265/5574782175_e9b08ab39a_m.jpg' alt='Focusing on Customer Fail' /&gt;
&lt;p&gt;Passing tests are quite a high. Engineers are always looking for cold hard facts. Passing tests take the edge off: &amp;#8220;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!&amp;#8221;&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&amp;#8217;s a great thing. But it&amp;#8217;s easy to chase that high by writing tests that don&amp;#8217;t test the right thing, test something that&amp;#8217;s already tested or, worse, pass despite a feature that still doesn&amp;#8217;t work correctly.&lt;/p&gt;

&lt;p&gt;Don&amp;#8217;t lose sight of your customers in spite of your test coverage.&lt;/p&gt;

&lt;h2 id='you_fear_failure'&gt;You Fear Failure&lt;/h2&gt;
&lt;img title='Failing at Failing' class='right' src='http://farm6.static.flickr.com/5253/5574803627_2129538b6c_m.jpg' alt='Failing at Failing' /&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='http://robots.thoughtbot.com/post/4191116705/updates-on-hoptoad'&gt;handle it the right way&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OK, that&amp;#8217;s not always true. If you&amp;#8217;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&amp;#8217;re like me, trying to break through to &lt;a href='http://en.wikipedia.org/wiki/Diffusion_of_innovations'&gt;meaty part of the adoption curve&lt;/a&gt;, then isn&amp;#8217;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='http://www.amazon.com/Raving-Fans-Revolutionary-Approach-Customer/dp/0688123163'&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;&lt;a href='http://twitter.com/bramcohen/status/51714087842877440'&gt;&amp;#8220;90% of coding is debugging. The other 10% is writing bugs&amp;#8221;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#8211; @bramcohen&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Show-stopping bugs are easy to prevent. At &lt;a href='http://www.sqoot.com'&gt;Sqoot&lt;/a&gt; we use a few tools that I consider just as important as &lt;code&gt;rake test&lt;/code&gt;. &lt;a href='http://github.com/avand/squawk'&gt;Squawk&lt;/a&gt;, a gem I wrote that let&amp;#8217;s our app tweet, gives us live feedback (good, bad and ugly). &lt;a href='http://pingdom.com'&gt;Pingdom&lt;/a&gt; hits our endpoints every minute to ensure uptime. &lt;a href='http://hoptoadapp.com'&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='you_slow_down'&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&amp;#8217;t want to stop. Untested code becomes a second-class citizen. But that&amp;#8217;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&amp;#8217;s tested, you think twice. This is especially true when you&amp;#8217;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&amp;#8217;s easy to get lost in a world of tools and process. Unless you&amp;#8217;re GitHub, your product is probably not other developers.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href='http://algeri-wong.com/yishan/engineering-management-process.html'&gt;&amp;#8220;New process is reluctantly introduced only right before the point where things tip into chaos&amp;#8221;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#8211; Yishan Wong on Facebook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='now_before_you_roast_me_on_hn'&gt;Now, Before You Roast Me on HN&amp;#8230;&lt;/h2&gt;

&lt;p&gt;By this point, I&amp;#8217;ve probably ruffled some feathers. So let me be clear that testing isn&amp;#8217;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&amp;#8217;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='http://piggyback.it/'&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;Loaded suite /Users/avand/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..................................................................................................................................................................................................
Finished in 5.778192 seconds.

194 tests, 290 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 50633
Loaded suite /Users/avand/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..............................................
Finished in 13.691397 seconds.

46 tests, 56 assertions, 0 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you&amp;#8217;re saying to yourself &amp;#8220;13 seconds to run 46 tests is slow,&amp;#8221; you may want to re-read this post or double-down and check out &lt;a href='https://github.com/thumblemonks/riot'&gt;riot&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='happy_customers_are_all_that_matters'&gt;Happy Customers are All That Matters&lt;/h2&gt;

&lt;p&gt;I don&amp;#8217;t enjoy writing &lt;a href='http://avandamiri.com/2010/02/08/getting-it-what-makes-a-great-software-engineer.html'&gt;code for code&amp;#8217;s sake&lt;/a&gt;. It&amp;#8217;s ironic to think you might even evaluate a software engineer by the code he doesn&amp;#8217;t write. Coding is fun, it&amp;#8217;s addictive and it&amp;#8217;s a bit hypnotic. So you have to be really careful that the code you&amp;#8217;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&amp;#8217;re working on doesn&amp;#8217;t answer that question with a huge &amp;#8220;yes&amp;#8221; then you&amp;#8217;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-07:00</updated>
   <id>http://avandamiri.com/2010/09/15/managing-styles-with-sass-on-heroku</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: I presented on the topics of this post at &lt;a href='http://www.meetup.com/ChicagoRuby'&gt;Chicago Ruby&lt;/a&gt; and &lt;a href='http://www.refreshchi.org/'&gt;Refresh&lt;/a&gt;. The &lt;a href='http://ontwik.com/javascript/simple-javascript-css-management-with-rack-by-avand-amiri/'&gt;video&lt;/a&gt; and &lt;a href='http://avandamiri.com/slides/css-js-rack.html'&gt;slides&lt;/a&gt; are now available online. (May 1st, 2011)&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve generally found stylesheets to be the messiest part of any website. And I&amp;#8217;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='http://video.google.com/videoplay?docid=-4101280286098310645'&gt;It&amp;#8217;s someone else&amp;#8217;s job&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But organizing styles doesn&amp;#8217;t have to be a mess and here&amp;#8217;s one strategy that may make your life easier.&lt;/p&gt;

&lt;h2 id='but_first'&gt;But First&amp;#8230;&lt;/h2&gt;

&lt;p&gt;Since &lt;a href='http://edgeguides.rubyonrails.org/routing.html'&gt;REST&lt;/a&gt; became the de facto way to design &lt;a href='http://rubyonrails.org'&gt;Rails&lt;/a&gt; apps, I&amp;#8217;ve focused on organizing stylesheets by the same patterns. It just seemed natural that if you had a folder &lt;code&gt;/views/users/new.html.erb&lt;/code&gt; you should have a similiar folder &lt;code&gt;/stylesheets/users/new.css&lt;/code&gt;. Back in 2008, I wrote a &lt;a href='http://avandamiri.com/2008/11/19/css-tricks-2-of-2-using-rails-to-manage-styles.html'&gt;two part post&lt;/a&gt; on how to do this nicely with Rails. Three years later, I&amp;#8217;m &lt;a href='http://2009.windycityrails.org/videos#8'&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='http://www.css3.info/'&gt;update&lt;/a&gt;. &lt;a href='http://sass-lang.com'&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='why_start_from_scratch'&gt;Why Start from Scratch?&lt;/h2&gt;
&lt;img title='Beware of Dog' class='right' src='http://farm5.static.flickr.com/4124/4994576910_2986eef71b_m_d.jpg' alt='Beware of Dog' /&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&amp;#8217;m masochistic&lt;/strong&gt;: I wanted it to work a certain way. I didn&amp;#8217;t want to wrangle with a &lt;a href='http://compass-style.org/'&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='http://www.heroku.com'&gt;Heroku&lt;/a&gt; has a (&lt;a href='http://docs.heroku.com/constraints#read-only-filesystem'&gt;mostly&lt;/a&gt;) read-only filesystem. &lt;a href='http://www.hulu.com/watch/19280/saturday-night-live-debbie-downer-birthday-party'&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='http://github.com/pedro/hassle'&gt;few workarounds&lt;/a&gt; that involve serving CSS from &lt;code&gt;/tmp&lt;/code&gt;, but I didn&amp;#8217;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='http://developer.yahoo.com/yslow/'&gt;Everyone should know&lt;/a&gt; &lt;a href='http://code.google.com/speed/page-speed/'&gt;by now&lt;/a&gt; that the HTTP overhead of requesting multiple CSS files degrades client performance. But you can&amp;#8217;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='http://synthesis.sbecker.net/pages/asset_packager'&gt;had a solution&lt;/a&gt;, but not with &lt;a href='http://docs.heroku.com/git'&gt;Git based deployments&lt;/a&gt; on Heroku and the &lt;a href='http://github.com/dim/sphere'&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&amp;#8217;t be this god damn complicated.&lt;/p&gt;

&lt;h2 id='ftw'&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&amp;#8217;t have to rewrite all your CSS to get started. &lt;a href='http://sass-lang.com/docs/yardoc/file.SASS_CHANGELOG.html'&gt;Scss plays nice&lt;/a&gt;. It&amp;#8217;s part of &lt;a href='http://haml-lang.com/'&gt;Haml&lt;/a&gt;, so throw it in your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;haml&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;3.0.18&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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&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&amp;#8217;ll do that later.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nv'&gt;$&amp;gt;&lt;/span&gt; sass-convert source.css destination.scss
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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='http://chrisjpowers.com/'&gt;Chris Powers&lt;/a&gt; noted that it was cleaner to store them in &lt;code&gt;/app/stylesheets/:package/&lt;/code&gt;. For me, &lt;code&gt;:package&lt;/code&gt; was just &amp;#8220;desktop.&amp;#8221; Later, I can easily create packages called &amp;#8220;mobile,&amp;#8221; &amp;#8220;print,&amp;#8221; or &amp;#8220;ie&amp;#8221; if I need to. See?&lt;/li&gt;
&lt;/ul&gt;
&lt;img title='Template and Styles, Happily Ever After' src='http://farm5.static.flickr.com/4088/4994576870_31e45aceab_d.jpg' alt='Template and Styles, Happily Ever After' /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use Rack to do all the heavy lifting&lt;/strong&gt;: Compiling Scss isn&amp;#8217;t hard. Concatinating all the stylesheets isn&amp;#8217;t hard either. &lt;a href='http://asciicasts.com/episodes/222-rack-in-rails-3'&gt;Ryan Bates&amp;#8217; 222nd Railscast&lt;/a&gt; helped me write a Rack application that does the work:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;AssetsApp&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActionController&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Metal&lt;/span&gt;  
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;ActionController&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rendering&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;stylesheets&lt;/span&gt;
    &lt;span class='vi'&gt;@output&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;

    &lt;span class='no'&gt;Dir&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;glob&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;root&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/app/stylesheets/&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:package&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/**/*.css*&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;filename&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
      &lt;span class='n'&gt;sass_options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:syntax&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:scss&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;sass_options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:style&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;:compressed&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;development?&lt;/span&gt;

      &lt;span class='vi'&gt;@output&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='no'&gt;Sass&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Engine&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;open&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;filename&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;sass_options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;render&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;headers&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Cache-Control&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;public, max-age=&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;year&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;seconds&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;development?&lt;/span&gt;
    &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;content_type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;text/css&amp;#39;&lt;/span&gt;

    &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:text&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@output&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Sqoot&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;routes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/stylesheets/:package.css&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;AssetsApp&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;action&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:stylesheets&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;stylesheets&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class='n'&gt;stylesheets_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:package&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:desktop&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='all_together_now'&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&amp;#8217;s happy.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&lt;a href='http://www.varnish-cache.org/'&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='http://gist.github.com/581728'&gt;gist&lt;/a&gt; of the code to try for yourself.&lt;/li&gt;
&lt;/ul&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-07: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, &amp;#8220;agile&amp;#8221; has got to be one of the most popular. It seems that everyone wants to be agile, and there&amp;#8217;s a lot of debate about what that means, &lt;a href='http://www.whattofix.com/blog/archives/2010/09/agile-ruined-my.php'&gt;if anything&lt;/a&gt;. &lt;a href='http://agilemanifesto.org/'&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='http://en.wikipedia.org/wiki/Scrum_(development)'&gt;Scrum&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;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&amp;#8217;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&amp;#8217;ll do X, next week you&amp;#8217;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&amp;#8217;ve found that the shorter the sprint the better. I&amp;#8217;m currently working in four-hour sprints and here&amp;#8217;s why you should too.&lt;/p&gt;

&lt;h2 id='incedental_reasons'&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='for_realzy_reasons'&gt;For Realzy Reasons&lt;/h2&gt;
&lt;img class='right' src='http://farm5.static.flickr.com/4154/4967913623_fd4868b07c_m_d.jpg' alt='4 Hour Timer' /&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&amp;#8217;re doing. You have to ship something! So, get your shit together.&lt;/li&gt;

&lt;li&gt;You can&amp;#8217;t write garbage code: Let&amp;#8217;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&amp;#8217;t have time to fuck around.&lt;/li&gt;

&lt;li&gt;You&amp;#8217;ll get realistic: &lt;a href='http://gettingreal.37signals.com/ch03_Embrace_Constraints.php'&gt;Constraints breed creativity&lt;/a&gt;. You&amp;#8217;ll come up with &lt;a href='http://books.google.com/books?id=QmkgwiB7bL8C&amp;amp;lpg=PA50&amp;amp;ots=uII-aE-bRR&amp;amp;dq=nasa%20apollo%20air%20filter%20crises&amp;amp;pg=PA50#v=onepage&amp;amp;q&amp;amp;f=false'&gt;incredible solutions&lt;/a&gt; to deliver on your deadline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know, this won&amp;#8217;t work for everyone. I&amp;#8217;ve worked on projects where simply deploying was a four hour task in and of itself! That&amp;#8217;s garbage. If this is you, put &amp;#8221;&lt;a href='http://heroku.com'&gt;make deployments easy&lt;/a&gt;&amp;#8221; 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='http://nvie.com/git-model'&gt;branching ninjas&lt;/a&gt; that can compartmentalize features and releases.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re very simple creatures. Most projects, probably the one you&amp;#8217;re working on right now, go over budget and over time. That&amp;#8217;s because, as humans, we grossly overestimate what we&amp;#8217;re capable of actually accomplishing. Don&amp;#8217;t fight it! &lt;a href='http://en.wikipedia.org/wiki/Getting_Things_Done'&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-08: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='http://www.travelchannel.com/TV_Shows/Bizarre_Foods'&gt;Andrew Zimmern&lt;/a&gt; cringe.&lt;/p&gt;

&lt;p&gt;I went to high school at &lt;a href='http://www.bu.edu/academy/'&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&amp;#8217;t play by the book. In tenth grade I was held back and junior year wasn&amp;#8217;t any more promising. My teachers begged me to study, explaining to my parents that I just wasn&amp;#8217;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;After that summer, I was brought out 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='http://www.depaul.edu'&gt;DePaul&lt;/a&gt; maintaining a solid A grade-average.&lt;/p&gt;

&lt;p&gt;Everything seemed copasetic until I dropped out.&lt;/p&gt;

&lt;h2 id='when_school_works'&gt;When School Works&lt;/h2&gt;

&lt;p&gt;It was an issue of motivation. When I&amp;#8217;m told to do something, I ask why. If I don&amp;#8217;t like the answer, I push back, and, depending on my conviction, will eventually just refuse. Turns out that up until college you don&amp;#8217;t have much say in what you learn. Ask why and eventually the answer boils down: you don&amp;#8217;t have choice.&lt;/p&gt;
&lt;img title='Stubborn as an...' class='left' src='http://farm3.static.flickr.com/2753/4365864058_9e9068b030_o.jpg' alt='Ox' /&gt;
&lt;p&gt;I think that&amp;#8217;s bullshit. A lot of what I was told to learn was, in retrospect, totally practical. Study a language and you&amp;#8217;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&amp;#8217;ve ever taken, there were many that were just arbitrarily required. School works when a student is motivated and motivation is fueled by purpose.&lt;/p&gt;

&lt;h2 id='when_it_doesnt'&gt;When It Doesn&amp;#8217;t&lt;/h2&gt;
&lt;img class='right' src='http://farm3.static.flickr.com/2748/4365864084_dc06d529c8_o.jpg' alt='Swiss Army Knife' /&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 learned a lot, but at a price: $1,688.00 per class. Each class was running me about $150.00 bucks.&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&amp;#8217;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 quite literally come out ahead. No opportunity had been jeopardized by an incomplete degree and I&amp;#8217;m humbly optimistic that it never will.&lt;/p&gt;

&lt;h2 id='get_real'&gt;Get Real&lt;/h2&gt;
&lt;img class='left' src='http://farm5.static.flickr.com/4005/4365121309_896682da2c_o.jpg' alt='Diploma' /&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&amp;#8217;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 &amp;#8220;real-life lessons&amp;#8221; 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&amp;#8217;s how it works in the world of software. It should work for other fields, too.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;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='what_about_you'&gt;What About You?&lt;/h2&gt;
&lt;iframe scrolling='no' allowTransparency='true' src='http://avand.wufoo.com/embed/r7x3p9/' frameborder='0' height='190' style='width:100%;border:none'&gt;&lt;a href='http://avand.wufoo.com/forms/r7x3p9/' title='Schooling Survey' rel='nofollow'&gt;Fill out my Wufoo form!&lt;/a&gt;&lt;/iframe&gt;
&lt;h2 id='update_august_1st_2010'&gt;Update (August 1st, 2010)&lt;/h2&gt;

&lt;p&gt;Since writing, I&amp;#8217;ve found several articles regarding the flaws in the academic system. &lt;a href='http://www.martynemko.com/'&gt;Marty Nemko&lt;/a&gt; of U.S. News describes one&amp;#8217;s undergraduate education as &lt;a href='http://www.martynemko.com/articles/americas-most-overrated-product-undergraduate-education_id1234'&gt;America&amp;#8217;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;&amp;#8220;What percent of students would you guess graduate from college within six years? Forty percent. Six out of ten never graduate.&amp;#8221;&lt;/li&gt;

&lt;li&gt;On the social value of attending university: &amp;#8220;Fact: 27% of all undergraduate students binge drink regularly&amp;#8221;&lt;/li&gt;

&lt;li&gt;&amp;#8220;We need to capitalize on students&amp;#8217; desire to learn what they&amp;#8217;re excited about and motivated to learn at that point in time. When kids are at eighteen or twenty, they&amp;#8217;re at their most idealistic. It&amp;#8217;s a great time to teach them about things that are going to foment that idealism. It&amp;#8217;s a great time to teach them about relationships. It&amp;#8217;s a great time to teach them about careers.&amp;#8221;&lt;/li&gt;

&lt;li&gt;&amp;#8220;Colleges produce a shoddy, overpriced product and it&amp;#8217;s time we held them accountable.&amp;#8221;&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-08:00</updated>
   <id>http://avandamiri.com/2010/02/08/getting-it-what-makes-a-great-software-engineer</id>
   <content type="html">&lt;h2 id='introduction'&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve been writing code for a while now and for about the last 2 years there&amp;#8217;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 &amp;#8220;rockstars&amp;#8221;, &amp;#8220;ninjas&amp;#8221;, &amp;#8220;submarine pilots&amp;#8221; or any other catchy title you&amp;#8217;d like. They exist, and they&amp;#8217;re dangerously good at what they do. Let&amp;#8217;s emphasize &lt;em&gt;dangerous&lt;/em&gt; there, because right next to them is a second bucket. You&amp;#8217;ve probably hired them, or worked with them - there might be one sitting right behind you. These guys know what they&amp;#8217;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='http://michaeldwan.com'&gt;Michael Dwan&lt;/a&gt; and I have always said that the ninjas just &amp;#8220;get it.&amp;#8221; In suit, I think it makes sense to refer to them, collectively, as the &amp;#8220;get-its&amp;#8221; and the latter as the &amp;#8220;get-nots.&amp;#8221;&lt;/p&gt;

&lt;h2 id='wait_why_engineer'&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='code_for_codes_sake'&gt;Code for Codes Sake&lt;/h2&gt;
&lt;img class='left no-border' src='http://farm3.static.flickr.com/2803/4338747142_58cd9768e3_o.png' /&gt;
&lt;p&gt;Car analogies work really well to conversationally describe software applications, but I&amp;#8217;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='http://www.wikihow.com/Use-a-Hammer-Safely'&gt;hold a hammer properly&lt;/a&gt;. If you told him to build a house, he&amp;#8217;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&amp;#8217;s a third category - let&amp;#8217;s call him &amp;#8220;qualified.&amp;#8221; He&amp;#8217;s just as comfortable as the expert behind the table saw. But he doesn&amp;#8217;t quite get it. He lacks the mastery of the expert and as a result mis-measures, recuts, rebuilds, and so on until he&amp;#8217;s got his shoddy house standing.&lt;/p&gt;

&lt;p&gt;Software is exactly the same - only worse. It&amp;#8217;s &lt;em&gt;way&lt;/em&gt; easier to type &lt;code&gt;rails superfluous-app&lt;/code&gt; than to fire up the saw and cut a piece of wood. And there&amp;#8217;s a lot of get-not&amp;#8217;s in the workshop, just keystrokes away from leaving 100&amp;#8217;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='drawing_a_line_between_done_and_done_right'&gt;Drawing a Line Between Done and Done Right&lt;/h2&gt;
&lt;object height='222' width='384' style='margin: 0pt 0pt 15px 15px; float: right;'&gt;&lt;param name='movie' value='http://www.hulu.com/embed/0trVsm_OdEX0qitmGaa_xg/i114' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;embed src='http://www.hulu.com/embed/0trVsm_OdEX0qitmGaa_xg/i114' allowFullScreen='true' type='application/x-shockwave-flash' height='222' width='384' /&gt;&lt;/object&gt;
&lt;p&gt;Now you&amp;#8217;ve got your house built. Maybe it looks a bit like Ned&amp;#8217;s after the Simpson&amp;#8217;s neighborhood chips in and rebuilds it, but hey, at least it&amp;#8217;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 &amp;#8220;Computers&amp;#8221; aisle. There&amp;#8217;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&amp;#8217;ve got a site up, but instead improving the experience, they migrate databases. They boast that their application has 100% test coverage, but it&amp;#8217;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='http://gettingreal.37signals.com/ch03_Embrace_Constraints.php'&gt;embracing the constraints&lt;/a&gt; and imperfections along the way.&lt;/p&gt;

&lt;h2 id='changing_the_future'&gt;Changing the Future&lt;/h2&gt;
&lt;img class='left' src='http://farm5.static.flickr.com/4040/4334975797_b83fb49cab_o.png' /&gt;
&lt;p&gt;Think about the last time you saw a master at work. Someone that&amp;#8217;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&amp;#8217;s how the get-its work. They&amp;#8217;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&amp;#8217;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;img class='right' src='http://farm3.static.flickr.com/2762/4334835361_205d573287_m.jpg' /&gt;
&lt;p&gt;Get-its don&amp;#8217;t just challenge the products their working on. They also challenge their tools. If it sucks, they build a new one. If they don&amp;#8217;t like the way so-and-so library handles bla-bla-bla, they make it better and then share it with their peers. They&amp;#8217;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&amp;#8217;s about to change. The best of them are the catalyst for that change.&lt;/p&gt;

&lt;h2 id='update_the_results_are_in'&gt;Update: The Results Are In&lt;/h2&gt;

&lt;p&gt;When this post when up, I asked people whether they &amp;#8220;got it&amp;#8221; or didn&amp;#8217;t. Here are the results:&lt;/p&gt;
&lt;table class='results'&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
      &lt;th class='percent'&gt;Percentage&lt;/th&gt;
      &lt;th class='count'&gt;Count&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tfoot&gt;
    &lt;tr&gt;
      &lt;td class='empty'&gt;&amp;nbsp;&lt;/td&gt;
      &lt;th&gt;Total&lt;/th&gt;
      &lt;td class='count'&gt;122&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tfoot&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;I don&amp;#039;t get it.&lt;/th&gt;
      &lt;td class='percent'&gt;
        &lt;div style='background: #499CC9; width:54.10%' /&gt;
        &lt;var&gt;54.10%&lt;/var&gt;
      &lt;/td&gt;
      &lt;td class='count'&gt;66&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;I get it!&lt;/th&gt;
      &lt;td class='percent'&gt;
        &lt;div style='background: #E53F11; width:45.90%' /&gt;
        &lt;var&gt;45.90%&lt;/var&gt;
      &lt;/td&gt;
      &lt;td class='count'&gt;56&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&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-08:00</updated>
   <id>http://avandamiri.com/2010/01/13/integrating-twitter-authentication-with-rails</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m working on a project called &lt;a href='http://piggyback.it/' title='Piggy Back'&gt;Piggy Back&lt;/a&gt;, a simple service where friends can keep track of debts between one another. To encourage user registration, I&amp;#8217;m lowering the barriers, allowing users to sign up their &lt;a href='http://twitter.com' title='Twitter'&gt;Twitter&lt;/a&gt; and &lt;a href='http://facebook.com' title='Facebook'&gt;Facebook&lt;/a&gt; accounts. I&amp;#8217;d like share with you how I got this functionality into this Rails app. A shout out to &lt;a href='http://twitter.com/chrisjpowers'&gt;Chris Powers&lt;/a&gt; and &lt;a href='http://twitter.com/nevernormal1'&gt;Jeff Talbot&lt;/a&gt; for their feedback along the way.&lt;/p&gt;

&lt;h2 id='eliminating_plugin_magic'&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='http://github.com/binarylogic/authlogic/' title='GitHub: binarylogic/authlogic'&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 &amp;#8220;magic columns&amp;#8221; (&lt;code&gt;last_logged_in_at&lt;/code&gt;, &lt;code&gt;failed_login_count&lt;/code&gt;, etc.) because they were free, but I didn&amp;#8217;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='http://github.com/binarylogic/authlogic/' title='GitHub: binarylogic/authlogic'&gt;Authlogic&lt;/a&gt; required. There were likely workarounds available, but that meant hacking &lt;a href='http://github.com/binarylogic/authlogic/' title='GitHub: binarylogic/authlogic'&gt;Authlogic&lt;/a&gt;, not working on my app.&lt;/p&gt;

&lt;h2 id='hand_rolling_authentication'&gt;Hand Rolling Authentication&lt;/h2&gt;

&lt;p&gt;Authentication isn&amp;#8217;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='http://github.com/jamis/bucketwise/'&gt;Jamis Buck&amp;#8217;s Bucketwise project&lt;/a&gt; and prepped my user to be authenticated.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://gist.github.com/276329' title='GitHub Gist: Hand Rolled Authentication'&gt;See the code!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authlogic encourages you to use a &lt;code&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&gt;SiteController&lt;/code&gt; that simply responded to &lt;code&gt;GET&lt;/code&gt; requests. Originally, I had used &lt;code&gt;require_authentication&lt;/code&gt; &lt;code&gt;before_filter&lt;/code&gt;s, so I ported those over to the new system as well. Check it all out in the &lt;a href='http://gist.github.com/276329' title='GitHub Gist: Hand Rolled Authentication'&gt;gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='now_lets_get_twitter_up_in_there'&gt;Now, Let&amp;#8217;s Get Twitter Up in There!&lt;/h2&gt;

&lt;p&gt;Twitter supports &lt;a href='http://oauth.net'&gt;OAuth&lt;/a&gt; authentication. It&amp;#8217;s a little trickier to implement than basic HTTP authentication, but isn&amp;#8217;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&amp;#8217;s a lot that OAuth does and I wasn&amp;#8217;t prepared to start from scratch, so I installed the &lt;a href='http://oauth.rubyforge.org/'&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&gt;twitter_id&lt;/code&gt;, &lt;code&gt;twitter_handle&lt;/code&gt;, &lt;code&gt;twitter_token&lt;/code&gt;, and &lt;code&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&gt;TwitterController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a bit too large to embed here, but you can still &lt;a href='http://gist.github.com/276329#file_twitter_controller.rb' title='GitHub Gist: TwitterController'&gt;take a look at the &lt;code&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&amp;#8217;m referencing comments in the &lt;a href='http://gist.github.com/276329#file_twitter_controller.rb' title='GitHub Gist: TwitterController'&gt;TwitterController&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A new users comes to Piggy Back and creates an account by logging in to Twitter. (C)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;An existing user comes back to Piggy Back and logs in via Twitter, but:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Piggy Back doesn&amp;#8217;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;/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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;with_options&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt; &lt;span class='ss'&gt;:user_action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;create&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;})&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;twitter_map&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;twitter_map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;twitter_oauth&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/twitter/oath/:user_action&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:twitter&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:oauth&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='n'&gt;twitter_map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;twitter_callback&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/twitter/callback/:user_action&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:twitter&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:callback&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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&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&amp;#8217;s a &amp;#8220;Sign in with Twitter&amp;#8221; 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&amp;#8217;m adding a big button to this login page, &amp;#8220;Don&amp;#8217;t Have an Account, Create One Instantly.&amp;#8221;&lt;/p&gt;

&lt;h2 id='conclusion'&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&amp;#8217;m sure the answer is yes. However, it&amp;#8217;s not a lot of code and there&amp;#8217;s a lot of customizations your app will need within the areas I commented out. I&amp;#8217;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='references'&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://github.com/jnunemaker/twitter/'&gt;jnunemaker/twitter&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://github.com/tardate/rails-twitter-oauth-sample/'&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-08: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='http://avandamiri.com/2009/06/08/the-pursuit-of-happiness-through-outstanding-customer-service.html'&gt;post about great customer service&lt;/a&gt;, where it&amp;#8217;s coming from and where to find more of it. Today, I&amp;#8217;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&amp;#8217;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&amp;#8217;s position. They&amp;#8217;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&amp;#8217;ve probably experienced, it&amp;#8217;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&amp;#8217;t planning on using them again. I&amp;#8217;m single now, so I have no immediate floral emergencies. But today, I&amp;#8217;m vowing to never again use their service, no matter how long I&amp;#8217;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='http://farm5.static.flickr.com/4061/4266183499_82010da51a.jpg' alt='Scam Letter' /&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&amp;#8217;re actually purchasing a membership. To make matters worse, it&amp;#8217;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='http://farm3.static.flickr.com/2714/4266944920_e73bb25483_o.png' alt='Fine Print' /&gt;&lt;/p&gt;

&lt;p&gt;I was appalled. I don&amp;#8217;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&amp;#8217;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&amp;#8217;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&amp;#8217;s crucial to constantly ask: does what I&amp;#8217;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&amp;#8217;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>Rebuilding a Brand. Avand.</title>
   <link href="http://avandamiri.com/2009/11/22/rebuilding-a-brand-avand.html" />
   <updated>2009-11-22T00:00:00-08:00</updated>
   <id>http://avandamiri.com/2009/11/22/rebuilding-a-brand-avand</id>
   <content type="html">&lt;p&gt;Once again, it&amp;#8217;s been months since my last post. I&amp;#8217;ve been taking some good and some bad classes at DePaul for the last 10 weeks and as a result haven&amp;#8217;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='motivations'&gt;Motivations&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve always wanted a web presence for myself. Unfortunately, I suffered from the same shortsightedness that many of the clients I&amp;#8217;ve worked for have had in the past: simply wanting a website isn&amp;#8217;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, &amp;#8220;Simple Things.&amp;#8221; 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&amp;#8217;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='goals'&gt;Goals&lt;/h2&gt;

&lt;p&gt;Describing one&amp;#8217;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&amp;#8217;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 &amp;#8220;Avand Amiri,&amp;#8221; although I have gone all my life by &amp;#8220;Andy.&amp;#8221; I decided that I wanted to stay true to my heritage and make the switch. It&amp;#8217;s been hard to get my friends to call me &amp;#8220;Avand,&amp;#8221; change my old accounts, and track down all the old references, but I think I&amp;#8217;m mostly there. Because &amp;#8220;Avand&amp;#8221; is so unique, I decided to build my entire &amp;#8220;brand name&amp;#8221; off of it. It became the cornerstone of this site.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;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 &amp;#8220;work and play&amp;#8221; is a little ambiguous for me, but that&amp;#8217;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&amp;#8217;t want an &amp;#8220;About Me&amp;#8221; page. In fact, I didn&amp;#8217;t want any text at all. I had to find something important about myself that could become part of the &amp;#8220;Avand&amp;#8221; 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 &amp;#8220;what do I like?&amp;#8221; Red, black and white are my favorite colors because they&amp;#8217;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='getting_there'&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&amp;#8217;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='http://vandev.com/'&gt;Chris Vanpelt&lt;/a&gt; had once mentioned &lt;a href='http://wiki.github.com/mojombo/jekyll'&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='http://wufoo.com'&gt;Wufoo&lt;/a&gt; allowed me to fulfill the &amp;#8220;Talk to Me&amp;#8221; 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&amp;#8217;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&amp;#8217;s really gratifying. At the same time, I&amp;#8217;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='http://avandamiri.com'&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-07:00</updated>
   <id>http://avandamiri.com/2009/07/16/piggy-back-launch-trials-and-tribulations</id>
   <content type="html">&lt;p&gt;I haven&amp;#8217;t posted in a while, and here&amp;#8217;s why: &lt;a href='http://www.piggybackme.com'&gt;Piggy Back&lt;/a&gt;;. If you follow me on &lt;a href='http://www.twitter.com/avand'&gt;Twitter&lt;/a&gt;, or are friends with me on &lt;a href='http://www.facebook.com/avand'&gt;Facebook&lt;/a&gt;, you&amp;#8217;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='http://www.echo.com/'&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&amp;#8217;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 &amp;#8220;Balancr,&amp;#8221; 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 &amp;#8220;the shortest distance between two wallets.&amp;#8221;&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&amp;#8217;s my story:&lt;/p&gt;

&lt;h2 id='focusing_on_what_matters'&gt;Focusing on What Matters&lt;/h2&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 &amp;#8220;no&amp;#8221; to &amp;#8220;pro&amp;#8221; 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='http://www.thoughtbot.com/projects/shoulda/'&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&amp;#8230; on paper:&lt;/p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4125753470/' title='page1 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2584/4125753470_557ae0236e_m.jpg' height='240' alt='page1' width='209' /&gt;&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4124984705/' title='page2 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2766/4124984705_cacdf056a2_m.jpg' height='229' alt='page2' width='240' /&gt;&lt;/a&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&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&amp;#8217;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&amp;#8217;m still keeping my fingers crossed.&lt;/p&gt;

&lt;h2 id='racing_to_production'&gt;Racing to Production&lt;/h2&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='http://www.slicehost.com'&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='http://www.hoptoadapp.com'&gt;error handling with Hoptoad&lt;/a&gt;, &lt;a href='http://www.google.com/analytics'&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;h2 id='feedback_is_deafening'&gt;Feedback is Deafening&lt;/h2&gt;

&lt;p&gt;Just like holding a microphone up to a speaker, the feedback started pouring in: where&amp;#8217;s the remember your password button, can I create private debts, why is this over here, etc., etc., etc. I guess it&amp;#8217;s really easy to criticize something.&lt;/p&gt;

&lt;p&gt;At times I got annoyed, sitting back and taking the attitude of, &amp;#8220;well, if you want it to work that way, why don&amp;#8217;t you build it!&amp;#8221; 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&amp;#8217;t swear them off just yet!&lt;/p&gt;

&lt;h2 id='build_it_to_use_it'&gt;Build it to Use It&lt;/h2&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&amp;#8217;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&amp;#8217;s really refreshing to really feel the need of the user and be able to act on it.&lt;/p&gt;

&lt;h2 id='build_it_to_use_it_again'&gt;Build it to Use It, Again&lt;/h2&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 &amp;#8220;Name&amp;#8221; I type &amp;#8220;Avand Amiri,&amp;#8221; while others type &amp;#8220;ben&amp;#8221; or &amp;#8220;G.&amp;#8221; When I click a link and it takes a second to load, I look to the browser&amp;#8217;s status bar to see if browser is loading something. Other&amp;#8217;s just give up.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve spent a few hours talking to people, and looking over people&amp;#8217;s shoulders to see how they move their mouse, and ask them &amp;#8220;why&amp;#8217;d you do that?&amp;#8221; Pay attention to how people phrase questions, and how many they&amp;#8217;re asking.&lt;/p&gt;

&lt;h2 id='testing'&gt;Testing&lt;/h2&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&amp;#8217;t been a priority. There&amp;#8217;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&amp;#8217;s been eye opening to test what actually matters. If I don&amp;#8217;t test that user&amp;#8217;s have many debts, I guess I don&amp;#8217;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, &amp;#8220;meh, this &lt;code&gt;has_many&lt;/code&gt; declaration can&amp;#8217;t be that important.&amp;#8221; It doesn&amp;#8217;t happen. At the end of the day, my tests are the product of necessity. Some new functionality I&amp;#8217;m releasing, requires my user registration to be much more robust, and I&amp;#8217;m a little scared of the edge cases, so I&amp;#8217;ll test them.&lt;/p&gt;

&lt;p&gt;So going back then, I guess I&amp;#8217;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;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;All things considered I&amp;#8217;m having a lot of fun building Piggy Back and I think that&amp;#8217;s because it directly impacts me. It&amp;#8217;s fun to be user number 1, and it&amp;#8217;s fun to see user number 10. Getting feedback has been huge, because it&amp;#8217;s made me think about things I didn&amp;#8217;t consider important or necessary. More than anything, it&amp;#8217;s dynamic. Don&amp;#8217;t get too comfortable with Piggy Back, just yet, there&amp;#8217;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-07:00</updated>
   <id>http://avandamiri.com/2009/06/08/the-pursuit-of-happiness-through-outstanding-customer-service</id>
   <content type="html">&lt;p&gt;Is anyone else seeing what&amp;#8217;s happening here? I&amp;#8217;m not sure where it&amp;#8217;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&amp;#8217;s Inc. magazine&amp;#8217;s article on &lt;a href='http://www.inc.com/ss/how-to-make-customers-love-you'&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&amp;#8217;t had to call in yet, and don&amp;#8217;t think I&amp;#8217;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 &amp;#34;buy?&amp;#34; That&amp;#8217;s impressive for a 800,000 square foot warehouse. Hsieh isn&amp;#8217;t trying to build a store where you buy shoes, though, as the article describes. He&amp;#8217;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='http://www.bonobos.com/'&gt;Bonobos&lt;/a&gt;. Who would buy pants online? Well when you make it so easy, I think the question becomes who wouldn&amp;#8217;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 &amp;#8220;if you&amp;#8217;re an 11.5 in &lt;a href='http://www.zappos.com/product/7400255'&gt;Kangaroos&lt;/a&gt;, you&amp;#8217;ll be an 11 &lt;a href='http://www.zappos.com/product/7384367/color/173925'&gt;Puma&lt;/a&gt;&amp;#8221; feature.&lt;/p&gt;

&lt;p&gt;So I started to notice a trend, although &lt;a href='http://twitter.com/singfoom'&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='http://www.wlcamp.org'&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&amp;#8217;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&amp;#8211;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&amp;#8217;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='http://www.mapquest.com/'&gt;MapQuest&lt;/a&gt; ruled the world (proof that you can take down the market leader with a &lt;a href='http://maps.google.com'&gt;better product&lt;/a&gt;&amp;#8230; &lt;a href='http://gmail.com'&gt;twice&lt;/a&gt;. &lt;a href='http://www.gastevich.com/'&gt;Goin&amp;#8217; 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&amp;#8217;s the deal? If an online shoe company can figure it out, what&amp;#8217;s Comcast&amp;#8217;s problem? Or AT&amp;amp;T&amp;#8217;s for that matter. It&amp;#8217;s a good thing I asked, because I&amp;#8217;ll tell you: &lt;em&gt;constraints&lt;/em&gt;. When you&amp;#8217;ve got your &lt;a href='http://www.crunchgear.com/2009/06/08/want-an-iphone-3g-s-already-have-an-iphone-3g-be-prepared-to-pay-700-to-upgrade/' title='Why AT&amp;amp;T Stinks'&gt;customers by the balls&lt;/a&gt; you don&amp;#8217;t have to be nice. But when you&amp;#8217;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='http://www.popsci.com/scitech/article/2008-12/machine-might-save-world'&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&amp;#8217;re competing with the International Thermonuclear Experimental Reactor, a consortium of seven governments sinking billions of dollars into decades worth of research. And they&amp;#8217;re doing it with 2 million bucks in an office park.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;It&amp;#8217;s pretty basic, boring stuff,&amp;#8221; he says. &amp;#8220;Look in your car. There&amp;#8217;s no superconducting magnet in there. There&amp;#8217;s pipes and pistons and tubes. That&amp;#8217;s what I want. I want to make a fusion machine at a sort of car level. And that&amp;#8217;s why we can make it for $50 million and they&amp;#8221; &amp;#8211; government and university coalitions &amp;#8211; &amp;#8220;make it for $20 billion. That&amp;#8217;s the difference.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It&amp;#8217;s survival of the fittest. So look for innovation, whether it be the cure for cancer, a solution to the world&amp;#8217;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&amp;#8217;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-07: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&amp;#8217;t really feel like spending $60.00 getting to West Village. Plus, there&amp;#8217;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, &amp;#8220;you know what, it&amp;#8217;s late - maybe a cab is the right move.&amp;#8221; Nope - apparently New York has these &amp;#8220;black&amp;#8221; cabs competing against the trusty yellow ones. I think they&amp;#8217;re just there to freak out tourists.&lt;/p&gt;

&lt;p&gt;Back to public transportation - and this time I&amp;#8217;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&amp;#8217;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='http://www.mta.info/nyct/maps/sub1a.gif' height='299' width='462' /&gt;&lt;/p&gt;
&lt;p&gt;When you decide below the streets, there&amp;#8217;s not 1, or even two layers of trains, there&amp;#8217;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&amp;#8230; again. And here&amp;#8217;s why:&lt;/p&gt;

&lt;h2 id='why_i_got_lost'&gt;Why I got Lost&lt;/h2&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4123339056/' title='IMG_0220 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2788/4123339056_db81bed53a_t.jpg' height='75' alt='IMG_0220' width='100' /&gt;&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4123338572/' title='IMG_0218 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2524/4123338572_047e16c4d9_t.jpg' height='75' alt='IMG_0218' width='100' /&gt;&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4122566789/' title='IMG_0217 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2611/4122566789_ac9013ddd6_t.jpg' height='75' alt='IMG_0217' width='100' /&gt;&lt;/a&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Why is the word &amp;#8220;Exit&amp;#8221; on a red background? Does following the arrow mean you&amp;#8217;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: &amp;#8220;Local to Bay Ridge-95 St. Late nights N to 36 St, Bklyn for R&amp;#8221; ?&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&amp;#8217;re underground, which way is North? South? When you&amp;#8217;re spun around, it can be very confusing. Don&amp;#8217;t look to the signs; unless you know the city they won&amp;#8217;t help you. I was amazed that even the transit maps (not pictured) while telling you &amp;#8220;you&amp;#8217;re here&amp;#8221; failed to point out which way you were going. Unless you traced the route to the last stop - and even that wasn&amp;#8217;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;h2 id='what_i_found_comforting'&gt;What I found comforting&lt;/h2&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4123338944/' title='IMG_0219 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2544/4123338944_a3182ce32d_t.jpg' height='75' alt='IMG_0219' width='100' /&gt;&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;&lt;a href='http://www.flickr.com/photos/amiriav/4122568283/' title='IMG_0228 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2637/4122568283_45d9eeabbb_t.jpg' height='75' alt='IMG_0228' width='100' /&gt;&lt;/a&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&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&amp;#8217;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='http://www.flickr.com/photos/amiriav/4122568451/' title='IMG_0229 by Avand Amiri, on Flickr'&gt;&lt;img src='http://farm3.static.flickr.com/2776/4122568451_dd30ec56e0_m.jpg' height='180' alt='IMG_0229' width='240' /&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 (&amp;#8220;Board here&amp;#8221;) 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='http://www.transitchicago.com/'&gt;Chicago&lt;/a&gt; vs &lt;a href='http://www.mta.info/'&gt;New York&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But one can&amp;#8217;t be too harsh, just take a close up look at their &lt;a href='http://www.mta.info/nyct/maps/submap.htm'&gt;subway map&lt;/a&gt; and you&amp;#8217;ll see it&amp;#8217;s really incredible.&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-08: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&amp;#8217;t about the code, it&amp;#8217;s all about the process. And when it comes to processes, there&amp;#8217;s a lot to choose from; developers have a habit of over thinking this stuff. So as one, I figured I&amp;#8217;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&amp;#8217;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&amp;#8217;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&amp;#8217;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='http://railscasts.com/episodes/126-populating-a-database'&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&amp;#8217;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&amp;#8217;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='http://populator.rubyforge.org/'&gt;populator&lt;/a&gt; and &lt;a href='http://faker.rubyforge.org/'&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&amp;#8217;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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# Given a set of class names, will require objects of those types to have been populated&lt;/span&gt;
&lt;span class='c1'&gt;# Usage: depends_on(User, Post, Comment)&lt;/span&gt;
&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;depends_on&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;raise&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Depends on &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;pluralize&lt;/span&gt; &lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.to_sentence.downcase} to populate data.&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;any?&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;zero?&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='nb'&gt;eval&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;@&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;underscore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;pluralize&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; = &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.all&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This not only helped declaratively define my dependencies, but also sets up whatever instance variables (i.e. &lt;code&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&amp;#8217;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='http://github.com/thoughtbot/factory_girl/tree/master'&gt;factory_girl&lt;/a&gt;. Not only can they run much faster as many tests don&amp;#8217;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-08: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&amp;#8217;ve really nailed, what in my mind, makes a great product.&lt;/p&gt;

&lt;p&gt;Immediately In-n-Out Burger&amp;#8217;s menu jumped out at me. In my day to day operations I&amp;#8217;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&amp;#8217;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='http://farm3.static.flickr.com/2598/4122576419_67c1c80661_o.jpg' alt='In-n-Out Burger Menu' /&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&amp;#8217;s right, no salads here. Even the option I found most delicious - &amp;#8220;animal style&amp;#8221;, is unlisted on the menu. Talk about restraint and compromise. So, we sit down to eat and I&amp;#8217;m anxious. I&amp;#8217;ve heard good things, and am happy thus far, but just because they have a simple menu, doesn&amp;#8217;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&amp;#8217;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&amp;#8217;s like someone came through with a &lt;a href='http://en.wikipedia.org/wiki/CH-47_Chinook'&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&amp;#8230; 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-08: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 &amp;#8220;tips n&amp;#8217; tricks&amp;#8221; tutorial, I&amp;#8217;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 &amp;#8216;app&amp;#8217; 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 &amp;#8220;default.css&amp;#8221; or &amp;#8220;application.css&amp;#8221; and placed in the stylesheets folder. I&amp;#8217;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&amp;#8217;ve started following, I think I&amp;#8217;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;h2 id='1_controllers_and_actions_as_css_selectors'&gt;1. Controllers and actions as CSS selectors&lt;/h2&gt;

&lt;p&gt;Depending on the application, you&amp;#8217;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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;head&amp;gt;...&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &amp;lt;div id=&amp;quot;wrapper&amp;quot; class=&amp;quot;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;controller_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;action_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='k'&gt;yield&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;    &amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='css'&gt;&lt;span class='nt'&gt;div&lt;/span&gt;&lt;span class='nf'&gt;#wrapper&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='c'&gt;/* insert styles common to all controllers here */&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='nt'&gt;div&lt;/span&gt;&lt;span class='nf'&gt;#wrapper&lt;/span&gt; &lt;span class='nt'&gt;div&lt;/span&gt;&lt;span class='nc'&gt;.users&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='c'&gt;/* insert common styles for all user actions here */&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='nt'&gt;div&lt;/span&gt;&lt;span class='nf'&gt;#wrapper&lt;/span&gt; &lt;span class='nt'&gt;div&lt;/span&gt;&lt;span class='nc'&gt;.users.index&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='c'&gt;/* insert users#index specific styles here */&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The key is to religiously obey these prefixes. In &lt;a href='/2008/09/18/css-tricks-1-of-2-first-get-down-with-the-oop.html'&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&amp;#8217;re not, you&amp;#8217;ll spend hours trying to figure out why something is rendering a certain way only to find that it&amp;#8217;s inheriting something entirely irrelevant. So once you have that sorted you can then make&amp;#8230;&lt;/p&gt;

&lt;h2 id='2many_shorter_css_files'&gt;2. Many shorter CSS files&lt;/h2&gt;

&lt;p&gt;So if you have a controller like UsersController, you&amp;#8217;ll have a folder, views/users. Within that you&amp;#8217;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&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&amp;#8230; 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;h2 id='3_rails_stylesheet_caching'&gt;3. Rails stylesheet caching&lt;/h2&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;application&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;users/index&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;users/new&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;users/common&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;cache&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;cached/users&amp;#39;&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    ...&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In some cases I&amp;#8217;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&amp;#8217;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-07: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;h2 id='introduction'&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I recently stumbled upon an &lt;a href='http://www.evoart.info/'&gt;interesting web design blog&lt;/a&gt; that featured an article about some &lt;a href='http://www.evoart.info/10-essential-considerations-when-designing-a-website/'&gt;CSS &amp;#8220;essentials&amp;#8221;&lt;/a&gt; and commonly used &lt;a href='http://www.evoart.info/7-essential-css-code-snippets/'&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&amp;#8217;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&amp;#8217;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&amp;#8217;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&amp;#8217;s what I&amp;#8217;ve learned&amp;#8230;&lt;/p&gt;

&lt;h2 id='embrace_a_convention_through_and_through'&gt;Embrace a Convention Through and Through&lt;/h2&gt;

&lt;p&gt;Seriously, if you&amp;#8217;re not using some kind of structure when it comes to building an application, you should probably &lt;a href='http://failblog.org/'&gt;go read some other blog&lt;/a&gt;. I&amp;#8217;m somewhat infatuated with the MVC pattern these days, but for the sake of what we&amp;#8217;re doing here I don&amp;#8217;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='http://en.wikipedia.org/wiki/Create,_read,_update_and_delete'&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&amp;#8217;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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;div id=&amp;quot;users&amp;quot;&amp;gt;&amp;lt;!-- Derive this from the controller --&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='k'&gt;in&lt;/span&gt; &lt;span class='vi'&gt;@users&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;div class=&amp;quot;user&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Users#show&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;div id=&amp;quot;user&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;h3&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Users#new&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;div id=&amp;quot;user&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;form&amp;gt;&amp;lt;!-- Key off this in the CSS (i.e. #user form input) --&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='cp'&gt;-%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;quot; /&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;  &amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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&amp;#8217;s look to the structure of the application code first and let it drive the front end.&lt;/p&gt;

&lt;h2 id='dont_over_refactor_css'&gt;Don&amp;#8217;t Over Refactor CSS&lt;/h2&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, &amp;#8220;never use inline styles - everything needs to have corresponding class or ID.&amp;#8221; That attitude is part of what&amp;#8217;s contributed to my career switch to Ruby on Rails. Don&amp;#8217;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&amp;#8217;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&amp;#8217;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;h2 id='tame_the_css_file'&gt;Tame the CSS File&lt;/h2&gt;

&lt;p&gt;Whether it be in a Controller, Stored Procedure, or CSS, it&amp;#8217;s not OK for files to just grow to thousands of lines without taking a step back and saying, &amp;#8220;woah&amp;#8221;, what just happened here? To avoid this little conundrum I like to use the &lt;a href='http://www.cssnewbie.com/css-import-rule/'&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&amp;#8217;re going to say. There&amp;#8217;s a significant performance hit for this, and I hear you. It&amp;#8217;s not OK to go to production using @import, because each file will require &lt;a href='http://developer.yahoo.com/performance/rules.html'&gt;another HTTP request, which isn&amp;#8217;t cool&lt;/a&gt;. But, if you&amp;#8217;re doing anything serious, you&amp;#8217;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;h3 id='be_as_specific_aspossible'&gt;Be #as .Specific .as:Possible&lt;/h3&gt;

&lt;p&gt;It&amp;#8217;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 &amp;#8220;refactored.&amp;#8221;&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&amp;#8217;s exactly the type of laziness I&amp;#8217;m talking about. Use #users .user instead. It will make life easier in the long run, and isn&amp;#8217;t that what development is all about?&lt;/p&gt;

&lt;h2 id='conclusion_and_whats_to_come'&gt;Conclusion and What&amp;#8217;s to Come&amp;#8230;&lt;/h2&gt;

&lt;p&gt;The approaches here are pretty high level, but in the next part of this post (Part 2, for those you playing at home), I&amp;#8217;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-07: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&amp;#8217;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&amp;#8217;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='http://www.inc.com/magazine/20080801/making-it-work.html'&gt;ROWE, a results-only work environment&lt;/a&gt;. Standing up against the &amp;#8220;tried and true&amp;#8221; 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&amp;#8217;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&amp;#8217;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&amp;#8217;t really jive with having &amp;#8220;passionate&amp;#8221; employees, does it?&lt;/p&gt;

&lt;p&gt;37Signals, of course, has tooted this horn for quite some time now. &lt;a href='http://www.37signals.com/svn/posts/893-workplace-experiments'&gt;4 day weeks&lt;/a&gt;, they say, has boosted productivity, catapulted morale skyward, and absolutely energized their company. It&amp;#8217;s all about working &amp;#8220;fresh;&amp;#8221; 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='http://www.google.com/support/jobs/bin/static.py?page=about.html&amp;amp;amp;amp;about=top10'&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&amp;#8217;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='http://wlcamp.org/'&gt;William Lawrence Camp&lt;/a&gt; as a counselor, I remember being a part of the tradition of &lt;a href='http://wlcamp.org/boys-summer-camp-other-programs.asp'&gt;&amp;#8220;Beach Day.&amp;#8221;&lt;/a&gt;. It&amp;#8217;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&amp;#8217;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, &amp;#8220;Andy, you&amp;#8217;re doing a great job, and thanks a lot for your help.&amp;#8221; 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&amp;#8217;s the amazing power of positive reinforcement. I think the tendency is to think that these philosophies don&amp;#8217;t really apply in the &amp;#8220;real world.&amp;#8221; After all, we&amp;#8217;re all adults here, and we have to put on our work clothes and just &amp;#8220;get the job done.&amp;#8221; That&amp;#8217;s what it&amp;#8217;s called, right? &amp;#8220;Work.&amp;#8221; So many &amp;#8220;work&amp;#8221; cultures are just that: a place where it&amp;#8217;s not about being a part of a team but just producing, however that needs to happen.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;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&amp;#8217;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='http://4.bp.blogspot.com/_EgF6v5WqT_g/SMRN-Zm4MzI/AAAAAAAAAEI/F3j9Y_m3_AU/s200/Iwo+Jima.jpg' alt='picture' /&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&amp;#8217;s the root of patriotism, and could be, arguably, the root of U.S.A&amp;#8217;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&amp;#8217;s a common theme of bringing employees closer together, while renouncing micromanagement and promoting quality results. Within my field of software development, &amp;#8220;agile&amp;#8221; processes come to mind, and I&amp;#8217;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&amp;#8217;t it be measured through emotion? Think again about the feeling that photo conjures. Do you feel like that at work and don&amp;#8217;t you think you&amp;#8217;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-07:00</updated>
   <id>http://avandamiri.com/2008/09/02/bravo-37signals-for-phasing-out-ie-6</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s been a long time coming&amp;#8230;&lt;/p&gt;

&lt;p&gt;&lt;img src='http://farm3.static.flickr.com/2665/4123348110_13e9dbc1c7_o.jpg' alt='Basecamp Phasing out IE 6 Screenshot' /&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='http://37signals.blogs.com/products/2008/07/basecamp-phasin.html'&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-07: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&amp;#8217;ve downloaded, that is paid, for exactly 3 games. The best - by a long shot - is &lt;a href='http://www.pangeasoft.net/enigmo/'&gt;Enigmo, from Pangea Software&lt;/a&gt;. For those of you who don&amp;#8217;t know it, it&amp;#8217;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='http://toucharcade.com/wp-content/uploads/2008/03/enigmo.jpg' alt='picture alt' /&gt;&lt;/p&gt;

&lt;p&gt;Not so lame anymore, huh? Yeah, that&amp;#8217;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&amp;#8217;m a bit of a perfectionist. I find myself constantly balancing my idealism against productivity and efficiency. Enigmo helps me practice this. You&amp;#8217;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&amp;#8217;t get every droplet into the pot. It&amp;#8217;s all about getting &amp;#8220;good enough.&amp;#8221;&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s OK! Because there&amp;#8217;s a countdown racing to zero, and the goal isn&amp;#8217;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&amp;#8217;t have to be beautiful or ideal; there&amp;#8217;s no &amp;#8220;grand scheme&amp;#8221; to the game, and there&amp;#8217;s definitely more than one solution&lt;/p&gt;

&lt;p&gt;So if you, like me, suffer from &amp;#8220;entrophobia&amp;#8221;, 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-07: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&amp;#8217;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='http://www.igvita.com/2007/05/23/bayes-classification-in-ruby/'&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 trend, if not a revolution, &lt;a href='http://www.wired.com/science/discoveries/magazine/16-07/pb_theory'&gt;according to WIRED&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem with this whole movement is that unless you&amp;#8217;re a math Ph.D., it&amp;#8217;s completely counterintuitive. You&amp;#8217;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&amp;#8217;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='http://en.wikipedia.org/wiki/Tabula_rasa'&gt;tabula rasa&lt;/a&gt;, we&amp;#8217;re not much further along than a blinking terminal window when we&amp;#8217;re born. It&amp;#8217;s just a little unnerving that a machine can go from infant to prophet in minutes where it takes humans years. But, hey, we&amp;#8217;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&amp;#8217;t even about computers. It&amp;#8217;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&amp;#8217;t &amp;#8220;solve for x&amp;#8221; with empathy. And it&amp;#8217;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 &amp;#8220;pish posh - I&amp;#8217;m a &lt;em&gt;human&lt;/em&gt;, I&amp;#8217;ll &lt;em&gt;always&lt;/em&gt; know better than an equation.&amp;#8221; But, like I said, in my dabbling, I&amp;#8217;ve found that nothing could be further to the truth, and if that means the computer wins, I&amp;#8217;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-07:00</updated>
   <id>http://avandamiri.com/2008/07/10/target-blank-convention</id>
   <content type="html">&lt;p&gt;I&amp;#8217;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='http://www.rubyonrails.org'&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 target=&amp;#8221;_blank&amp;#8221; is one such convention that has yet to be settled it seems.&lt;/p&gt;

&lt;p&gt;I guess it&amp;#8217;s a two sided issue. When do you use target=&amp;#8221;_blank&amp;#8221;, 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&amp;#8217;re changing domain&amp;#8217;s the target should be in a new window. Just because someone want&amp;#8217;s to read a little background behind a hyperlink, shouldn&amp;#8217;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 &amp;#8216;View&amp;#8217; link that targeted a new window so that if you wanted to see the changes you&amp;#8217;ve made, you could, without being taken away from editing. So as far as I&amp;#8217;m concerned this issue is pretty straight forward.&lt;/p&gt;

&lt;p&gt;This one isn&amp;#8217;t: giving the user feedback that the link is actually opening in a new window. I can&amp;#8217;t seem to find anything that is blatantly obvious. I&amp;#8217;ve tried appending &amp;#8216;(opens in a new window)&amp;#8217;, 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&amp;#8217;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&amp;#8217;ve found, I saw for the first time with &lt;a href='http://www.mantisbt.org/'&gt;Mantis&lt;/a&gt;, a bug tracking system, which was to append a &amp;#8217;&amp;#8217; 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 (&amp;#8220;Open in a New Window,&amp;#8221; or &amp;#8220;Open in a New Tab&amp;#8221;, 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&amp;#8217;s a browser setting, but we&amp;#8217;d be closer to a consistent solution. Or everyone could just agree to something, which I suppose I&amp;#8217;d be OK with&amp;#8230;&lt;/p&gt;

&lt;p&gt;&amp;#8230;as long as I&amp;#8217;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-07: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 Northpoint Horizons (&lt;a href='http://www.northpointhorizons.com'&gt;http://www.northpointhorizons.com&lt;/a&gt;), and it was seriously one of the simplest deployments I&amp;#8217;ve ever experienced.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ve been working on the site for months on the future (now current) production server. We&amp;#8217;ve used it for the client to review the site, to perform testing, everything you&amp;#8217;d do with you traditional development environment. All the meanwhile, the DNS for northpointhorizons.com has been pointing at some sandbox with an &amp;#8220;under construction&amp;#8221; banner. So after rigorously reviewing the &amp;#8220;staged&amp;#8221; 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&amp;#8217;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-07: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='http://chicagoruby.org/'&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;p&gt;&lt;strong&gt;Here’s the dilemma:&lt;/strong&gt;&lt;/p&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;p&gt;&lt;strong&gt;Here’s the solution:&lt;/strong&gt;&lt;/p&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='http://www.davidjrice.co.uk/articles/2006/11/29/inline-ajax-form-validation-plugin-for-ruby-on-rails'&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='http://www.ineightydays.com/archives/validating-an-ajax-form-in-ruby-on-rails'&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='http://www.bigsmoke.us/ajax-validation-on-rails/'&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;error_message_for&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;model&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{})&lt;/span&gt; &lt;span class='n'&gt;tag_id&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;model&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;_&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;_validator&amp;quot;&lt;/span&gt;
  &lt;span class='c1'&gt;# generate javascript for AJAX request and field observation&lt;/span&gt;
  &lt;span class='n'&gt;function&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;new Ajax.Request(&amp;#39;/users/validate?field=&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;amp;value=&amp;#39; + value, { method: &amp;#39;get&amp;#39;, onSuccess: function(transport) { element = document.getElementById(&amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;tag_id&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;); var output = transport.responseText; var css_class = &amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:error_css_class&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;; if (output.length == 0) { output = &amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:success&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;; css_class = &amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:success_css_class&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39;; } element.innerHTML = output; element.setAttribute(&amp;#39;class&amp;#39;, css_class) } });&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;js&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;observe_field&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;model&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;_&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:function&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; 
  
  &lt;span class='c1'&gt;# generate html for placing error message&lt;/span&gt;
  &lt;span class='n'&gt;tag&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;content_tag&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:tag&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:hint&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:id&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;tag_id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:class&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:hint_css_class&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  
  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;tag&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;js&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I wanted my solution to be equally elegant as &lt;a href='http://api.rubyonrails.org/classes/ActionView/Helpers/ActiveRecordHelper.html#M001005'&gt;Rails’ non-Ajax solution&lt;/a&gt;, so I created a method &lt;code&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='http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M000966'&gt;&lt;code&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='http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#M001033'&gt;&lt;code&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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;validate&lt;/span&gt;
  &lt;span class='n'&gt;field&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:field&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:value&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;output&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt; &lt;span class='c1'&gt;# trigger the errors hash to be filled&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;errors&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='kp'&gt;nil&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;errors&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;class&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nb'&gt;String&lt;/span&gt;
      &lt;span class='n'&gt;output&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;titleize&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;errors&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='n'&gt;output&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;titleize&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;errors&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;field&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;to_sentence&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  
  &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:text&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;output&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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&gt;validate&lt;/code&gt;. Validate then uses the &lt;code&gt;valid?&lt;/code&gt; method to populate the &lt;code&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='http://api.rubyonrails.org/classes/ActionView/Helpers/ActiveRecordHelper.html#M001005'&gt;&lt;code&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&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, it’s 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;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;text_field&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt;
&lt;span class='n'&gt;error_message_for&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:tag&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:span&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:hint&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Your email must be formatted properly.&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:success&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Looking good!&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You may have noticed some code in there referring to &lt;code&gt;:success&lt;/code&gt; and &lt;code&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='http://github.com/avand/RailsAjaxFormValidationExample/zipball/master'&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-07:00</updated>
   <id>http://avandamiri.com/2008/04/15/peeling-up</id>
   <content type="html">&lt;p&gt;I&amp;#8217;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&amp;#8217;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&amp;#8217;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&amp;#8217;ve been looking for &lt;em&gt;simple&lt;/em&gt; ways to evoke the same illusion of depth. I think I&amp;#8217;ve found two, but I&amp;#8217;ll talk about one here.&lt;/p&gt;

&lt;p&gt;Every since I signed up for &lt;a href='http://www.linkedin.com/'&gt;LinkedIn&lt;/a&gt;, I&amp;#8217;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&amp;#8217;ve never seen before and I was really impressed. I&amp;#8217;m referring to this:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://farm3.static.flickr.com/2562/4169458440_fcd4a28052_o.png' alt='LinkedIn Peeling Up Screenshot' /&gt;&lt;/p&gt;

&lt;p&gt;Do you see what I&amp;#8217;m referring to? It&amp;#8217;s the peeling up effect below the &amp;#8220;Add Connections&amp;#8221; button. It doesn&amp;#8217;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 &amp;#8220;sticky-box&amp;#8221; which I think embodies that &amp;#8220;peel up&amp;#8221; 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-07:00</updated>
   <id>http://avandamiri.com/2008/03/11/skepticism-happens-here</id>
   <content type="html">&lt;p&gt;I attended Microsoft&amp;#8217;s 2008 Product Launch Event, &lt;a href='http://www.microsoft.com/heroeshappenhere/default.mspx'&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&amp;#8217;s take a minute to dissect what that means.&lt;/p&gt;

&lt;p&gt;Stephen D. Levitt in &lt;a href='http://books.google.com/books?id=LkQPOSXMUscC&amp;amp;amp;dq=freakonomics&amp;amp;amp;pg=PP1&amp;amp;amp;ots=4oLkB7ouHV&amp;amp;amp;sig=5tqcxVi69Aqdt7fqvj4YCYSH_lg&amp;amp;amp;hl=en&amp;amp;amp;prev=http://www.google.com/search?hl=en&amp;amp;amp;client=safari&amp;amp;amp;rls=en-us&amp;amp;amp;sa=X&amp;amp;amp;oi=spell&amp;amp;amp;resnum=0&amp;amp;amp;ct=result&amp;amp;amp;cd=1&amp;amp;amp;q=freakonomics&amp;amp;amp;spell=1&amp;amp;amp;oi=print&amp;amp;amp;ct=title&amp;amp;amp;cad=one-book-with-thumbnail'&gt;Freakonomics&lt;/a&gt; talks about the simple law of incentives. Real estate brokers, he argues, don&amp;#8217;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 &amp;#8220;wait it out.&amp;#8221; 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 Visual Studio 2008, SQL Server 2008, and Windows Server 2008. And that&amp;#8217;s really only the beginning. Once you&amp;#8217;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&amp;#8217;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&amp;#8217;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='http://www.cnug.org/Default.aspx?tabid=31'&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 &amp;#8220;uh, duh, Dreamweaver,&amp;#8221; I become skeptical. And what about LINQ? Try on &lt;a href='http://wiki.rubyonrails.org/rails/pages/ActiveRecord'&gt;ActiveRecord&lt;/a&gt; for size - it&amp;#8217;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&amp;#8217;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 the speaker referred to JavaScript as one of the &amp;#8220;bane of a web developer&amp;#8217;s existence;&amp;#8221; and you might say an UpdatePanel is the &lt;span class='Apple-style-span' style='font-style: italic;'&gt;definition&lt;/span&gt; of simple. But to who? A dilettante or a developer?&amp;lt;/div&amp;gt;&lt;/p&gt;

&lt;p&gt;If you want to do anything there&amp;#8217;s a learning curve. If you embrace that curve you&amp;#8217;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. &amp;lt;/div&amp;gt;&lt;/p&gt;

&lt;p&gt;And knowing that, it&amp;#8217;s hard for me to bank on the guy &lt;a href='http://en.wikipedia.org/wiki/Bill_Gates&amp;apos;_house'&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-08:00</updated>
   <id>http://avandamiri.com/2008/03/05/best-tool-for-the-job</id>
   <content type="html">&lt;p&gt;&lt;a href='http://www.codinghorror.com/blog/archives/001065.html'&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&amp;#8217;s &lt;a href='http://www.amazon.com/What-Got-Here-Wont-There/dp/1401301304'&gt;What Got you Here, Won&amp;#8217;t Get You There&lt;/a&gt;. Goldsmith, an organizational psychologist, describes a terribly-negative characteristic common among successful people dubbed as the &amp;#8220;need to win.&amp;#8221; Developers have got a serious case of it.&lt;/p&gt;

&lt;p&gt;Looking for a feeding frenzy better than &lt;a href='http://dsc.discovery.com/convergence/sharkweek/sharkweek.html'&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&amp;#8217;s the best way to refactor some classes to support an MVC architecture. Before you know it, you&amp;#8217;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&amp;#8217;t need a sledgehammer to hang a picture (although it might be fun). You don&amp;#8217;t perform brain surgery with a chainsaw (I&amp;#8217;m looking at you, &lt;a href='http://en.wikipedia.org/wiki/Quentin_Tarantino'&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&amp;#8217;t just write 300 page, $50.00 software text books for fun. So it&amp;#8217;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&amp;#8217;s stop arguing already and build something &lt;a href='http://www.stanthecaddy.com/sounds-sidra-theyre-real-and-spectacular.html'&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-08: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 site, 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 IMAPing 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-07: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 Saturday’s at the Museum of Fine Arts in Boston. However, along the way, I also feel in love with technology. I love computers, gadgets, iPhone’s, 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 doesn’t have a coat racks? Why the latest OS’s have a wonderful animation library of fades and shadows but then abruptly blink to life after the screen turns off. 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>

