<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><description>The Anideo Dev Blog.

Check out our apps — Denso and Huntville!
Email us at dev@anideo.com if you have any questions, or just to say hi!</description><title>com.anideo.dev</title><generator>Tumblr (3.0; @anideo-dev)</generator><link>http://dev.anideo.com/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/anideo-dev" /><feedburner:info uri="anideo-dev" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://tumblr.superfeedr.com/" /><item><title>How we setup Amazon Cloudfront to play nice with Rails 3.0.x on Heroku</title><description>&lt;p&gt;As was mentioned in our &lt;a href="http://dev.anideo.com/post/15021361987/how-moving-to-amazon-cloudfront-increased-our-app-store"&gt;previous post&lt;/a&gt;, we recently started using Amazon Cloudfront for our CDN needs. We wanted the performance benefits that we would gain from the move, we certainly didn’t want it to come at the cost of speed of deployment.&lt;/p&gt;
&lt;p&gt;While the CloudFront custom origin server solution takes care of deployment, there is still the problem of expiring stale assets (especially Javascript and CSS).&lt;/p&gt;
&lt;p&gt;As they say, the two toughest problems in Computer Science are caching, naming things and off-by-one errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset Fingerprinting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The problem of expiring stale content for CDN’s (and browsers) is solved by &lt;a href="http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care"&gt;asset fingerprinting&lt;/a&gt; as part of Rails 3.1’s Asset Pipelining feature.&lt;/p&gt;
&lt;p&gt;Every file in the app/assets directory in Rails 3.1 is “compiled” as part of the &lt;em&gt;&lt;strong&gt;rake assets:precompile&lt;/strong&gt;&lt;/em&gt; Rake task and the asset fingerprint is appended to the each file’s path and copied over to public/. The asset fingerprint is an MD5 digest of the contents of each file - so if a file is changed (for e.g. and image is changed or you change something in your CSS), the MD5 of the asset will change, and hence that particular asset will be ‘expired’.&lt;/p&gt;
&lt;p&gt;The blog post that I referenced from the &lt;a href="http://blog.opengovernment.org/2011/02/10/cloudfront-s3-rails-and-jammit-on-apache/"&gt;Open Government&lt;/a&gt;, uses the SHA of the most recent Git commit as the asset fingerprint. While that is a simple solution, it is quite inefficient. Think about it - any time you make a change to your site - (including model code or a change in a Rake task), your assets will be expired, even though technically the assets haven’t changed.&lt;/p&gt;
&lt;p&gt;We don’t change our CSS/JS/images that often, but we do make changes to our business logic quite often (and deploy multiple times a day), so this solution won’t fly and defeats the purpose of the CDN, since content will always be expired.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset Fingerprinting without Sprockets&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What we came up with is a better solution, which takes a digest of the entire public/ directory under Rails.root. It’s still less efficient than Sprockets’ asset fingerprinting, since in our solution the fingerprint is a hash of the entire directory and not each file. So even if you make a change to a single file, an unrelated file under the public/ will also be expired even if it hasn’t changed.&lt;/p&gt;
&lt;p&gt;The hash of the public/ directory is stored in a file called &lt;strong&gt;assets.fingerprint&lt;/strong&gt; under Rails.root, and is generated like &lt;a href="https://gist.github.com/1554094"&gt;this&lt;/a&gt;. (This is a function of a deploy Rake task which performs pre-flight checks such as these before pushing to Heroku)&lt;/p&gt;
&lt;p&gt;We define a constant called REVISION which is defined in config/initializers/asset_fingerprint.rb thusly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;REVISION = File.read(Rails.root.join(‘assets.fingerprint’)).strip&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;…and in application.rb, the assets path is prepended with the hash as part of the path.&lt;/p&gt;
&lt;p&gt;We also make sure that we use Rack::Rewrite to rewrite paths to the assets to ignore the hash and that the assets host points to the Amazon CDN.&lt;/p&gt;
&lt;p&gt;Our entire application.rb is here for your reference: &lt;a href="https://gist.github.com/1554090"&gt;&lt;a href="https://gist.github.com/1554090"&gt;https://gist.github.com/1554090&lt;/a&gt;&lt;/a&gt;.&lt;/p&gt;</description><link>http://feedproxy.google.com/~r/anideo-dev/~3/1F5zbai12sU/15239283328</link><guid isPermaLink="false">http://dev.anideo.com/post/15239283328</guid><pubDate>Tue, 03 Jan 2012 21:23:30 +0800</pubDate><feedburner:origLink>http://dev.anideo.com/post/15239283328</feedburner:origLink></item><item><title>How moving to Amazon Cloudfront increased our App Store conversion rate by 250%</title><description>&lt;p&gt;So as you may know, we’ve been working on &lt;a href="http://bit.ly/densoapp"&gt;Denso&lt;/a&gt; for a while now, and our primary source of marketing (after the initial wave of PR via &lt;a href="http://facebook.com/saverin"&gt;Eduardo&lt;/a&gt;) has been our website. We post interesting videos once in a while to Hacker News, Reddit, Twitter and Facebook, thus generating inbound traffic.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://news.ycombinator.com/item?id=3346674"&gt;Hacker News story&lt;/a&gt; about &lt;a href="http://getdenso.com/videos/2711806-december-08-2011-ed-gillespie-part-3"&gt;Jon Stewart’s takedown of scammy iOS games&lt;/a&gt; generated a record number of visits to &lt;a href="http://getdenso.com"&gt;getdenso.com&lt;/a&gt;, but unfortunately, that number didn’t correlate well with the App Store downloads for that period. What we noticed was that our site appeared slow (even though New Relic indicated that our website stood up quite well against the onslaught) - and the reason was that our static assets (Javascript and CSS) were taking too long to load and would occasionally even 504.&lt;/p&gt;
&lt;p&gt;This, was obviously, unacceptable.&lt;/p&gt;
&lt;p&gt;We researched a bunch of ways on how we can improve the speed of the site, and naturally Amazon Cloudfront ranked very high among our options. But we needed a way for it not to interfere with our existing deployment strategy (which is git push heroku master). We chanced upon this &lt;a href="http://blog.opengovernment.org/2011/02/10/cloudfront-s3-rails-and-jammit-on-apache/"&gt;excellent resource&lt;/a&gt; which basically gives a detailed tutorial on setting up a custom origin server on CloudFront. With Heroku, its not as straightforward as the Open Government tutorial makes it out to be - there will be another blog post coming up on the tweaks that we implemented.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before and After&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We switched over to our shiny new CDN solution on the 16th of December.&lt;/p&gt;
&lt;p&gt;Before the 16th, our App-Store-downloads-to-web-visits ratio was hovering around &lt;strong&gt;6-8%&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After the CDN deployment, our App-Store-downloads-to-web-visits ratio is now a healthier &lt;strong&gt;21-28%.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Moral Of the Story&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Obviously the moral of the story is not for everyone to move over to a CDN. A lot of other iOS app downloads are probably not driven by their web cousins, so it won’t &lt;em&gt;&lt;strong&gt;always &lt;/strong&gt;&lt;/em&gt;make sense for you to optimize web performance.&lt;/p&gt;
&lt;p&gt;Our biggest takeway is - run experiments, follow up on performance, try to find out root causes for weaknesses, and ruthlessly tackle them.&lt;/p&gt;</description><link>http://feedproxy.google.com/~r/anideo-dev/~3/V2IhMilIhIo/15021361987</link><guid isPermaLink="false">http://dev.anideo.com/post/15021361987</guid><pubDate>Fri, 30 Dec 2011 18:16:00 +0800</pubDate><feedburner:origLink>http://dev.anideo.com/post/15021361987</feedburner:origLink></item></channel></rss>
