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

  <title><![CDATA[The Disco Blog]]></title>
  <link href="http://aglover.github.com/atom.xml" rel="self"/>
  <link href="http://aglover.github.com/"/>
  <updated>2013-05-17T21:56:26-04:00</updated>
  <id>http://aglover.github.com/</id>
  <author>
    <name><![CDATA[Andrew Glover]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[ElasticSearch on EC2 in less than 60 seconds]]></title>
    <link href="http://aglover.github.com/blog/2013/05/17/elasticsearch-on-ec2-in-less-than-60-seconds/"/>
    <updated>2013-05-17T17:24:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/05/17/elasticsearch-on-ec2-in-less-than-60-seconds</id>
    <content type="html"><![CDATA[<p><img class="left" src="http://aglover.github.com/images/mine/es-bonzai.jpg">Curious to see what all the <a href="http://www.elasticsearch.org/">ElasticSearch</a> hubbub is about? Wanna see it in action without a lot of elbow grease? Then look no further, friend &#8211; in less than 60 seconds, I&#8217;ll show you how to install <a href="http://www.ibm.com/developerworks/java/library/j-javadev2-24/">ElasticSearch</a> on an <a href="http://aws.amazon.com/">AWS AMI</a>.</p>

<p>You&#8217;ll first <a href="http://www.drdobbs.com/web-development/getting-started-with-the-cloud-amazon-we/231601598">need an AWS account</a> along with an SSH key pair. If you don&#8217;t already have those two steps done, go ahead and do that. The steps that follow suggest a particular AMI; however, you are free to select the <a href="http://aws.amazon.com/ec2/instance-types/">instance type</a>. <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html">Micro instance types</a> are free to use; consequently, you can get <a href="http://thediscoblog.com/blog/2013/05/14/the-democratization-of-search/">up and running with ElasticSearch</a> in less than a minute <em>for free</em>.</p>

<!-- more -->


<p>Now that you&#8217;ve got an <a href="http://www.ibm.com/developerworks/web/library/j-s3/">AWS</a> account and an SSH key pair, go ahead and create a new security group (or edit an existing one). It&#8217;s important that the <a href="http://www.elasticsearch.org/tutorials/elasticsearch-on-ec2/">following ports</a> are open:</p>

<ul>
<li>22 (required for SSH)</li>
<li>80 (ElasticSearch uses HTTP for standard API calls)</li>
<li>9200 (required for ElasticSearch)</li>
<li>9300 (required for ElasticSearch)</li>
</ul>


<p>Next, fire up a Linux AMI. I, for example, prefer <a href="http://cloud-images.ubuntu.com/locator/ec2/">ami-c30360aa</a> (this is Ubuntu Server version 13.04) and I configure the AMI to use the security group that I just covered.</p>

<p>Now, SSH to your newly instantiated AMI.  Once on the AMI, you&#8217;ll need to install Java. Never fear though, I&#8217;ve got you covered. All you need to do is run a handy script via the <a href="https://github.com/aglover/ubuntu-equip">Ubuntu-Equip project</a>, that I use frequently just for this sorta thing:</p>

<figure class='code'><figcaption><span>installing Java</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>wget --no-check-certificate https://github.com/aglover/ubuntu-equip/raw/master/equip_java.sh <span class="o">&amp;&amp;</span> bash equip_java.sh
</span></code></pre></td></tr></table></div></figure>


<p>You&#8217;ll need to accept the license from Oracle. Once that script completes, go ahead and type  <code>java -version</code> and you should see Oracle&#8217;s JDK (i.e Java version &#8220;1.7.0_21&#8221;).</p>

<p>Next, download and install ElasticSearch via another nifty <a href="https://github.com/aglover/ubuntu-equip">Ubuntu-Equip</a> script:</p>

<figure class='code'><figcaption><span>installing elasticsearch</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>wget --no-check-certificate https://github.com/aglover/ubuntu-equip/raw/master/equip_elasticsearch.sh <span class="o">&amp;&amp;</span> bash equip_elasticsearch.sh
</span></code></pre></td></tr></table></div></figure>


<p>This script doesn&#8217;t start ElasticSearch for you; thus, go ahead and change directories into the <code>elasticsearch</code> directory and fire it up like so:</p>

<figure class='code'><figcaption><span>starting elasticsearch</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>~/elasticsearch<span class="nv">$ </span>bin/elasticsearch -f
</span></code></pre></td></tr></table></div></figure>


<p>Take a deep breath (but not too deep, as I need you to finish in less than 60 seconds) and find the Public DNS of the AMI you&#8217;ve been working on. Go ahead and copy it, then fire up a browser on your local machine and go to http://YOUR_AMI_DNS_NAME.com:9200/_plugin/inquisitor/ (be sure to note the port).</p>

<p>By the way, <a href="https://github.com/polyfractal/elasticsearch-inquisitor">Inquisitor</a> is a handy web application that lets you query your indexes. It was installed via the Ubuntu-Equip script &#8211; this tool is invaluable in figuring out how to properly query your indexes.</p>

<p>And that is it. In less than 60 seconds you&#8217;ve got ElasticSearch running in the cloud for you. Want to create a cluster? No problem, just follow these steps again to fire up another ElasticSearch instance and then <a href="http://www.elasticsearch.org/videos/three-nodes-and-one-cluster/">configure the cluster accordingly</a>.</p>

<p>I&#8217;ve not gone over <a href="http://www.elasticsearch.org/guide/reference/setup/configuration/">configuring ElasticSearch</a> nor have I showed you how to create ElasticSearch as a service on a Linux instance, but for one minute, what do you expect?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Mobile-isticly optimized in 10 seconds]]></title>
    <link href="http://aglover.github.com/blog/2013/05/15/mobile-isticly-optimized-in-10-seconds/"/>
    <updated>2013-05-15T13:20:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/05/15/mobile-isticly-optimized-in-10-seconds</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/unoptmobile.png">Anyone ever told you that your website isn&#8217;t mobile optimized? Or have you ever seen a lilliputian-looking website on your device? You know, one that renders so small you are forced to squint as you enlarge various parts of the site with your fingers just to read it?</p>

<p>Websites render this way on mobile devices because they lack a simple <code>meta</code> tag. While the subject of mobile website optimization can be rather involved (especially when dealing with <a href="http://css-tricks.com/css-media-queries/">CSS media queries</a>, which take longer than 10 seconds to understand), there is a simple trick that can at least can make your website render normally on a mobile device. And it can be done in 10 seconds.</p>

<!--more-->


<p>Simply add the following <code>meta</code> tag in the <code>head</code> element of your website&#8217;s index page:</p>

<figure class='code'><figcaption><span>viewport definition</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">&quot;viewport&quot;</span> <span class="na">content=</span><span class="s">&quot;width=device-width, initial-scale=1&quot;</span><span class="nt">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The viewport <code>meta</code> tag is supported by browsers on both iOS, Android, and by other device browsers including Internet Explorer Mobile on Windows Phone 8. This tag instructs a browser on how to properly display a webpage; without it, a webpage is, unfortunately, displayed mini-style on device browsers, which have a narrow width.</p>

<p>Thus, the viewport tag essentially zooms in the display of a webpage. In the case of the example tag above, the width of the website is set to the device&#8217;s width and the scale is set to 100% &#8211; this&#8217;ll allow the website to be displayed normally on a mobile device. Website visitors won&#8217;t have to squint or pinch and expand to just to read the site&#8217;s relevant text.</p>

<p><a href="http://www.paulund.co.uk">Paulund.co.uk</a> has a really <a href="http://www.paulund.co.uk/understanding-the-viewport-meta-tag">good write up</a> regarding the usage of the viewport <code>meta</code> tag as well as CSS media queries; what&#8217;s more, the good folks who created <a href="http://html5boilerplate.com/mobile/">HTML5boilerplate.com</a> have a <a href="http://t.co/dKP3o1e">nifty presentation</a> that&#8217;s worth a read too.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The democratization of search]]></title>
    <link href="http://aglover.github.com/blog/2013/05/14/the-democratization-of-search/"/>
    <updated>2013-05-14T11:33:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/05/14/the-democratization-of-search</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/democracy.jpg">Over the past year and a half, I&#8217;ve watched <a href="http://www.elasticsearch.org/">ElasticSearch</a> grow from a seemingly part-time code experiment into a thriving ecosystem. Not only has the number of <a href="http://www.elasticsearch.org/guide/clients/">client libraries</a> grown from 1 to over 25 (and counting!); it&#8217;s now a <a href="http://www.elasticsearch.com/">commercially sponsored project</a> to the tune of <a href="http://www.whiteboardmag.com/youre-hot-or-not-why-elasticsearch-raised-24-million-just-3-months-after-a-10-million-round/">$34 million</a> (a <a href="http://www.zdnet.com/elasticsearch-raises-24-million-big-data-analytics-7000011496/">$10M series A</a> and a <a href="http://gigaom.com/2013/02/19/open-source-search-tool-elasticsearch-gets-24m/">$24M series B</a>) with 200,000 downloads a month.</p>

<p>Search is the touchstone of the Internet; without search the Internet wouldn&#8217;t be all that useful. Google&#8217;s meteoric rise and its resultant eponymous name for search is clear evidence as to the importance of search. Search, however, hasn&#8217;t always been that easy nor affordable to implement.</p>

<!--more-->


<p>Before the likes of open source projects like <a href="http://lucene.apache.org/">Lucene</a>, implementing search in an application involved an expensive commercial product or a series of SQL <code>like</code> statements that were never really good enough. Lucene, however, isn&#8217;t a simple hobbyist&#8217;s pursuit. Lucene requires a lot of expertise; what&#8217;s more, successful projects within the Lucene ecosystem, like <a href="http://lucene.apache.org/solr/">Solr</a> lack a key feature that is defining modern architectures: <a href="http://www.searchblox.com/solr-vs-elasticsearch">distributed</a>.</p>

<p>The continued low cost of storage combined with cheap rent-able infrastructures like <a href="http://www.drdobbs.com/web-development/getting-started-with-the-cloud-amazon-we/231601598">AWS</a> has made it convenient to store a plethora of data, thus bringing to bear the importance that applications must support searching vast amounts of data, do it quickly, and affordably. This is where <a href="http://www.ibm.com/developerworks/java/library/j-javadev2-24/">ElasticSearch shines</a>.</p>

<p><a href="http://www.elasticsearch.org/overview/">ElasticSearch sits on top of Lucene</a> and adds not only a simple API for adding and searching content, but does it in a distributed manner. With infinitesimal arm grease, you can set up a search cluster that smears your data and resultant queries across a series of nodes. Not only is this resultant architecture fast, but it&#8217;s easy to set up and extremely affordable as search nodes can run on commodity hardware. In essence, ElasticSearch brings search to the masses.</p>

<p>Google and its resultant ease of search has changed the mindset of application users. Searching content is a <em>presumed feature</em> and if you don&#8217;t provide it, you&#8217;re already a few steps behind your competition. ElasticSearch is clearly a path to constructing a viable, easy to install, affordable, distributed search infrastructure for any application. If you don&#8217;t believe me, take a look at some of the innovative companies with substantial amounts of users using it: <a href="https://github.com/">Github</a>, <a href="https://foursquare.com/">foursquare</a>, and <a href="http://stackoverflow.com/">Stack Overflow</a> are just a few.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Hold your horses! It's still only a two horse race.]]></title>
    <link href="http://aglover.github.com/blog/2013/05/09/hold-your-horses-its-still-only-a-two-horse-race/"/>
    <updated>2013-05-09T12:49:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/05/09/hold-your-horses-its-still-only-a-two-horse-race</id>
    <content type="html"><![CDATA[<p><img class="left" src="http://aglover.github.com/images/mine/2horsesracesm.jpg">There has been a lot of excitement in recent months regarding a few new entrants to the mobile operating systems arena including <a href="http://www.mozilla.org/en-US/firefox/partners/">Firefox OS</a>, <a href="https://www.tizen.org/">Tizen</a>, and <a href="https://wiki.ubuntu.com/Touch">Ubuntu Touch</a>. These relatively nascent projects, which are all built on top of a Linux kernel, appear to have fully embraced HTML 5 apps; indeed, HTML 5 apps on these operating systems are first class citizens that can run without a browser. Moreover, the ubiquity of HTML 5 means the same app can run on all 3 of these operating systems plus Android and iOS!</p>

<p>What&#8217;s also exciting is that there are some major players behind these projects &#8211; Mozilla is, of course behind Firefox OS, Canonical is behind Ubuntu Touch, and quite a few large players are behind Tizen, including Samsung. <a href="http://www.forbes.com/sites/haydnshaughnessy/2013/04/13/how-mozillas-firefox-os-will-open-up-the-smartphone-market/">Firefox OS even appears to be courting carriers with an opportunity to run their own app stores</a>. This app store opportunity naturally has carriers foaming at the mouth to re-assert some semblance of control: behold the Verizon app store! All apps are $0.99 and we&#8217;ll just bill you at the end of the month (like we used to do for all those ringtones you were accustomed to download back when we were in control of all things device-related before Apple destroyed that cash cow).</p>

<!--more-->


<p>Naturally, we&#8217;re all eager to see how these new entrants fair. It reminds me of how interested I was in learning more about <a href="http://www.windowsphone.com/en-us/how-to/wp8/start/whats-new-in-windows-phone">Windows Phone 8</a> and even <a href="http://global.blackberry.com/blackberry-10.html">Blackberry&#8217;s latest and greatest attempt</a> at regaining some composure.</p>

<p>But then I remember this stunning fact: Apple and Google</p>

<blockquote><p>together control nearly 9 out of 10 smartphones sold globally.</p><footer><strong>Tomi Ahonen</strong> <cite><a href='http://www.forbes.com/sites/haydnshaughnessy/2013/04/09/ios-vs-android-can-competitors-break-apple-and-googles-stranglehold/'>Can These Competitors Break Apple and Google&#8217;s Stranglehold on the Mobile OS?</a></cite></footer></blockquote>


<p>Even with industry heavyweight contenders (who are not new to mobile!) like <a href="http://www.windowsphone.com/en-us">Microsoft</a> and <a href="http://us.blackberry.com/">Blackberry</a> (who, we all should remember, <em>owned</em> the smartphone market before Apple got involved) haven&#8217;t really made a dent. Granted, it&#8217;s early to rush to conclusions, however, preliminary signs don&#8217;t bode well for either company.</p>

<p>The co-CEO of Samsung had some stinging criticism for Microsoft:</p>

<blockquote><p>Smartphones and tablets based on Microsoft&#8217;s Windows operating system aren&#8217;t selling very well. There is a preference in the market for Android. In Europe, we&#8217;re also seeing lackluster demand for Windows-based products.</p><footer><strong>JK Shin</strong> <cite><a href='http://www.theverge.com/2013/3/15/4106980/samsung-ceo-jk-shin-says-windows-isnt-selling-very-well'>New Samsung CEO Says There Is &#8216;Lackluster Demand&#8217; for Windows Tablets and Phones</a></cite></footer></blockquote>


<p>Blackberry appears to have some demand in the UK and Canada, a recently analyst T. Michael Walkley had this to say:</p>

<blockquote><p>While we anticipate stronger near-term results for BlackBerry as higher margin BB10 smartphones sell into the channel, we do not believe BlackBerry can achieve sell-through market share levels to return to sustained profit levels</p><footer><strong>T. Michael Walkley</strong> <cite><a href='http://business.financialpost.com/2013/05/06/blackberry-estimates-cut-despite-q10-strength-likely-offsetting-z10-weakness/'>BlackBerry Sales Forecast Cut Despite Strong Demand for Q10</a></cite></footer></blockquote>


<p>The salient point, nevertheless, is that neither Microsoft or Blackberry have yet to make a dent into the Google-Apple duopoly. And so while it&#8217;s easy to get excited about new entrants like Ubuntu Touch, the reality, at least for the time being, is that these operating systems will have little impact in the smartphone market.</p>

<p>After all, when your competition essentially owns 9 out of every 10 smartphones, evolutionary enhancements aren&#8217;t enough to break that stranglehold: you have to do something <em>revolutionary</em>. Besides, we&#8217;ve already seen this before: the iPhone was not an evolutionary offshoot of the Blackberry. It was revolutionary. Sadly, neither Ubuntu Touch, Tizen, nor Firefox OS appear revolutionary.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Rails, CloudFront, and Heroku performance hat-trick]]></title>
    <link href="http://aglover.github.com/blog/2013/05/01/the-rails-cloudfront-and-heroku-performance-hat-trick/"/>
    <updated>2013-05-01T09:10:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/05/01/the-rails-cloudfront-and-heroku-performance-hat-trick</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/hat-trick.png"><a href="http://aws.amazon.com/cloudfront/">Amazon CloudFront</a> is a pay-as-you-go global <a href="http://en.wikipedia.org/wiki/Content_delivery_network">content delivery network</a> (or CDN) that provides high availability and high performance serving of static assets. Basically, it means users have to wait less time to view your web app regardless of their location on the globe.</p>

<p>It&#8217;s easy to configure a <a href="http://rubyonrails.org/">Rails</a> app to take advantage of CloudFront; what&#8217;s more, if your Rails app is hosted on <a href="http://www.ibm.com/developerworks/java/library/j-javadev2-21/">Heroku</a>, there&#8217;s <a href="https://github.com/romanbsd/heroku-deflater">a nifty gem</a>, dubbed heroku-deflater, that&#8217;ll enable <a href="http://en.wikipedia.org/wiki/HTTP_compression">HTTP compression</a> of static assets (<a href="http://stackoverflow.com/questions/12326191/any-way-to-serve-gzip-assets-from-heroku">other than images</a>).</p>

<p>To get these three entities to play nicely together requires a few simple steps. Let me show you how.</p>

<!--more-->


<p>First, if you want to enable HTTP gzip compression of static assets other than images from a Heroku app, then add the heroku-deflater gem to your <code>Gemfile</code>. This gem doesn&#8217;t compress images as in some cases, zipping images creates bigger ones!</p>

<p>Once you&#8217;ve run <code>bundle install</code> and deployed your app to Heroku, fire up a terminal and run <code>[cURL](http://thediscoblog.com/blog/2013/04/18/curling-for-wget/)</code> to verify that the HTTP response Content-Encoding is gzip like so:</p>

<figure class='code'><figcaption><span>cURL testing gzip response</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>curl -i -H <span class="s2">&quot;Accept-Encoding: gzip,deflate&quot;</span> http://your.awesome.web.app
</span></code></pre></td></tr></table></div></figure>


<p>You should see in the response this key phrase:</p>

<figure class='code'><figcaption><span>cURL response</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Content-Encoding: gzip
</span></code></pre></td></tr></table></div></figure>


<p>If you do see the Content-Encoding set to gzip, then you are good to go. If, for some reason, you don&#8217;t see it, check your environment&#8217;s configuration file (which you will have to edit to get CloudFront working anyway) and verify that the property <code>config.serve_static_assets</code> is set to <code>true</code>.</p>

<p>Next, sign into the AWS Management Console and enable CloudFront if you haven&#8217;t already. From the CloudFront admin page, create a new distribution via the Create Distribution button on the top left.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_1.png"></p>

<p>Once the create distribution wizard begins, be sure to select Download as your delivery method.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_2.png"></p>

<p>In the next screen, there are some important fields you&#8217;ll need to fill out, namely: the Origin Source Name and the Viewer Protocol Policy. For the Origin Source Name, you will need to put in your app&#8217;s URL or the Heroku URL (if you do not map a custom domain name to it). If you web site supports HTTPS, then be sure to set the Viewer Protocol Policy to HTTP and HTTPS.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_3.png"></p>

<p>The only other important setting after these two is the Price Class. It&#8217;s here where you can set where CloudFront will essentially serve up your content &#8211; the default setting of Use All Edge Locations is most likely what you need.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_5.png"></p>

<p>Finally, click the Create Distribution button &#8211; once you do that, it&#8217;ll take a bit for things to initialize (basically, the CDN needs to get built and this may take up to 30 minutes).</p>

<p>Now to configure your Rails app, you&#8217;ll need to open up your target environment&#8217;s configuration file (i.e. <code>production.rb</code>). The <a href="http://bindle.me/blog/index.php/395/caches-cdns-and-heroku-cedar">two fields</a> you&#8217;ll want to be sure are properly set are <code>serve_static_assets</code> and <code>static_cache_control</code>. In particular, you are setting the cache control variable to one year. This means that once a static asset, like a JavaScript file is downloaded to the browser, it&#8217;ll be cached for one year. Don&#8217;t fret, however, if you think that&#8217;ll inhibit change &#8211; the file that is ultimately downloaded has a hash attached to it (via the magic of <a href="http://guides.rubyonrails.org/asset_pipeline.html">Rail&#8217;s Asset Pipeline</a>). Consequently, the file that is cached is something like <code>your_js_file-asdf098203820980a980</code> where that last bit is a hash value that&#8217;ll change if the file itself changes.</p>

<figure class='code'><figcaption><span>production.rb edited to support CDN</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">config</span><span class="o">.</span><span class="n">serve_static_assets</span> <span class="o">=</span> <span class="kp">true</span>
</span><span class='line'><span class="n">config</span><span class="o">.</span><span class="n">static_cache_control</span> <span class="o">=</span> <span class="s1">&#39;public, max-age=31536000&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The last change you need to make to your environment file is to set the <code>asset_host</code> to the CloudFront domain that you just created. You can find this in your AWS Management Console &#8211; it&#8217;ll be a cryptic URL like http://asdjlkj2321.cloudfront.net.</p>

<figure class='code'><figcaption><span>production.rb edited to support asset host</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">config</span><span class="o">.</span><span class="n">action_controller</span><span class="o">.</span><span class="n">asset_host</span> <span class="o">=</span> <span class="s1">&#39;the domain name from AWS Dashboard&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Commit your changes and deploy your app.</p>

<p>To verify things are kosher, you&#8217;ll need to give it some time (check the status of your CloudFront CDN &#8211; if it&#8217;s status is Enabled then you are good to go!). If things are ready, then fire up a browser and go to your app.</p>

<p>In this case, <a href="http://thediscoblog.com/blog/2013/04/15/chromes-console-commands/">I&#8217;m using Chrome</a>. Go to JavaScript console and hit the Network tab.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_6.png"></p>

<p>Surf around and you&#8217;ll note a few things &#8211; one, that the assets like images and JavaScript files are being severed up from your CDN (just look at the URL) and that the size will often say &#8220;(from cache)&#8221; &#8211; that means the CDN is handling the load rather than <a href="http://www.ibm.com/developerworks/podcast/glover-heroku-110811/">Heroku</a>. You should also note that your web app is probably a bit more snappy!</p>

<p><img class="center" src="http://aglover.github.com/images/mine/cloudfront_7.png"></p>

<p>Check out your Heroku logs and you&#8217;ll note fewer hits in this case &#8211; dynamic pages are still being loaded, however, static assets are not anymore &#8211; that&#8217;s the job of your CDN!</p>

<p>CloudFront isn&#8217;t free; nevertheless, I think you&#8217;ll find the corresponding cost quite reasonable. Pricing will vary depending on how much content you&#8217;ll be serving up with CloudFront &#8211; this is a function of how many visitors you have <em>along with</em> how many static assets that are ultimately downloaded to a user&#8217;s browser. For instance, 500GB of average content will cost you less than $75/month.</p>

<p>CloudFront&#8217;s pay-as-you-go model makes it extremely affordable to add a nice bit of pep to your app&#8217;s performance along with using gzip compression and HTTP caching. And hopefully as I&#8217;ve shown you, it&#8217;s rather easy to do with a Rails app running on Heroku.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Mobile for the masses: gestures and test deployments]]></title>
    <link href="http://aglover.github.com/blog/2013/04/24/mobile-for-the-masses-gestures-and-test-deployments/"/>
    <updated>2013-04-24T21:13:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/24/mobile-for-the-masses-gestures-and-test-deployments</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/mftm_1.jpg">My second article in <a href="http://www.ibm.com/developerworks/">IBM developerWorks</a>&#8217; series <a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=mobile+for+the+masses">Mobile for the Masses</a> is out! <a href="http://www.ibm.com/developerworks/java/library/j-mobileforthemasses2/index.html">This article</a> covers how to go about designing a mobile interface from the standpoint of usability via gestures. In essence, eschew buttons and prefer the swipe! What&#8217;s more, I cover at a high level how to test your app on an Android device.</p>

<p>As the article summary states:</p>

<blockquote><p>Mobile users are typically distracted, busy, and ergonomically constrained, so build your mobile application UIs accordingly. Andrew Glover discusses key factors that differentiate mobile apps from web apps, then guides you through the creation of a mobile application UI that uses swipe gestures for navigation rather than button clicks.</p><footer><strong>IBM DeveloperWorks</strong> <cite><a href='http://www.ibm.com/developerworks/java/library/j-mobileforthemasses2/index.html'>Mobile for the Masses: Take a Swipe at It! Programming Gestures in Android</a></cite></footer></blockquote>


<p>So what are you waiting for? Check out &#8221;<a href="http://www.ibm.com/developerworks/java/library/j-mobileforthemasses2/index.html">Mobile for the masses: Take a swipe at it! Programming gestures in Android</a>&#8221; and trade buttons for swipes in your Android mobile apps! And if you missed the first article, check out &#8221;<a href="http://www.ibm.com/developerworks/library/j-mobileforthemasses1/">Mobile for the masses: A gentle introduction to Android</a>&#8221; and learn the ins and outs of Android development!</p>

<p>Stay tuned for more articles in this series and don&#8217;t forget to watch for <a href="http://thediscoblog.com/blog/categories/mobile/">mobile focused articles on this blog</a> as well.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[cURLing for Wget]]></title>
    <link href="http://aglover.github.com/blog/2013/04/18/curling-for-wget/"/>
    <updated>2013-04-18T09:33:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/18/curling-for-wget</id>
    <content type="html"><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Wget">Wget</a> is an extremely handy utility I use all the time when I find myself on a Linux box. It&#8217;s quite helpful, for example, for downloading files. Need to <a href="https://github.com/aglover/ubuntu-equip/blob/master/equip_ruby.sh">install Ruby</a>? No problem, just download the binary like so:</p>

<figure class='code'><figcaption><span>wget example of downloading Ruby binary</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p180.tar.gz
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>and you&#8217;re one step closer. There&#8217;s no flags to remember either.</p>

<!--more-->


<p>Wget, however, isn&#8217;t natively available on OSX. From time to time, I&#8217;m stung to see the nefarious &#8216;command not found&#8217; message after expectantly waiting to see some file I need downloaded.</p>

<p>Luckily, you can force <a href="http://curl.haxx.se/docs/manpage.html">cURL</a> to act like Wget with a few flags. Simply use the <code>-OL</code> flags like so:</p>

<figure class='code'><figcaption><span>cURL acting like Wget</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>curl -OL http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p180.tar.gz
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>and you&#8217;ll be on your way to downloading some file.</p>

<p>Of course, it&#8217;s possible to get <code>wget</code> on your Mac via <a href="http://osxdaily.com/2012/05/22/install-wget-mac-os-x/">MacPorts or Homebrew</a>; nevertheless, knowing you can achieve the same goals with cURL is always handy.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Chrome's console commands]]></title>
    <link href="http://aglover.github.com/blog/2013/04/15/chromes-console-commands/"/>
    <updated>2013-04-15T10:05:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/15/chromes-console-commands</id>
    <content type="html"><![CDATA[<p>As if the JavaScript console in Chrome couldn&#8217;t be any more awesome. Check it out: <a href="https://developers.google.com/chrome-developer-tools/docs/commandline-api">Command Line API Reference</a>. Yep, it&#8217;s legit. I&#8217;ve been using Firebug and the like for years and only just ran across this feature of Chrome&#8217;s JavaScript console.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/jschrome.png"></p>

<p>My favorite: <code>getEventListeners</code>. Understanding how the DOM is augmented with listeners is amazingly helpful!</p>

<p>All you have to do is fire up the JavaScript Console in Chrome and in the actual console window, you have a host a commands you can execute now just like you have in any other terminal app. Very helpful!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Hybrid inappropriateness]]></title>
    <link href="http://aglover.github.com/blog/2013/04/14/hybrid-inappropriateness/"/>
    <updated>2013-04-14T11:14:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/14/hybrid-inappropriateness</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/confused.png">The mobile development landscape is <a href="http://skytechgeek.com/2011/09/10-mobile-application-frameworks-for-easy-development/">bursting at the seams</a> with frameworks and tools that enable you to target <a href="http://thediscoblog.com/blog/2013/03/25/modeveast-2012-panel-discussion/">two primary mobile platforms</a>: iOS and <a href="http://thediscoblog.com/blog/categories/android/">Android</a>. And the mobile community has <a href="http://thediscoblog.com/blog/2012/12/02/comprehending-the-mobile-development-landscape/">classified these frameworks and tools</a> into three categories: native, hybrid, and web. Unfortunately, limiting the classification to three <a href="http://thediscoblog.com/blog/2013/04/05/crowd-think-often-lacks-clarity/">is inadequate</a> as the term hybrid is too generic.</p>

<p>Web apps are truly ubiquitous because they take advantage of the browser and are thus, cross platform. You, for the most part, can get away with <a href="http://thediscoblog.com/blog/2012/09/01/cost-and-the-great-mobile-app-debate/">maintaining one code base</a> that can be viewed on iOS, Android, and the other minor players. Yet, the key point of Web apps is that they are <a href="http://thediscoblog.com/blog/2012/09/25/modevtablet-2012-video-mobile-web-realities/"><em>web sites</em>, not mobile apps</a>.</p>

<!--more-->


<p>As you begin to blur that mobile app/mobile website line, you&#8217;ll <a href="http://thediscoblog.com/blog/2013/03/04/its-a-question-of-wow/">stumble over various issues</a> like performance or varying behaviors depending on the underlying device.  Worse, you&#8217;ll find that <a href="http://thediscoblog.com/blog/2012/09/24/a-tale-of-three-browsers/">not all browsers are created equally</a> and thus, you&#8217;ll need to <a href="http://thediscoblog.com/blog/2013/02/17/circumventing-mobile-ux-expectations/">compensate for various scenarios</a> or use assorted compensating tools like <a href="http://modernizr.com/">Modernizr</a>. Or, you&#8217;ll find yourself throwing the web app into a container because you want mass distribution via an app store or because you want to take advantage of some native feature.</p>

<p>And at that point, in the eyes of many, you&#8217;ve built a hybrid mobile app. But that&#8217;s not the whole story.</p>

<p>Hybrid frameworks aren&#8217;t all created equal.  There are, in fact, two flavors of hybrid-ness: <em>hybrid-web</em> and <em>hybrid-native</em>. Both are extremely different; in fact, to showcase the difference, I need only compare the &#8220;featured&#8221; apps of two hybrid frameworks: <a href="http://phonegap.com/">PhoneGap</a> and <a href="http://www.madewithmarmalade.com/">Marmalade</a>.</p>

<p>PhoneGap is a great framework for building hybrid-web apps. You code in HTML and JavaScript and the resultant code is run inside of a web view managed by a native container.  You ostensibly write one code base and deploy to all the primary mobile platforms. Similar frameworks are: <a href="http://www-01.ibm.com/software/mobile-solutions/worklight/">IBM&#8217;s Worklight</a> and <a href="http://www.icenium.com/">Icenium</a>. <a href="http://www.sencha.com/products/touch">Sencha Touch</a> falls into this realm as well when you employ their container technology.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/phonegap_example.png"></p>

<p><a href="http://www.madewithmarmalade.com/">Marmalade</a> is a hybrid-native app platform; that is, you can code in an intermediary language like C++ that is ultimately compiled down into native code (i.e. Java for Android, Objective-C for iOS, etc). These apps are not characterized by a web view in any way. They are native, close to the bone as it gets apps. The benefit is that you only had to write <em>one code base</em>, the underlying tool took care of the dirty work in making it work similarly on iOS and Android, for example. Similar frameworks are: <a href="http://www.coronalabs.com/">Corona</a>, <a href="http://www.mosync.com/">MoSync</a>, and <a href="http://www.appcelerator.com/">Appcelerator</a> to name a few.</p>

<p><img class="center" src="http://aglover.github.com/images/mine/marmalate_example.png"></p>

<p>Now look closely at the <a href="http://phonegap.com/app/feature/">featured apps</a> of each <a href="http://www.madewithmarmalade.com/app-showcase">hybrid framework</a>. They&#8217;re <a href="http://phonegap.com/blog/2011/11/07/phonegap-application-craft-pain-free-mobile-app-development/">distinctly</a> <a href="http://www.madewithmarmalade.com/marmaladesdk/application/cut-rope">different</a> aren&#8217;t they?</p>

<p>PhoneGap and the rest of the hybrid-web frameworks are good at producing informational apps. These apps can look beautiful and certainly can have some compelling features like tight integration with social networks and geo-tracking, for example. But they&#8217;re inadequate for games and still lack a rich user experience when compared to more native apps like Flipboard or AngryBirds.</p>

<p>Marmalade and the rest of the hybrid-native crowd shine when it comes to highly interactive apps like games; what&#8217;s more, these frameworks can build an app that generates a wow. And therein lies the crucial aspect that&#8217;s missed when the industry blindly assumes all hybrid options are similar. They couldn&#8217;t be more incorrect &#8211; thus, we need at least four categories (native, web, hybrid-native, and hybrid-web) and we need to eschew the lone term &#8220;hybrid&#8221; as it lacks clarification and therefore has no meaning.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Painless Android swipe detection]]></title>
    <link href="http://aglover.github.com/blog/2013/04/07/painless-android-swipe-detection/"/>
    <updated>2013-04-07T10:37:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/07/painless-android-swipe-detection</id>
    <content type="html"><![CDATA[<p><img class="left" src="http://aglover.github.com/images/mine/gesticulate.png">Why bother building navigation buttons in an Android app when you can easily capture finger swipes? But, if you&#8217;ve ever implemented gesture section in Android there&#8217;s the drudgery of implementing listeners and you also need to do some elementary Cartesian math. Save yourself the boilerplate bother mathematics and use a <a href="https://github.com/aglover/gesticulate">library</a>!</p>

<p><a href="https://github.com/aglover/gesticulate">Gesticulate</a> makes it painless to detect straightforward swiping motions like up, down, left, and right. It&#8217;s a simple jar file you include in your Android <code>libs</code> directory. Throw Gesticulate&#8217;s <code>SwipeDetector</code> inside an instance of Android&#8217;s <code>SimpleOnGestureListener</code>, for example, and you&#8217;re detecting swipes with ease!</p>

<p>Gesticulate is used in Savvy Words, a flash card vocabulary app found on <a href="https://play.google.com/store/apps/details?id=com.b50.savvywords">Google Play</a> and <a href="http://www.amazon.com/Beacon50-Savvy-Words/dp/B00C535D20/ref=sr_1_1?s=mobile-apps&amp;ie=UTF8&amp;qid=1365339189&amp;sr=1-1">Amazon&#8217;s Appstore for Android</a>. See the <a href="https://github.com/aglover/gesticulate">Github project</a> for more details such as code examples for how to use Gesticulate, how to build it, and to see Gesticulate&#8217;s tests. Swipe on, baby!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Crowd think often lacks clarity]]></title>
    <link href="http://aglover.github.com/blog/2013/04/05/crowd-think-often-lacks-clarity/"/>
    <updated>2013-04-05T21:04:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/04/05/crowd-think-often-lacks-clarity</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/crowd.jpg">In case you missed it, <a href="http://www.infoq.com/">InfoQ</a> has an <a href="http://www.infoq.com/research/cross-platform-mobile-tools">interesting analysis regarding hybrid mobile app development frameworks</a>. They are profiling 12 tools and soliciting community feedback so as to make a <a href="http://www.thoughtworks.com/insights">ThoughtWorks-like technology radar</a>. If you participate in the voting you are entitled to see the voting distribution.</p>

<p>What&#8217;s interesting (and not too surprising) about this analysis is that frameworks like <a href="http://phonegap.com/">PhoneGap</a> or <a href="http://jquerymobile.com/">jQuery Mobile</a> (and laughably <a href="http://jqtjs.com/">JQTouch</a>?) are leaning more towards <em>adoption ready</em> when compared to frameworks like <a href="http://www.madewithmarmalade.com/">Marmelade</a>, <a href="http://www.coronalabs.com/">Coronona</a> or <a href="http://www.mosync.com/">MoSync</a>. But this radar lacks some clarifying dimensions &#8211; for example, if you want to produce a mobile website on a lot of different mobile platforms quickly, then PhoneGap is probably the way to go. But if you&#8217;re looking to create a mobile app, then the choice to use PhoneGap must be treated with extreme caution.</p>

<!--more-->


<p>You cannot create a <a href="http://thediscoblog.com/blog/2013/03/04/its-a-question-of-wow/">compelling user experience</a> that works across <a href="http://thediscoblog.com/blog/2012/09/01/cost-and-the-great-mobile-app-debate/">all platforms consistently</a> with this framework right now. And it isn&#8217;t even the fault of PhoneGap entirely &#8211; it&#8217;s <a href="http://thediscoblog.com/blog/2013/02/17/circumventing-mobile-ux-expectations/">HTML5</a>. That&#8217;s why going with something like JQTouch without viewing the big picture of what you are building is laughable.</p>

<p>Frameworks like Marmelade or Corona might be a bit more difficult to get started with (after all, you code in something other than HTML or JavaScript) but they can produce a native app that offers a compelling user experience capable of generating a wow. Remember, native-ness <a href="http://thediscoblog.com/blog/2012/09/24/a-tale-of-three-browsers/">trumps the browser</a> almost always unless your app is a series of screens that don&#8217;t require the user to interact.</p>

<p>Accordingly, the study lacks some needed dimensions &#8211; mainly, whether or not you are building a mobile app or mobile website. Don&#8217;t fall into the hype trap and jump into PhoneGap development unless you are sure what you are building is a simple mobile website and your audience isn&#8217;t expecting something like Flipboard or AngryBirds. Otherwise, you&#8217;ll find yourself investigating either pure play native development or frameworks that ultimately produce a native app.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Mongoid batch inserts]]></title>
    <link href="http://aglover.github.com/blog/2013/03/27/mongoid-batch-inserts/"/>
    <updated>2013-03-27T11:34:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/03/27/mongoid-batch-inserts</id>
    <content type="html"><![CDATA[<p>In SQL land, all databases support batch inserts. Batch inserts are an effective and efficient mechanism to insert a lot of similar data. That is, instead of issuing x insert statements, you execute 1 insert with x records. This is much more efficient because the insert statement doesn&#8217;t need to be re-parsed x times, there is only 1 network trip as opposed to x, and in the case of transactions, there is only 1 transaction instead of x. When compared to x inserts, batch inserts are always faster.</p>

<p>As it turns out, <a href="http://www.mongodb.org/">MongoDB</a> supports <a href="http://docs.mongodb.org/manual/applications/create/#bulk-insert-multiple-documents">batch inserts</a>! And just like in SQL land, Mongo&#8217;s batching feature is much faster at inserting a lot of data in one insert rather than x inserts.</p>

<p>For example, the <a href="https://github.com/mongodb/mongo-ruby-driver">Mongo Ruby driver</a>&#8217;s <a href="https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/collection.rb#L371">insert method takes a collection</a>; thus, you can insert an array of hashes quite efficiently. Even if you are using a <a href="http://mongoid.org/en/mongoid/index.html">ODM like Mongoid</a>, you can still perform batch inserts as all you need to do is get a reference to the model object&#8217;s underlying collection and then issue an <code>insert</code> with an array of hashes matching the collection&#8217;s intended document structure.</p>

<p>For instance, to insert a collection of <code>Tag</code> models (each having 3 fields: <code>name</code>, <code>system_tag</code>, and <code>account_id</code>) in one fell swoop I can do the following:</p>

<figure class='code'><figcaption><span>Batch inserts with Mongoid model example</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">tags</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;bunch&#39;</span><span class="p">,</span> <span class="s1">&#39;of&#39;</span><span class="p">,</span> <span class="s1">&#39;tags&#39;</span><span class="o">].</span><span class="n">collect</span> <span class="p">{</span> <span class="o">|</span><span class="n">tag</span><span class="o">|</span> <span class="p">{</span><span class="nb">name</span><span class="p">:</span> <span class="n">tag</span><span class="p">,</span> <span class="n">system_tag</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="n">account_id</span><span class="p">:</span> <span class="nb">id</span><span class="p">}</span> <span class="p">}</span>
</span><span class='line'><span class="no">Tag</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">insert</span> <span class="n">tags</span>
</span></code></pre></td></tr></table></div></figure>


<p>In the code above, the <code>insert</code> takes a collection of hashes; what&#8217;s more, the <code>insert</code> is tied to the <code>tags</code> collection via the <code>Tag.collection</code> call.</p>

<p>Batch inserts are always faster if you have a lot of similar documents &#8211; in our case, we saw a <em>tremendous</em> performance increase when employing batching.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[MoDevEast 2012 panel discussion]]></title>
    <link href="http://aglover.github.com/blog/2013/03/25/modeveast-2012-panel-discussion/"/>
    <updated>2013-03-25T18:34:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/03/25/modeveast-2012-panel-discussion</id>
    <content type="html"><![CDATA[<p>Last fall, I had the pleasure of moderating a panel discussion at <a href="http://modeveast.com/">MoDevEast</a> entitled &#8221;<a href="http://www.youtube.com/watch?v=b7P-wNuHPL0">What Developers Love and Hate about iOS, Android, Windows and HTML5</a>&#8221; with five super star mobile app developers.</p>

<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/b7P-wNuHPL0 "></iframe></div>




<p></p>


<p>The panelists are a diverse set, which made the interaction a lot of fun as each had unique perspectives. Check out what my friends <a href="https://twitter.com/rmm5t">Ryan McGeary</a>, Steve Jernigan, Michael Shapard, <a href="https://twitter.com/andytrice">Andrew Trice</a>, and Chris Kamsler have to say!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2013 Open Analytics Summit]]></title>
    <link href="http://aglover.github.com/blog/2013/03/21/2013-open-analytics-summit/"/>
    <updated>2013-03-21T15:21:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/03/21/2013-open-analytics-summit</id>
    <content type="html"><![CDATA[<p><img class="right left" src="http://www.openanalyticssummit.com/wp-content/uploads/2012/12/OAS-logo-Full-colour3-300x85.png">On March 25, 2013, <a href="http://www.openanalyticssummit.com/speakers/">I&#8217;ll be speaking</a> at the <a href="http://www.openanalyticssummit.com/">Open Analytics Summit in Washington DC</a>; specifically, I&#8217;ll be discussing how the <a href="http://www.app47.com/2013/03/20/next-monday-app47-cto-andy-glover-offers-a-database-reality-check-at-the-open-analytics-summit/">App47</a> team has used <a href="http://www.mongodb.org/">MongoDB</a> as the backend of our enterprise mobile application management platform. We&#8217;ve learned quite a few things about <a href="http://thediscoblog.com/blog/categories/mongodb/">Mongo</a> over the last two years! In the process of growing from a few gigabytes of data a month to over a terabyte/month, we&#8217;ve found out first hand what <a href="http://www.ibm.com/developerworks/training/kp/j-kp-mongo/">Mongo</a> is good at and what it&#8217;s <em>not good at</em>. I&#8217;ll be addressing a number of tips, techniques, and strategies &#8211; if you are a Mongo user or planning on being one, come on by!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Node.js in 3 commands]]></title>
    <link href="http://aglover.github.com/blog/2013/03/12/node-in-3-commands/"/>
    <updated>2013-03-12T11:55:00-04:00</updated>
    <id>http://aglover.github.com/blog/2013/03/12/node-in-3-commands</id>
    <content type="html"><![CDATA[<p>A few <a href="http://www.javaworld.com/community/node/8140">short years ago</a> when I started to explore <a href="http://nodejs.org/">Node.js</a>, I remember the installation on my MacBook Pro required downloading the source, compiling and installing it, and then updating paths. <em>And then</em> you had to install <a href="https://npmjs.org/">NPM</a>.</p>

<p>Since then, <a href="http://www.ibm.com/developerworks/library/j-nodejs/">Node</a>&#8217;s installation has been come tremendously easy and NPM is even <em>bundled</em> with <a href="http://www.ibm.com/developerworks/offers/lp/demos/summary/j-jnodejs.html?ca=drs-">Node</a>. And yet, installing Node (and keeping up w/its rapid release schedule) is even easier with a nifty tool: <a href="https://github.com/creationix/nvm">Node Version Manager</a>.</p>

<p>With Node Version Manager (or <a href="https://twitter.com/aglover/status/105824835149627392">nvm</a>) you can be up and running with Node in 3 easy commands.</p>

<p>Step 1: Download and install nvm.</p>

<figure class='code'><figcaption><span>downloading nvm</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>curl https://raw.github.com/creationix/nvm/master/install.sh | sh
</span></code></pre></td></tr></table></div></figure>


<p>Step 2: Reload your shell.</p>

<figure class='code'><figcaption><span>reloading .bash_profile</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">source</span> .bash_profile
</span></code></pre></td></tr></table></div></figure>


<p>Step 2.5: Obtain a list of available node versions to install.</p>

<figure class='code'><figcaption><span>listing available node versions</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>nvm ls-remote
</span></code></pre></td></tr></table></div></figure>


<p>Step 3: Install your desired version of node.</p>

<figure class='code'><figcaption><span>installing node version 0.10.0</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>nvm install v0.10.0
</span></code></pre></td></tr></table></div></figure>


<p>After that&#8217;s done, execute a <code>node -v</code> to verify. Now wasn&#8217;t that easy? You bet!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The bull's eye on mobility: Mobile for the masses]]></title>
    <link href="http://aglover.github.com/blog/2013/03/06/the-bulls-eye-on-mobility-mobile-for-the-masses/"/>
    <updated>2013-03-06T09:28:00-05:00</updated>
    <id>http://aglover.github.com/blog/2013/03/06/the-bulls-eye-on-mobility-mobile-for-the-masses</id>
    <content type="html"><![CDATA[<p><img class="left" src="http://aglover.github.com/images/mine/mftm_1.jpg">Since joining <a href="http://www.app47.com/">App47</a>, I&#8217;ve been lazer focused on mobility; consquently, I&#8217;m pleased to announce that a new mobile development series has debuted on <a href="http://www.ibm.com/developerworks/">IBM developerWorks</a>! The inaugural article,  &#8221;<a href="http://www.ibm.com/developerworks/library/j-mobileforthemasses1/">A gentle introduction to Android</a>&#8221;, begins by exploring the mobile landscape and introduces how to get started with Android app development.</p>

<p>As the article summary states:</p>

<blockquote><p>The mobile landscape is rich with promise, and Android is a viable and exciting platform for developers who seek a way in. This new series starts with an introduction to Android that is tailored specifically for Java developers just getting started with mobile. Learn about Android&#8217;s three-layer versioning system (and find out why it matters), then set up your development environment and build your first Android app.</p><footer><strong>IBM DeveloperWorks</strong> <cite><a href='http://www.ibm.com/developerworks/library/j-mobileforthemasses1/'>Mobile for the Masses: A Gentle Introduction to Android</a></cite></footer></blockquote>


<p>So what are you waiting for? Check out &#8221;<a href="http://www.ibm.com/developerworks/library/j-mobileforthemasses1/">Mobile for the masses: A gentle introduction to Android</a>&#8221; and learn the ins and outs of Android development! Stay tuned for more articles to come and don&#8217;t forget to watch for <a href="http://thediscoblog.com/blog/categories/mobile/">mobile focused articles on this blog</a> as well.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[It's a question of wow]]></title>
    <link href="http://aglover.github.com/blog/2013/03/04/its-a-question-of-wow/"/>
    <updated>2013-03-04T10:29:00-05:00</updated>
    <id>http://aglover.github.com/blog/2013/03/04/its-a-question-of-wow</id>
    <content type="html"><![CDATA[<p>Let me ask you a question: do you want to build a mobile website or a mobile app? If your answer is mobile website, then <a href="http://www.ebizmba.com/articles/best-html5-websites">HTML5 is good enough</a>. But if your answer is mobile app then you had better <a href="http://www.trademob.com/why-native-apps-remain-unrivalled-by-web-apps-in-user-experience-and-discoverability/">think about user experience</a>. You see, the user experience bar has been set extraordinarily high by a number of stellar native apps. People expect to be wowed and if they aren&#8217;t, they won&#8217;t use your app. It&#8217;s that simple.</p>

<p><img class="right" src="http://aglover.github.com/images/mine/wow.png">How do you wow someone? You make your app easy to use and aesthetically pleasing to the eye. And it has to work correctly consistently. Unresponsiveness, however minor, won&#8217;t do.</p>

<p>Can you wow someone <a href="http://thediscoblog.com/blog/2013/02/17/circumventing-mobile-ux-expectations/">with an HTML5 mobile app</a>? <a href="http://thediscoblog.com/blog/2012/09/24/a-tale-of-three-browsers/">Sometimes</a>. But let me tell you: <a href="http://thediscoblog.com/blog/2012/09/25/modevtablet-2012-video-mobile-web-realities/">it&#8217;s not easy</a>. Don&#8217;t think for a second that just because there are a gazillion developers who have an <a href="http://thediscoblog.com/blog/2012/09/01/cost-and-the-great-mobile-app-debate/">understanding of HTML and JavaScript</a>, that anyone can build an app to inspire a wow. No, it&#8217;s a <a href="http://thediscoblog.com/blog/2012/09/07/past-performance-is-no-guarantee-of-future-results/">tricky business with HTML5</a> these days.</p>

<p>Yep, there are fewer developers out there that actually can code <a href="http://en.wikipedia.org/wiki/Objective-C">Objective-C</a> or truly understand <a href="http://developer.android.com/index.html">Android</a>. They might be costly too. But the wow comes from native apps these days and it looks to be that way for some time. Native apps are close to the bone &#8211; they don&#8217;t have to rely on browser standards or <a href="https://code.google.com/p/html5shiv/">shivs</a> to <a href="http://paulirish.com/2011/the-history-of-the-html5-shiv/">work correctly</a> 83% of the time.  Coded correctly, they work <em>all the time</em>. They are responsive, fast, and can work offline without a lot of magic.</p>

<p><a href="http://en.wikipedia.org/wiki/HTML5">HTML5</a> is great for mobile web sites. Not mobile apps. Until HTML5 can produce a significant wow factor, your best bet is to go native. It&#8217;s that simple.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Everything you need to know about MongoDB]]></title>
    <link href="http://aglover.github.com/blog/2013/02/23/everything-you-need-to-know-about-mongodb/"/>
    <updated>2013-02-23T09:39:00-05:00</updated>
    <id>http://aglover.github.com/blog/2013/02/23/everything-you-need-to-know-about-mongodb</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://aglover.github.com/images/mine/mongodb_icon.png">Are you new to <a href="http://www.mongodb.org/">MongoDB</a>? Curious to see what&#8217;s interesting about it?  Document-oriented databases like MongoDB are vastly different from relational databases in that they don&#8217;t store data in tables; instead, they store it in the form of documents. From a developer&#8217;s perspective, document-oriented (or schemaless) data is simpler and <a href="http://thediscoblog.com/blog/2012/09/03/mongodb-from-the-trenches-masochistic-embedded-collections/">far more flexible</a> to manage than relational data. Rather than storing data into a rigid schema of tables, rows, and columns, joined by relationships, documents are written individually, containing whatever data they require.</p>

<p>Among open source, document-oriented databases, MongoDB is often billed as a <a href="http://www.ibm.com/developerworks/library/j-javadev2-12/">NoSQL database with RDBMS features</a>. One example of this is MongoDB&#8217;s support for dynamic queries that don&#8217;t require predefined MapReduce functions. MongoDB also comes with an interactive shell that makes accessing its datastore refreshingly easy, and its out-of-the-box support for sharding and clustering (via <a href="http://thediscoblog.com/blog/2012/09/11/mongodb-from-the-trenches-prudent-production-planning/">replica sets</a>) enables high scalability across multiple nodes.</p>

<p>Check out this IBM developerWorks&#8217; Knowledge Path dubbed &#8221;<a href="http://www.ibm.com/developerworks/training/kp/j-kp-mongo/">Discover MongoDB</a>&#8221; &#8211; watch four videos, read a few articles, listen to a podcast and learn everything you need to know about MongoDB!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Testing Rails migrations]]></title>
    <link href="http://aglover.github.com/blog/2013/02/18/testing-rails-migrations/"/>
    <updated>2013-02-18T16:22:00-05:00</updated>
    <id>http://aglover.github.com/blog/2013/02/18/testing-rails-migrations</id>
    <content type="html"><![CDATA[<p>I recently found myself searching <a href="http://stackoverflow.com/">Stackoverflow</a> and Google for various techniques for automatically testing <a href="http://guides.rubyonrails.org/migrations.html">Rails migrations</a>. I was surprised not to have found <a href="http://stackoverflow.com/questions/6079016/how-do-i-test-rails-migrations">too much</a> information though. While testing a migration is fairly straightforward (migrations are classes and you can easily invoke corresponding methods); the challenge can be setting models up properly. That is, migrations are a tool to update an underlying database to reflect changes in models &#8211; by the time you are writing a migration, the models <em>already</em> reflect what should be.</p>

<p>Accordingly, to test a migration, you need to set up your test with how things were and then run your migration and verify things have migrated.  As it turns out, this is super easy to do with a document oriented database like <a href="http://www.mongodb.org/">MongoDB</a>. For this particular project, we&#8217;re using <a href="http://mongoid.org/en/mongoid/index.html">Mongoid</a>,  which is an Object-Document-Mapper (or ODM) for MongoDB and we&#8217;re also using a nifty gem dubbed <a href="https://github.com/adacosta/mongoid_rails_migrations">mongoid_rails_migrations</a>, which facilitates writing Mongoid migrations.</p>

<p>In order to reflect the state of the underlying datastore before running a migration, I needed to remove a particular collection, which due to changes in our models, is automatically populated with meta data when various events occur (think <a href="http://en.wikipedia.org/wiki/Database_trigger">relational trigger</a> here, for example). As you can probably see, as this new collection doesn&#8217;t exist in production, all the existing data in production needs some corresponding default meta data to reflect the new requirements which brought this collection to life.</p>

<p>Accordingly, once I initialize my models and the corresponding collection is populated, I need to completely <a href="http://docs.mongodb.org/manual/reference/method/db.collection.drop/">drop the collection</a>. Then, I can run my migration and then verify that the previously nuked collection is present with all the required data.</p>

<p>In my case, I&#8217;m using <a href="https://github.com/thoughtbot/shoulda">shoulda</a> in concert with <a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/test/unit/rdoc/Test/Unit.html">Test::Unit</a>, but the details of a test framework really don&#8217;t matter &#8211; in any case, you&#8217;ll need to load your migration, which can be done via a <code>require</code> statement like so:</p>

<figure class='code'><figcaption><span>Requiring a migration</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="p">,</span> <span class="s1">&#39;db&#39;</span><span class="p">,</span> <span class="s1">&#39;migrate&#39;</span><span class="p">,</span> <span class="s1">&#39;20130217194234_member_app_roles_permissions&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>In my <a href="http://en.wikipedia.org/wiki/Test_fixture">fixture</a> logic, I&#8217;ve initialized a few objects and related them, which automatically creates the aforementioned meta data collection; consequently, I need to do two things. First, get a connection to the underlying test datastore and then drop that collection.</p>

<figure class='code'><figcaption><span>Obtaining a connection and dropping a collection</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">db</span> <span class="o">=</span> <span class="vi">@account</span><span class="o">.</span><span class="n">db</span>
</span><span class='line'><span class="n">db</span><span class="o">[</span><span class="s1">&#39;member_app_roles&#39;</span><span class="o">].</span><span class="n">drop</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now I&#8217;m ready to run my migration &#8211; it&#8217;s as simple as invoking the <a href="http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/">class method</a> <code>up</code>!</p>

<figure class='code'><figcaption><span>Invoking a migration </span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">MemberAppRolesPermissions</span><span class="o">.</span><span class="n">up</span>
</span></code></pre></td></tr></table></div></figure>


<p>Once the migration has finished running, I can then verify that everything is cool and copasetic. In this case, I need to go directly to the datastore because those objects in memory won&#8217;t reflect my changes just yet.</p>

<figure class='code'><figcaption><span>Asserting things worked!</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">member</span> <span class="o">=</span> <span class="no">Member</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">member</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="n">assert_equal</span> <span class="mi">2</span><span class="p">,</span> <span class="n">member</span><span class="o">.</span><span class="n">member_app_roles</span><span class="o">.</span><span class="n">size</span>
</span><span class='line'><span class="n">member</span><span class="o">.</span><span class="n">member_app_roles</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">app_role</span><span class="o">|</span>
</span><span class='line'>  <span class="n">assert_equal</span> <span class="s1">&#39;admin&#39;</span><span class="p">,</span> <span class="n">app_role</span><span class="o">.</span><span class="n">role</span>
</span><span class='line'>  <span class="n">assert_equal</span> <span class="n">member</span><span class="p">,</span> <span class="n">app_role</span><span class="o">.</span><span class="n">member</span>
</span><span class='line'>  <span class="n">assert_not_nil</span> <span class="n">app_role</span><span class="o">.</span><span class="n">app</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>As a benefit of thinking through how to test a migration, you end up unveiling how you&#8217;d construct the migration&#8217;s <code>down</code> method. That is, in my case, to roll back, all I need to do is blow away the <code>member_app_roles</code> collection!</p>

<p>As you can see, testing migrations isn&#8217;t terribly difficult (probably a good reason why I haven&#8217;t found too much information about it); the key aspect is the logic that is applied to verify your migration actually worked. It should be noted that while I executed this test in the context of a document oriented database, you could certainly do the same in a relational database. For example, by dropping  columns, tables, etc before running a migration. Either way, testing a migration is a snap. Can you dig it?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Circumventing mobile UX expectations]]></title>
    <link href="http://aglover.github.com/blog/2013/02/17/circumventing-mobile-ux-expectations/"/>
    <updated>2013-02-17T12:10:00-05:00</updated>
    <id>http://aglover.github.com/blog/2013/02/17/circumventing-mobile-ux-expectations</id>
    <content type="html"><![CDATA[<p>Recently, a <a href="https://twitter.com/trianglechoke">buddy of mine</a> pointed me to an interesting tweet:</p>

<blockquote><p>New tool converts your Apple #iOS apps to #HTML5 http://dld.bz/cejxz  #appdev</p><footer><strong>@effectiveui</strong> <cite><a href='https://twitter.com/effectiveui/status/299626694149537792'>twitter.com/effectiveui/status/&hellip;</a></cite></footer></blockquote>


<p>The article about this new tool, dubbed the &#8221;<a href="http://software.intel.com/en-us/articles/technical-reference-intel-html5-app-porter-tool-beta">Intel HTML5 App Porter Tool</a>&#8221; suggests that because iOS apps are limited to one platform, HTML5:</p>

<blockquote><p>represents an opportunity because it’s supported across a wide range of different devices and operating systems, so it enables the same code base to be reused across different app deployments.</p><footer><strong>Softtalkblog</strong> <cite><a href='http://www.develop-online.net/news/43193/New-tool-converts-your-Apple-apps-to-HTML5'>New Tool Converts Your Apple Apps to HTML5</a></cite></footer></blockquote>


<p><img class="right" src="http://www.carinsurance.com/imagesvr_ce/6464/152631.jpg"> While technically this statement is true &#8211; HTML5 <em>is ubiquitous</em> and you do end up with a single code base &#8211; HTML5 is the lowest common app development denominator and thus produces an underwhelming experience when compared to its native brethren.</p>

<p>Taking a native iOS (or Android) app and recasting it into an HTML5 app is like taking your beautiful Ferrari and trading it for a station wagon. The experience will never be quite the same.</p>

<p>Don&#8217;t get caught up in the HTML5 hype-cycle. It&#8217;s a great platform for mobile web sites, but if you&#8217;re building a mobile app, the UX bar has been set quite high. You cannot yet meet that bar with HTML5.</p>
]]></content>
  </entry>
  
</feed>
