<?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.encosia.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Encosia</title>
	
	<link>http://encosia.com</link>
	<description>ASP.NET and AJAX code, ideas, and examples.</description>
	<lastBuildDate>Thu, 23 May 2013 15:00:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.encosia.com/Encosia" /><feedburner:info uri="encosia" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" /><meta xmlns="http://pipes.yahoo.com" name="pipes" content="noprocess" /><feedburner:emailServiceId>Encosia</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.encosia.com/Encosia" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.encosia.com%2FEncosia" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><item>
		<title>My favorite alternative to JavaScript’s switch statement</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/zvQFOoikl-M/</link>
		<comments>http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/#comments</comments>
		<pubDate>Thu, 23 May 2013 15:00:15 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1375</guid>
		<description><![CDATA[One of my least favorite parts of nearly every programming language I&#8217;ve spent much time with has been the ubiquitous switch statement. Though it does serve a useful purpose in some compiled languages, I think switch is a clunky eyesore in most code. Its structure is prone to taking root and only growing larger and more cumbersome over time. [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/in-javascript-curly-brace-placement-matters-an-example/' rel='bookmark' title='In JavaScript, curly brace placement matters: An example'>In JavaScript, curly brace placement matters: An example</a></li>
<li><a href='http://encosia.com/cheerio-faster-windows-friendly-alternative-jsdom/' rel='bookmark' title='Cheerio: A faster, Windows-friendly alternative to jsdom'>Cheerio: A faster, Windows-friendly alternative to jsdom</a></li>
<li><a href='http://encosia.com/composition-with-jquery-templates-why-and-how/' rel='bookmark' title='Composition with jQuery Templates: Why and How'>Composition with jQuery Templates: Why and How</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>One of my least favorite parts of nearly every programming language I&#8217;ve spent much time with has been the ubiquitous <code>switch</code> statement. Though it does <a href="http://en.wikipedia.org/wiki/Switch_statement#Compilation" target="_blank">serve a useful purpose</a> in some compiled languages, I think switch is a clunky eyesore in most code. Its structure is prone to taking root and only growing larger and more cumbersome over time.</p>
<p>If you&#8217;re coming to JavaScript from a background in procedural languages like C#, Java, or PHP, it&#8217;s natural to reach for the same tools, like switch, that you&#8217;re accustomed to using in those languages. However, <strong>JavaScript&#8217;s flexible object literal syntax and first-class functions offer alternatives to switch that I believe are cleaner, more extensible, and more maintainable</strong>.</p>
<p>So, in this post I want to show you a few ways that you can refactor a JavaScript <code>switch</code> statement to use this alternate technique, and improve its extensibility and maintainability in the process.</p>
<h3>Starting with a switch</h3>
<p>To start with a concrete example, let&#8217;s say we need find the pricing for line items on an invoice and that those line items might be discounted based on the type of customer that&#8217;s being invoiced.</p>
<p>To do that, you might iterate over each line item and multiply the price times quantity and apply the correct discount depending on customer type. The latter bit being something like the following:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> getItemPricing<span style="color: #009900;">&#40;</span>customer<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">switch</span><span style="color: #009900;">&#40;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// VIPs are awesome. Give them 50% off.</span>
    <span style="color: #000066; font-weight: bold;">case</span> <span style="color: #3366CC;">'VIP'</span><span style="color: #339933;">:</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.50</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Preferred customers are no VIPs, but they still get 25% off.</span>
    <span style="color: #000066; font-weight: bold;">case</span> <span style="color: #3366CC;">'Preferred'</span><span style="color: #339933;">:</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.75</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// No discount for other customers.</span>
    <span style="color: #000066; font-weight: bold;">case</span> <span style="color: #3366CC;">'Regular'</span><span style="color: #339933;">:</span>
    <span style="color: #000066; font-weight: bold;">case</span> <span style="color: #003366; font-weight: bold;">default</span><span style="color: #339933;">:</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>That&#8217;s simple enough, but you&#8217;ve probably seen code that started like this and then spiraled out of control over time as more and more complexity was needed. I know I have (and been responsible for that myself a few times too).</p>
<h3>Turn off the switch</h3>
<p>JavaScript&#8217;s flexible object literal syntax makes it easy to replace the switch with something that looks similar, but can be decomposed later. To get started on that, we can define our pricing rules in an object literal like this one:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// This should be namespaced somehow in the real world,</span>
<span style="color: #006600; font-style: italic;">//  not hanging off the global object.</span>
pricing <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// VIPs are awesome. Give them 50% off.</span>
  <span style="color: #3366CC;">'VIP'</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0.50</span><span style="color: #339933;">,</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// Preferred customers are no VIPs, but they still get 25% off.</span>
  <span style="color: #3366CC;">'Preferred'</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0.75</span><span style="color: #339933;">,</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// No discount for other customers.</span>
  <span style="color: #3366CC;">'Regular'</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1.0</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Putting that into action is straightforward enough. We can check that pricing object for a key matching our customer&#8217;s type and then apply that custom pricing if it is available:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> getItemPricing<span style="color: #009900;">&#40;</span>customer<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">else</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> pricing.<span style="color: #660066;">Regular</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now, instead of explicitly stepping through a case statement, we&#8217;ve separated the pricing rules from the actual pricing mechanism.</p>
<h3>Embrace the functional side</h3>
<p>Using the object literal is fine for the simple example of multiplying a few numbers together. What if our pricing rules needed to be more powerful than simple multiplication though? To complicate the example a bit, let&#8217;s say that the discount for &#8220;Preferred&#8221; customers should only apply to items costing up to $100.</p>
<p>One of the beautiful things about a functional language like JavaScript is that you can define and pass functions around just as easily as a basic type like a string or boolean.</p>
<p>We could approach our new object literal &#8220;switch&#8221; a little bit differently to take advantage of that:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> getItemPricing<span style="color: #009900;">&#40;</span>customer<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> pricing <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">'VIP'</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.50</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'Preferred'</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">100.0</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.75</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #006600; font-style: italic;">// Else</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'Regular'</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000066; font-weight: bold;">return</span> pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">else</span>
    <span style="color: #000066; font-weight: bold;">return</span> pricing.<span style="color: #660066;">Regular</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>That&#8217;s a bit more verbose than the original switch, but it&#8217;s worth the extra LoC in the long run. Now we&#8217;ve got all the power of arbitrary code in a switch, but none of the syntactical restrictions keeping us from breaking it into separate pieces.</p>
<p>The functional approach is a departure from the procedural languages you might be used to, and from JavaScript code rooted in those same old practices. It can take a while for the utility and flexibility of first-class functions to really sink in, but it&#8217;s well worth internalizing this approach in your day-to-day JavaScript.</p>
<h3>Modularity === Maintainability</h3>
<p>Now that we&#8217;ve refactored our pricing logic to be decoupled and functional, the <code>getItemPricing</code> method doesn&#8217;t really need to know anything about <em>how</em> the pricing works. The method only needs to understand how to choose which function, if one exists, to apply for a given line item.</p>
<p>In fact, they don&#8217;t even need to be in the same file anymore:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Pricing.VIP.js</span>
pricing <span style="color: #339933;">=</span> pricing <span style="color: #339933;">||</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
pricing.<span style="color: #660066;">VIP</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.50</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Pricing.Preferred.js</span>
pricing <span style="color: #339933;">=</span> pricing <span style="color: #339933;">||</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
pricing.<span style="color: #660066;">Preferred</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">100</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.75</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// Else</span>
  <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Pricing.Regular.js</span>
pricing <span style="color: #339933;">=</span> pricing <span style="color: #339933;">||</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
pricing.<span style="color: #660066;">Regular</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">price</span> <span style="color: #339933;">*</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">quantity</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Pricing.js</span>
<span style="color: #003366; font-weight: bold;">function</span> getItemPricing<span style="color: #009900;">&#40;</span>customer<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000066; font-weight: bold;">return</span> pricing<span style="color: #009900;">&#91;</span>customer.<span style="color: #660066;">type</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">else</span>
    <span style="color: #000066; font-weight: bold;">return</span> pricing.<span style="color: #660066;">Regular</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now, adding a new pricing type to our program is as easy as dropping new file in a directory and referencing it in your program (e.g. a script reference for website code). As long as it augments the Pricing object with a key/function pair that matches the new customer type, everything &#8220;just works&#8221;.</p>
<p>If you use something like <a href="http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification" target="_blank">ASP.NET&#8217;s Web Optimization framework </a>or Rails&#8217; Asset Pipeline, you can configure server-side bundling to automate that work. Then, simply dropping a new pricing logic file into the right directory will affect pricing without any extra configuration or script reference.</p>
<h3>Conclusion</h3>
<p>To me, one of the nicest things about this approach is the flexibility and modularity. You can drop a discrete bit of logic in a file in the right directory and change the behavior of your program without touching the program&#8217;s core logic.</p>
<p>In this example, adding, modifying, or removing a custom pricing type doesn&#8217;t require touching pricing.js. That means we avoid even the potential for a range of regression errors that centralized logic constructs, like switch statements, are prone to.</p>
<p>Ultimately, my experience has been that this technique finds an ideal middle ground between inflexible switch/if-then cruft and <a href="http://thedailywtf.com/Articles/The_Enterprise_Rules_Engine.aspx" target="_blank">over-complicated &#8220;rules engines&#8221;</a>. I hope you find it as useful as I have.</p>
<p>My question to you is: Did you find this useful? Are you going to replace your switch statements with the functional approach going forward? Were you already doing this?</p>
<hr />

<p>You've been reading <a href="http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/">My favorite alternative to JavaScript&#8217;s switch statement</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/in-javascript-curly-brace-placement-matters-an-example/' rel='bookmark' title='In JavaScript, curly brace placement matters: An example'>In JavaScript, curly brace placement matters: An example</a></li>
<li><a href='http://encosia.com/cheerio-faster-windows-friendly-alternative-jsdom/' rel='bookmark' title='Cheerio: A faster, Windows-friendly alternative to jsdom'>Cheerio: A faster, Windows-friendly alternative to jsdom</a></li>
<li><a href='http://encosia.com/composition-with-jquery-templates-why-and-how/' rel='bookmark' title='Composition with jQuery Templates: Why and How'>Composition with jQuery Templates: Why and How</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=zvQFOoikl-M:-rds6t7n4cg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=zvQFOoikl-M:-rds6t7n4cg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=zvQFOoikl-M:-rds6t7n4cg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=zvQFOoikl-M:-rds6t7n4cg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/zvQFOoikl-M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/</feedburner:origLink></item>
		<item>
		<title>Using jQuery to POST [FromBody] parameters to Web API</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/IwFKltmGGTE/</link>
		<comments>http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/#comments</comments>
		<pubDate>Wed, 03 Apr 2013 15:24:24 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Web API]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1480</guid>
		<description><![CDATA[ASP.NET Web API has been one of my favorite recent additions to ASP.NET. Whether you prefer a RESTful approach or something more RPC-oriented, Web API will do just about anything you need. Even if you&#8217;re still using ASP.NET WebForms, Web API still has you covered &#8211; a nice example of the &#8220;One ASP.NET&#8221; philosophy that&#8217;s finally [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/' rel='bookmark' title='3 mistakes to avoid when using jQuery with ASP.NET AJAX'>3 mistakes to avoid when using jQuery with ASP.NET AJAX</a></li>
<li><a href='http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/' rel='bookmark' title='Using jQuery to directly call ASP.NET AJAX page methods'>Using jQuery to directly call ASP.NET AJAX page methods</a></li>
<li><a href='http://encosia.com/using-complex-types-to-make-calling-services-less-complex/' rel='bookmark' title='Using complex types to make calling services less&#8230; complex'>Using complex types to make calling services less&#8230; complex</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p><img class="size-full" alt="square-peg-round-hole" src="http://encosia.com/blog/wp-content/uploads/2013/03/square-peg-round-hole.jpg" width="490" height="205" />ASP.NET Web API has been one of my favorite recent additions to ASP.NET. Whether you prefer a RESTful approach or something more RPC-oriented, <a href="http://encosia.com/rest-vs-rpc-in-asp-net-web-api-who-cares-it-does-both/" target="_blank">Web API will do just about anything you need</a>. Even if you&#8217;re still using ASP.NET WebForms, <a href="http://blogs.msdn.com/b/henrikn/archive/2012/02/23/using-asp-net-web-api-with-asp-net-web-forms.aspx" target="_blank">Web API still has you covered</a> &#8211; a nice example of the &#8220;One ASP.NET&#8221; philosophy that&#8217;s finally beginning to come together.</p>
<p>However, ASP.NET Web API throws an unintuitive curveball at you when you want to accept simple primitive types as parameters to POST methods. Figuring this issue out is particularly confusing because it&#8217;s one of the rare parts of Web API that violates <a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment" target="_blank">the principle of least astonishment</a>.</p>
<p>Because of that, using jQuery to interact with those methods requires a slight contortion that seems strange at first, but makes sense once you understand why it&#8217;s necessary. In this post, I&#8217;ll briefly describe the underlying issue and show you how jQuery can be convinced to work around the issue.</p>
<h3>POSTing primitive parameters to Web API</h3>
<p>There are three things you need to know about Web API if you want to go the route of POSTing a primitive type (e.g. string, int, or bool) to a method. For example, say you&#8217;re working with this straightforward POST method in a Web API controller named <code>ValuesController</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// POST api/values</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> Post<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> value<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">return</span> value<span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>You might try POSTing a value into that Web API method using a standard jQuery <code>$.post</code>, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/api/values'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> value<span style="color: #339933;">:</span> <span style="color: #3366CC;">'Dave'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>If you inspect the server&#8217;s response to that request, you&#8217;ll be greeted with a bewildering 404 error:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2013/03/web-api-post-request-without-FromBody.png" rel="attachment"><img class="size-full" alt="web-api-post-request-without-[FromBody]-sm" src="http://encosia.com/blog/wp-content/uploads/2013/03/web-api-post-request-without-FromBody-sm.png" width="490" height="69" /></a></p>
<p>Confronted with that response, it&#8217;s only natural to treat the problem as an issue with your routing configuration and debug from there, but that&#8217;s not the issue.</p>
<h4>1. Parameters must be marked as [FromBody]</h4>
<p>As it turns out, the reason for that 404 error isn&#8217;t a routing problem. ASP.NET correctly identifies our <code>ValuesController</code> as the controller to handle a POST to <code>/api/values</code>, but it can&#8217;t locate an acceptable method to process the request.</p>
<p>The reason for that is a twofold mismatch between the required parameter that Web API expects to accompany requests to our <code>Post</code> method and what we sent. The first of those mismatches is that the method&#8217;s parameter must be decorated with the <code>[FromBody]</code> attribute.</p>
<p><code>[FromBody]</code> directs Web API to search for the parameter&#8217;s value in the body of a POST request. Adding that directive to our method is easy enough:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// POST api/values</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> Post<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span>FromBody<span style="color: #000000;">&#93;</span><span style="color: #FF0000;">string</span> value<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">return</span> value<span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>I can&#8217;t say that I understand why this extra hassle is necessary, <em>especially since it wasn&#8217;t required in WCF Web API and preliminary versions of ASP.NET Web API</em>, but it&#8217;s easy enough as long as you&#8217;re aware that it needs to be present.</p>
<p>Adding <code>[FromBody]</code> fixes our 404 error, but things unfortunately still aren&#8217;t working quite right. Making the same request to it again works, but the <code>value</code> parameter is coming back as <code>null</code> now instead of the provided value:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2013/03/web-api-post-request-with-FromBody.png" rel="attachment"><img class="size-full" alt="web-api-post-request-with-FromBody-sm" src="http://encosia.com/blog/wp-content/uploads/2013/03/web-api-post-request-with-FromBody-sm.png" width="490" height="69" /></a></p>
<h4>2. Only one parameter per method</h4>
<p>Speaking of the parameters to our method, another potentially confusing thing about accepting <code>[FromBody]</code> parameters is that <strong>there can be only one</strong>.</p>
<p>Attempting to accept multiple parameters from the POST body will result in a (refreshingly decipherable) server-side error along these lines:</p>
<blockquote><p>Can&#8217;t bind multiple parameters (&#8216;foo&#8217; and &#8216;bar&#8217;) to the request&#8217;s content.</p></blockquote>
<p>It&#8217;s possible to circumvent this limitation by using manual parsing techniques, but that seems antithetical to Web API and model binding to me. If you want Web API to automatically convert POST data to your <code>[FromBody]</code> input parameter, you have to limit yourself to only a single parameter.</p>
<p>I believe the thinking here is that, especially in a RESTful API, you&#8217;ll want to bind data to the single <em>resource</em> that a particular method deals with. So, pushing data into several loose parameters isn&#8217;t the sort of usage that Web API caters to.</p>
<p>This limitation can be a bit confusing when you&#8217;re coming from WebForms or MVC though, and trying work around it feels like going against the grain of the framework. So, if I need to accept more than one POST parameter, I just define a quick view model.</p>
<p>In other words, don&#8217;t try to do this:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> Post<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span>FromBody<span style="color: #000000;">&#93;</span><span style="color: #FF0000;">string</span> FirstName,
                   <span style="color: #000000;">&#91;</span>FromBody<span style="color: #000000;">&#93;</span><span style="color: #FF0000;">string</span> LastName<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">return</span> FirstName <span style="color: #008000;">+</span> <span style="color: #666666;">&quot; &quot;</span> <span style="color: #008000;">+</span> LastName<span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>Instead, work <em>with</em> the framework and do something like this if you need to accept more than a single parameter:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// DTO or ViewModel? Potato or potato, IMO.</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> PersonDTO <span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> FirstName <span style="color: #000000;">&#123;</span> get<span style="color: #008000;">;</span> set<span style="color: #008000;">;</span> <span style="color: #000000;">&#125;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> LastName <span style="color: #000000;">&#123;</span> get<span style="color: #008000;">;</span> set<span style="color: #008000;">;</span> <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> Post<span style="color: #000000;">&#40;</span>PersonDTO Person<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">return</span> Person.<span style="color: #0000FF;">FirstName</span> <span style="color: #008000;">+</span> <span style="color: #666666;">&quot; &quot;</span> <span style="color: #008000;">+</span> Person.<span style="color: #0000FF;">LastName</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<h4>3. [FromBody] parameters must be encoded as =value</h4>
<p>The final hurdle remaining is that Web API requires you to pass <code>[FromBody]</code> parameters in a particular format. That&#8217;s the reason why our value parameter was null in the previous example even after we decorated the method&#8217;s parameter with <code>[FromBody]</code>.</p>
<p>Instead of the fairly standard <code>key=value</code> encoding that most client- and server-side frameworks expect, Web API&#8217;s model binder expects to find the <code>[FromBody]</code> values in the POST body without a key name at all. In other words, instead of <code>key=value</code>, it&#8217;s looking for <code>=value</code>.</p>
<p>This part is, by far, the most confusing part of sending primitive types into a Web API POST method. Not too bad once you understand it, but terribly unintuitive and not discoverable.</p>
<h3>What not to do</h3>
<p>Now that we&#8217;ve covered what you need to know about the server-side code, let&#8217;s talk about using jQuery to POST data to <code>[FromBody]</code> parameters. Again, here&#8217;s the Web API method that we&#8217;re trying to POST data into:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// POST api/values</span>
<span style="color: #003366; font-weight: bold;">public</span> string Post<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span>FromBody<span style="color: #009900;">&#93;</span>string value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">return</span> value<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>You&#8217;ll have a hard time finding a  jQuery <code>$.post</code> (or <code>$.ajax</code>) example that conforms to the <code>=value</code> encoding approach. Typically, platform-agnostic jQuery documentation and tutorials suggest that one of these two approaches should work:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Value will be null.</span>
$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'api/values'</span><span style="color: #339933;">,</span> value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Value will be null.</span>
$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'api/values'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> key<span style="color: #339933;">:</span> value <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Unfortunately, neither of those work with Web API in the case of <code>[FromBody]</code> parameters (the latter would work to send an object, rather than a single primitive value). In both cases, our method will be invoked, but the model binder won&#8217;t assign anything to <code>value</code> and it will be <code>null</code>.</p>
<h3>Making it work</h3>
<p>There are two ways to make jQuery satisfy Web API&#8217;s encoding requirement. First, you can hard code the <code>=</code> in front of your value, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'api/values'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;=&quot;</span> <span style="color: #339933;">+</span> value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Personally, I&#8217;m not a fan of that approach. Aside from just plain looking kludgy, playing fast and loose with JavaScript&#8217;s type coercsion is a good way to find yourself debugging <a href="https://www.destroyallsoftware.com/talks/wat" target="_blank">a &#8220;wat&#8221; situation</a>.</p>
<p>Instead, you can take advantage of how jQuery encodes object parameters to <code>$.ajax</code>, by using this syntax:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'api/values'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">''</span><span style="color: #339933;">:</span> value <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>If the data parameter has properties with empty string keys, jQuery serializes those properties in the form of <code>=value</code>. And, that&#8217;s exactly what we need to make Web API happy:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2013/04/post-request-to-web-api-with-empty-key-sm.png" rel="attachment"><img class="alignnone size-full wp-image-1494" alt="post-request-to-web-api-with-empty-key-sm" src="http://encosia.com/blog/wp-content/uploads/2013/04/post-request-to-web-api-with-empty-key-sm.png" width="491" height="70" /></a></p>
<hr />

<p>You've been reading <a href="http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/">Using jQuery to POST [FromBody] parameters to Web API</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/' rel='bookmark' title='3 mistakes to avoid when using jQuery with ASP.NET AJAX'>3 mistakes to avoid when using jQuery with ASP.NET AJAX</a></li>
<li><a href='http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/' rel='bookmark' title='Using jQuery to directly call ASP.NET AJAX page methods'>Using jQuery to directly call ASP.NET AJAX page methods</a></li>
<li><a href='http://encosia.com/using-complex-types-to-make-calling-services-less-complex/' rel='bookmark' title='Using complex types to make calling services less&#8230; complex'>Using complex types to make calling services less&#8230; complex</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=IwFKltmGGTE:rJU99WiO_18:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=IwFKltmGGTE:rJU99WiO_18:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=IwFKltmGGTE:rJU99WiO_18:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=IwFKltmGGTE:rJU99WiO_18:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/IwFKltmGGTE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		<feedburner:origLink>http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/</feedburner:origLink></item>
		<item>
		<title>I wish Twitter’s direct messages were less restrictive</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/dla656HamlA/</link>
		<comments>http://encosia.com/twitter-direct-messages-are-brokenly-restrictive/#comments</comments>
		<pubDate>Thu, 07 Mar 2013 16:35:29 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1476</guid>
		<description><![CDATA[One of the best things about Twitter is that relationships there can be asymmetrical. Even if I don&#8217;t know you or follow your updates, you can still follow mine if you&#8217;re interested. Over time, we might talk in @mentions from time to time and I might realize that you&#8217;re someone whose updates I&#8217;m interested in all the time. In fact, [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/4-years-of-encosia-and-the-best-of-2010/' rel='bookmark' title='4 years of Encosia, and the best of 2010'>4 years of Encosia, and the best of 2010</a></li>
<li><a href='http://encosia.com/im-giving-away-10-free-months-of-tekpub-this-week/' rel='bookmark' title='I&#8217;m giving away 10 free months of TekPub this week'>I&#8217;m giving away 10 free months of TekPub this week</a></li>
<li><a href='http://encosia.com/3-years-of-encosia-the-best-of-2009-and-my-gratitude/' rel='bookmark' title='3 years of Encosia, the best of 2009, and my gratitude'>3 years of Encosia, the best of 2009, and my gratitude</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>One of the best things about Twitter is that relationships there can be asymmetrical. Even if I don&#8217;t know you or follow your updates, you can still follow mine if you&#8217;re interested. Over time, we might talk in @mentions from time to time and I might realize that you&#8217;re someone whose updates I&#8217;m interested in all the time. In fact, that&#8217;s exactly how I end up following most of the people on Twitter that I&#8217;ve never met before.</p>
<p>It&#8217;s not that I don&#8217;t want to hear what everyone has to say, but automatically following thousands of people back would make my timeline impossible to keep up with (and even more productivity-cripplingly distracting than it already is).</p>
<p>One thing about these loose, asymmetric relationships constantly frustrates me though. The requirement that I must follow you in order for you to direct message me, <em>even after I&#8217;ve direct messaged you</em>, is too restrictive. Pointlessly restrictive.</p>
<p>It often makes sense to take a Twitter discussion private, but we can only use Twitter to do that if we have a symmetric relationship with each other. Sure, I can follow you temporarily or message you my email address for follow up, but why? It should be easy for Twitter to allow anyone to reply to any direct message for some period of time, or even forever.</p>
<p>Wouldn&#8217;t that make the direct message feature a lot more useful?</p>
<hr />

<p>You've been reading <a href="http://encosia.com/twitter-direct-messages-are-brokenly-restrictive/">I wish Twitter&#8217;s direct messages were less restrictive</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/twitter-direct-messages-are-brokenly-restrictive/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/4-years-of-encosia-and-the-best-of-2010/' rel='bookmark' title='4 years of Encosia, and the best of 2010'>4 years of Encosia, and the best of 2010</a></li>
<li><a href='http://encosia.com/im-giving-away-10-free-months-of-tekpub-this-week/' rel='bookmark' title='I&#8217;m giving away 10 free months of TekPub this week'>I&#8217;m giving away 10 free months of TekPub this week</a></li>
<li><a href='http://encosia.com/3-years-of-encosia-the-best-of-2009-and-my-gratitude/' rel='bookmark' title='3 years of Encosia, the best of 2009, and my gratitude'>3 years of Encosia, the best of 2009, and my gratitude</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=dla656HamlA:mXfV5N9dze8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=dla656HamlA:mXfV5N9dze8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=dla656HamlA:mXfV5N9dze8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=dla656HamlA:mXfV5N9dze8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/dla656HamlA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/twitter-direct-messages-are-brokenly-restrictive/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://encosia.com/twitter-direct-messages-are-brokenly-restrictive/</feedburner:origLink></item>
		<item>
		<title>Using nConf and Azure to avoid leaking secrets on GitHub</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/98JiZVZ67bQ/</link>
		<comments>http://encosia.com/using-nconf-and-azure-to-avoid-leaking-secrets-on-github/#comments</comments>
		<pubDate>Tue, 26 Feb 2013 18:39:16 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1468</guid>
		<description><![CDATA[GitHub recently released a new version of its search feature. Unfortunately, it quickly became obvious that the feature could be misused to locate data that wasn&#8217;t intended to be exposed publicly. Passwords, oAuth tokens, and private API keys are particularly common in source code, and well-crafted searches to find them were making the social media rounds [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/' rel='bookmark' title='3 mistakes to avoid when using jQuery with ASP.NET AJAX'>3 mistakes to avoid when using jQuery with ASP.NET AJAX</a></li>
<li><a href='http://encosia.com/avoid-this-tricky-conflict-between-aspnet-ajax-and-jquery/' rel='bookmark' title='Avoid this tricky conflict between ASP.NET AJAX and jQuery'>Avoid this tricky conflict between ASP.NET AJAX and jQuery</a></li>
<li><a href='http://encosia.com/resolving-an-iisnode-the-service-is-unavailable-503-error/' rel='bookmark' title='Resolving an iisnode &#8220;The service is unavailable&#8221; 503 error'>Resolving an iisnode &#8220;The service is unavailable&#8221; 503 error</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>GitHub recently released a <a href="https://github.com/blog/1381-a-whole-new-code-search" target="_blank">new version of its search feature</a>. Unfortunately, it quickly became obvious that <a href="https://github.com/blog/1390-secrets-in-the-code" target="_blank">the feature could be misused to locate data that wasn&#8217;t intended to be exposed publicly</a>. Passwords, oAuth tokens, and private API keys are particularly common in source code, and well-crafted searches to find them were making the social media rounds almost immediately after the new feature was released.</p>
<p>Of course, this sort of thing is nothing new. <a href="http://www.kottke.org/06/10/google-code-search" target="_blank">Similar Google searches</a> have been possible for years. However, GitHub currently seems to house a concentration of particularly sensitive secrets. Maybe that&#8217;s because it&#8217;s so easy to accidentally commit these things along with associated code with a quick <code>git commit -a</code>.</p>
<p>I&#8217;ve been working on a few <a href="http://www.windowsazure.com/en-us/develop/nodejs/" target="_blank">Node.js projects hosted on Windows Azure</a> lately, and one in particular is stored in a public GitHub repository but needs access to private oAuth keys. So, this topic is something I&#8217;ve been dealing with myself lately. Through that project, I&#8217;ve been fortunate enough to stumble onto a nice symbiosis between Azure and a Node.js module called nConf that solves the problem of storing secrets in my public repositories.</p>
<h3>Adding nConf to your Node.js app</h3>
<p><a href="https://github.com/flatiron/nconf" target="_blank">nConf</a> is a simple, but handy, module by <a href="https://twitter.com/indexzero" target="_blank">Charlie Robbins</a>. As with any other npm module, adding nConf to your app is easy. A quick <code>npm install nconf</code> from your project&#8217;s root directory will do it:</p>
<p><img class="alignnone size-full wp-image-1471" alt="installing-nconf-with-npm" src="http://encosia.com/blog/wp-content/uploads/2013/02/installing-nconf-with-npm.png" width="490" height="368" /></p>
<p>You&#8217;ll see npm downloading nConf and its dependencies, and then you&#8217;ll be ready to start using the module in your code right away.</p>
<p>I can&#8217;t say enough good things about how well the folks at Joyent and Microsoft have made this work on Windows. I have a MacBook and I host this site on an Ubuntu VPS, but I still do the overwhelming majority of my serious development work on a Windows 8 desktop. In the early days, working with Node.js on my Windows desktop was tedious and painful, but things have changed significantly for the better during 2012. <strong>Kudos to everyone involved in making that happen</strong>.</p>
<h3>Using nConf to read settings from a config file</h3>
<p>With nConf installed, exposing configurable settings for your app is simple. For example, let&#8217;s say we want our app to have a configurable username and password. You might create a file called <code>settings.json</code> like this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
  <span style="color: #3366CC;">&quot;username&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;dave@encosia.com&quot;</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;password&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;password123&quot;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Then, you could pull those settings into your application with code like this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> nconf <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'nconf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
nconf.<span style="color: #660066;">file</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'settings.json'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> username <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'username'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    password <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Output: dave@encosia, your password is password123</span>
console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>username<span style="color: #339933;">,</span> <span style="color: #3366CC;">', your password is:'</span><span style="color: #339933;">,</span> password<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>That&#8217;s a handy way to read in settings from a config file, but this approach alone brings us right back the point where <code>settings.json</code> might accidentally get committed to a public repository.</p>
<h3>Reading environment variables instead of a config file</h3>
<p>Along with pulling settings out of a JSON file, nConf also supports reading arguments from environment variables. That&#8217;s particularly useful if your app is hosted on a <a href="http://www.windowsazure.com/en-us/develop/nodejs/" target="_blank">PaaS like Azure</a> that allows you to configure those environment variables through an interface that&#8217;s independent of your code.</p>
<p>For example, providing a username and password setting in this section of Azure&#8217;s &#8220;Configure&#8221; tab makes those settings available to Node as environment variables:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2013/02/changing-app-settings-in-the-azure-portal.png" rel="attachment"><img class="alignnone size-full wp-image-1470" alt="changing-app-settings-in-the-azure-portal-sm" src="http://encosia.com/blog/wp-content/uploads/2013/02/changing-app-settings-in-the-azure-portal-sm.png" width="490" height="114" /></a></p>
<p>That&#8217;s great because nConf can read configuration from environment variables just as easily as a JSON file. All you need to do is a call <code>nconf.env()</code> instead of <code>nconf.file()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> nconf <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'nconf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
nconf.<span style="color: #660066;">env</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> username <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'username'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    password <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Output: dave@encosia, your password is hunter2</span>
console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>username<span style="color: #339933;">,</span> <span style="color: #3366CC;">', your password is:'</span><span style="color: #339933;">,</span> password<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>By itself, that&#8217;s not particularly impressive. You could also read those environment variables via <code>process.env.username</code> and <code>process.env.password</code>, without any extra modules.</p>
<p>However, the beauty of nConf is that you can combine both approaches.</p>
<h3>The best of both worlds</h3>
<p>Using environment variables works pretty well once the code is deployed to Azure, but I think the simple config file is a lot more convenient when I&#8217;m developing locally. The best thing about nConf is that it supports reading settings from <em>both</em> locations, in the priority that you specify.</p>
<p>So, you can use a settings file locally, but supersede that with environment variables if they&#8217;re present (i.e. once deployed to Azure). To do that, you can chain nConf initialization calls to both <code>.file()</code> and <code>.env()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> nconf <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'nconf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
nconf.<span style="color: #660066;">file</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'settings.json'</span><span style="color: #009900;">&#41;</span>
     .<span style="color: #660066;">env</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> username <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'username'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    password <span style="color: #339933;">=</span> nconf.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>username<span style="color: #339933;">,</span> <span style="color: #3366CC;">', your password is:'</span><span style="color: #339933;">,</span> password<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Now, running this locally with the <code>settings.json</code> file from earlier will output &#8220;password123&#8243;, but deploying it to the Azure site with the app settings shown above will change the output to&#8230; a 500 error, of course.</p>
<p>This simple example code doesn&#8217;t handle HTTP requests, nor does it output HTTP responses, so running it on Azure doesn&#8217;t work. But, the password variable will be correctly initialized to &#8220;hunter2&#8243; instead of &#8220;password123&#8243; when running on Azure with the environment variables we set in the previous section.</p>
<p>Now, add <code>settings.json</code> to your <code>.gitignore</code> and you&#8217;ll never need to worry about pushing your local, potentially-sensitive, credentials to a public repository.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/using-nconf-and-azure-to-avoid-leaking-secrets-on-github/">Using nConf and Azure to avoid leaking secrets on GitHub</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/using-nconf-and-azure-to-avoid-leaking-secrets-on-github/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/' rel='bookmark' title='3 mistakes to avoid when using jQuery with ASP.NET AJAX'>3 mistakes to avoid when using jQuery with ASP.NET AJAX</a></li>
<li><a href='http://encosia.com/avoid-this-tricky-conflict-between-aspnet-ajax-and-jquery/' rel='bookmark' title='Avoid this tricky conflict between ASP.NET AJAX and jQuery'>Avoid this tricky conflict between ASP.NET AJAX and jQuery</a></li>
<li><a href='http://encosia.com/resolving-an-iisnode-the-service-is-unavailable-503-error/' rel='bookmark' title='Resolving an iisnode &#8220;The service is unavailable&#8221; 503 error'>Resolving an iisnode &#8220;The service is unavailable&#8221; 503 error</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=98JiZVZ67bQ:m1TzSfigcBg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=98JiZVZ67bQ:m1TzSfigcBg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=98JiZVZ67bQ:m1TzSfigcBg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=98JiZVZ67bQ:m1TzSfigcBg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/98JiZVZ67bQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/using-nconf-and-azure-to-avoid-leaking-secrets-on-github/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://encosia.com/using-nconf-and-azure-to-avoid-leaking-secrets-on-github/</feedburner:origLink></item>
		<item>
		<title>Six years of Encosia</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/frME0v2eOuc/</link>
		<comments>http://encosia.com/six-years-of-encosia/#comments</comments>
		<pubDate>Mon, 31 Dec 2012 23:33:36 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1455</guid>
		<description><![CDATA[Each year, I get a little closer to not making this post before the year is over, much less on the actual anniversary of when I started posting (12/21). That&#8217;s mainly because it seems more like a &#8220;me&#8221; post instead of something that you might actually find interesting or useful and that&#8217;s not really what [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/4-years-of-encosia-and-the-best-of-2010/' rel='bookmark' title='4 years of Encosia, and the best of 2010'>4 years of Encosia, and the best of 2010</a></li>
<li><a href='http://encosia.com/3-years-of-encosia-the-best-of-2009-and-my-gratitude/' rel='bookmark' title='3 years of Encosia, the best of 2009, and my gratitude'>3 years of Encosia, the best of 2009, and my gratitude</a></li>
<li><a href='http://encosia.com/five-years-of-encosia/' rel='bookmark' title='Five years of Encosia'>Five years of Encosia</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-1459" style="margin-top: 5px; margin-bottom: 20px;" alt="six-candles" src="http://encosia.com/blog/wp-content/uploads/2012/12/six-candles.jpg" width="234" height="216" />Each year, I get a little closer to not making this post before the year is over, much less on the actual anniversary of when I started posting (12/21). That&#8217;s mainly because it seems more like a &#8220;me&#8221; post instead of something that you might actually find interesting or useful and that&#8217;s not really what this site is supposed to be about. However, every time I mention skipping it, the feedback is in favor of making the post. So, here it is (and I&#8217;ll try to do better next year).</p>
<h3>Site stats</h3>
<p>When I loaded up Google Analytics to check my stats for the past year, I was half expecting the numbers to be lower than last year&#8217;s. I haven&#8217;t posted very much this year and haven&#8217;t bothered to link-bait my way onto the front page of Hacker News or reddit either.</p>
<p>As it turns out, the site did manage to eek out a small increase in traffic over last year anyway. There&#8217;s always inflation, I suppose:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/12/encosia-traffic-2012.jpg" rel="attachment"><img class="alignnone size-full wp-image-1457" alt="encosia-traffic-2012-sm" src="http://encosia.com/blog/wp-content/uploads/2012/12/encosia-traffic-2012-sm.jpg" width="492" height="359" /></a></p>
<p>&nbsp;</p>
<p>Since last year&#8217;s post, that&#8217;s about an 8% increase in page views, which isn&#8217;t terrible. It&#8217;s a good thing I managed to finish <a href="http://encosia.com/a-month-with-my-surface-rt/" target="_blank">that Surface RT review</a>, which accounted for the second spike on the chart.</p>
<p>It may seem weird to spend time worrying about things like page views and <a href="http://encosia.com/how-30-seconds-dropped-my-bounce-rate-by-78/" target="_blank">bounce rates</a> on a non-commercial site like this one. These metrics are one of the few things I can measure consistently across the years though. It&#8217;s important (for me, at least) to have metrics that I can use to set goals against and then get relevant feedback to motivate myself.</p>
<p>So, I measure and watch these things, for better or worse.</p>
<h3>2012: Better than the Mayans predicted</h3>
<p>Aside from my poor posting frequency, 2012 turned out to be a good year. I started the year off by becoming a Microsoft Regional Director (though it&#8217;s neither regional, nor do I direct anyone) in January and then receiving an MVP of the Year award in February. Not a terrible way to get the year rolling.</p>
<p>Throughout the rest of the year, I continued to enjoy working with my excellent existing clients on interesting projects and began working with a few exciting new ones too. I truly do count myself fortunate to be able to earn a living learning and working with cutting edge technologies like Node.js, PhoneGap, C# 4.5, and ASP.NET MVC 4.</p>
<p>I also finally began recording new episodes with Rob at TekPub, starting with a new series called <a href="http://tekpub.com/shows/jquery_garage" target="_blank">jQuery Garage</a>. Though it&#8217;s getting a bit long in the tooth now, I was happy with how <a href="http://tekpub.com/productions/jquery" target="_blank">Mastering jQuery</a> turned out. So, I&#8217;m very much looking forward to seeing what we&#8217;re able to accomplish in this new series.</p>
<h3>2013: Let&#8217;s make it great</h3>
<p>Since the Mayans were wrong (I know, I know), it looks like we get to take a shot at 2013 after all. Ignoring the political turmoil here in the US and the potential that poorly performing IPOs like Groupon, Zynga, and Facebook might threaten the software investment bubble we seem to be in, I&#8217;m still optimistic about 2013.</p>
<p>Between Node.js continuing to make inroads on the server-side, the ongoing proliferation of smartphones and the mobile web, and some early signs that Windows 8 is succeeding, there&#8217;s never been a better time to be an HTML, CSS, and JavaScript developer. I would have used the term &#8220;web&#8221; developer to reference that trifecta in past years, but that&#8217;s no longer the case.</p>
<p>If you&#8217;re reading this, you&#8217;re probably somehow involved with that mix of technologies. If so, you&#8217;re poised to be right at the forefront of some our field&#8217;s most exciting upcoming developments. I hope you&#8217;ll join me in taking advantage of that in 2013.</p>
<h3>Thanks</h3>
<p>Thanks for joining me here in 2012. I hope you&#8217;ll stick around for the upcoming year, because none of the work I put into the site would be worthwhile without you.</p>
<p>Most important of all: I hope you have a safe, happy, and prosperous 2013.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/six-years-of-encosia/">Six years of Encosia</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/six-years-of-encosia/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/4-years-of-encosia-and-the-best-of-2010/' rel='bookmark' title='4 years of Encosia, and the best of 2010'>4 years of Encosia, and the best of 2010</a></li>
<li><a href='http://encosia.com/3-years-of-encosia-the-best-of-2009-and-my-gratitude/' rel='bookmark' title='3 years of Encosia, the best of 2009, and my gratitude'>3 years of Encosia, the best of 2009, and my gratitude</a></li>
<li><a href='http://encosia.com/five-years-of-encosia/' rel='bookmark' title='Five years of Encosia'>Five years of Encosia</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=frME0v2eOuc:ZLwupxSOHE0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=frME0v2eOuc:ZLwupxSOHE0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=frME0v2eOuc:ZLwupxSOHE0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=frME0v2eOuc:ZLwupxSOHE0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/frME0v2eOuc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/six-years-of-encosia/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://encosia.com/six-years-of-encosia/</feedburner:origLink></item>
		<item>
		<title>A month with my Surface RT</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/i35dj8yipbw/</link>
		<comments>http://encosia.com/a-month-with-my-surface-rt/#comments</comments>
		<pubDate>Mon, 26 Nov 2012 18:08:53 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Surface RT]]></category>
		<category><![CDATA[Windows 8]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1424</guid>
		<description><![CDATA[If you follow me on Twitter, you probably know that I&#8217;ve been playing with a shiny new Microsoft Surface RT that I&#8217;ve had for about a month now. I&#8217;ve had a bunch of requests for a post about my experience with it thus far, so here we go&#8230; Since I had a few weeks to write it, [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/' rel='bookmark' title='Closing Windows 8 apps with Surface RT&#8217;s Touch Cover'>Closing Windows 8 apps with Surface RT&#8217;s Touch Cover</a></li>
<li><a href='http://encosia.com/a-month-with-my-zenbook-ux31/' rel='bookmark' title='A month with my Zenbook UX31'>A month with my Zenbook UX31</a></li>
<li><a href='http://encosia.com/interesting-details-on-ie10s-javascript-performance-tweaks/' rel='bookmark' title='Interesting details on IE10&#8242;s JavaScript performance tweaks'>Interesting details on IE10&#8242;s JavaScript performance tweaks</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p style="text-align: left;">If you <a href="http://twitter.com/Encosia" target="_blank">follow me on Twitter</a>, you probably know that I&#8217;ve been playing with a shiny new <a href="http://www.microsoft.com/surface/en-US/surface-with-windows-rt/home" target="_blank">Microsoft Surface RT</a> that I&#8217;ve had for about a month now. I&#8217;ve had a bunch of requests for a post about my experience with it thus far, so here we go&#8230;</p>
<p style="text-align: left;">Since I had a few weeks to write it, this post grew a little bit out of control. Sorry in advance for the wall of text. To hopefully compensate a bit, here&#8217;s an index of the major sections:</p>
<ul>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Windows-8">Windows 8 RT</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Hardware">Hardware</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Touch-and-Type-Covers">Touch and Type Covers</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#ClearType-Display">ClearType Display</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Apps">Apps</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Performance">Performance</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Battery-Life">Battery Life</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#WiFi">WiFi</a></li>
<li><a href="http://encosia.com/a-month-with-my-surface-rt/#Conclusion">Conclusion</a></li>
</ul>
<p>In an unsurprising twist ending, I wrote the first few drafts of this entire post on my Surface RT. I used the Touch Cover for most of it, and then picked up a Type Cover toward the end and used that for the rest.</p>
<p>I tried to write a post like this soon after receiving my original iPad, but was not successful due to a combination of the pain that comes along with long-form writing on a screen-board and the tedious multi-app workflow in iOS &#8212; <a href="http://daringfireball.net/2010/04/the_ipad" target="_blank">it&#8217;s definitely possible</a>, but it&#8217;s a task that requires more determination than I could muster at the time.</p>
<p>By contrast, Windows 8 and the physical keyboard made writing this on the Surface RT nearly indistinguishable from writing on my 13&#8243; laptop. If you want a tl;dr for the next 6,500 words, I think that sums it up pretty well.</p>
<h3 id="Windows-8" style="text-align: left;">Windows 8 RT</h3>
<p><img class="size-full wp-image-1440 alignnone" title="my-windows-8" src="http://encosia.com/blog/wp-content/uploads/2012/11/my-windows-8.png" alt="" width="490" height="275" /></p>
<p style="text-align: left;">At its heart, I think the Surface RT is at least as much about showcasing Windows 8 on quasi-reference hardware as it is about that hardware itself.</p>
<p style="text-align: left;">Having used iOS and Android tablets almost daily for a couple years, <strong>Windows 8 is the best tablet operating system I&#8217;ve used yet</strong>. There&#8217;s really no comparison. Once you learn the new gestures well enough to use them effortlessly, Windows 8 makes those older operating systems feel as dated as they look.</p>
<p style="text-align: left;">Even the simplest things &#8212; like accessing application settings and sharing features in a consistent location in the right-hand charms bar &#8212; are welcome improvements over the chaos that has been encroaching further and further into iOS&#8217; UX for the past few years.</p>
<p style="text-align: left;">Multitasking is a pleasure. Swiping to cycle through open apps is neat, but I prefer the swipe left-right-left gesture that displays a temporary sidebar of open apps (and the &#8220;missing&#8221; Start Menu) on the left. From there, you can jump directly to the app you want instead of cycling through the ones in between. After an hour or two, using that gesture and sidebar became completely unconscious, even though I almost never use that approach on my Windows 8 desktop machine. By comparison, the iOS and Android approaches to multitasking now feels downright archaic.</p>
<p style="text-align: left;">It&#8217;s difficult to put such a visceral UX difference into words. It&#8217;s hard to take my iPad seriously anymore, after using the Surface RT. Even though the iPad does have more apps, they all seem to be constrained inside an overall interface that often makes them feel like <a href="http://www.amazon.com/gp/product/B008VXS6D6/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B008VXS6D6&amp;linkCode=as2&amp;tag=encosia-20" target="_blank">a child&#8217;s toy</a>. By comparison, using Windows 8 on the Surface feels like I&#8217;m using a high quality tool &#8212; which is what I want. I have enough toys already.</p>
<h4 style="text-align: left;">Touch</h4>
<p>If you told me a year ago that I&#8217;d be using a laptop with a capacitive screen and actually touching the screen on a regular basis, I wouldn&#8217;t have believed you. The idea of touching the screen on a regular PC has never made much sense to me no matter how many times I&#8217;ve seen staged demos.</p>
<p>After just a few hours of using the Surface, <strong>I realized that I was reaching up from the keyboard to tap and scroll without thinking about it on a regular basis</strong>. Having a responsive touch screen a few inches from where my fingers naturally rest on the Touch Cover completely changes what feels natural.</p>
<p>So often on web pages, there&#8217;s a button or link that you can&#8217;t readily activate via keyboard, but tapping it is quick and easy when you&#8217;re already looking right at it.</p>
<p>Beyond simple button tapping, the system-wide gestures in Windows 8 are often effort multipliers compared to traditional keyboard and mouse inputs. A quick right-left swipe from the left edge shows thumbnails of open programs and then tapping the one you want to focus is usually faster than flipping through them all with Alt + Tab or hunting and clicking with the mouse.</p>
<p>Similarly, swiping down in Internet Explorer 10 to see thumbnails of open tabs and tapping on one is faster and more useful than cycling through them with Ctrl + Tab. On the Surface&#8217;s relatively narrow 16:9 display, it&#8217;s great that you don&#8217;t have to waste screen real estate on things like the address bar and open tabs while you&#8217;re using a particular tab.</p>
<p>A litany of relatively small things &#8212; as simple as being able to slide the volume slider up and down via touch after pressing the hardware button &#8212; all add up to a level of UI polish that you would normally expect from a more mature product.</p>
<h4>Metro</h4>
<p>The new &#8220;Modern UI&#8221; (aka Metro) interface in Windows 8 is at its best on a tablet. It&#8217;s easy to navigate, live tiles optionally provide useful ambient information, and it truly does feel <em>modern</em>. The grid of icons on my iPad reminds me of Windows 3.11 after using the Surface for a couple weeks. Not to mention how frustrating the arbitrary page breaks become after you&#8217;re accustomed to seamlessly scrolling across Windows 8&#8242;s landscape of tiles.</p>
<p>Being able to pin apps to the side was a lifesaver as I wrote this post. Often, I pinned Evernote to the left 1/4 while using the right 3/4 for WordPress&#8217; full screen editor. Using Evernote as a scratch area to temporarily hold sections of the post or serve as reference for rewriting a paragraph was something I noticed sorely lacking from iOS&#8217; simplistic take on multitasking when I attempted the same task with my iPad.</p>
<p>Within a week of using the Surface on a daily basis, <strong>I even began unconsciously trying to use its top-to-bottom swipe gesture to close apps on my iPhone</strong>. The entire interface is surprisingly natural once you get acclimated to it. Not necessarily discoverable for novices, but powerful, efficient, and <em>intuitive</em> if you put some effort into learning how to use it effectively.</p>
<h4>Not perfect</h4>
<p>Though the new interface is fantastic overall, I did have a couple minor issues using it even after learning all of its new tricks.</p>
<p>The most persistent annoyance is that, to my knowledge, you can&#8217;t see the percentage of battery charge remaining unless you flip over to the desktop and tap the battery icon in the system tray. That&#8217;s not terribly hard, but it buries the information a few steps away. I much prefer an ambient indicator of exactly what charge is remaining. The simple icon without a numeric percentage is not granular enough to instill confidence (imagine if the fuel gauge on your car dropped directly from 1/4 tank to empty without warning!).</p>
<p>Another thing I found myself missing is iOS&#8217; scroll-to-top feature. In iOS, on both the phone and tablet, you can tap the status bar at the top of the screen to scroll to the top of wherever you happen to be. On web pages and long lists (e.g. my email inbox every morning), that shortcut back to the top is a very useful time saver.</p>
<p>Those are my only serious complaints about the Windows 8 interface after a month of daily use though. That&#8217;s impressive for a first generation device and first iteration of something as fundamentally new as Windows 8.</p>
<h3 id="Hardware">Hardware</h3>
<p>Until very recently, one of the PC industry&#8217;s greatest failings has been a lack of solidly-constructed, aesthetically pleasing hardware. This year&#8217;s latest wave of UltraBooks has finally begun turning that around, but the MacBook Pro and Air still have advantages in some aspects. Similarly, there really hasn&#8217;t been a PC (or Android) tablet that compares with the iPad&#8217;s industrial design.</p>
<p>The Surface RT has finally made an impressive dent in that status quo. I&#8217;ve found it to be every bit as nice in reality as it looks in Microsoft&#8217;s advertisements.</p>
<h4>The VaporMg case</h4>
<p>The Surface&#8217;s construction and VaporMg case truly do seem to live up to the marketing hype thus far: It&#8217;s as solid as any electronic device you&#8217;re likely to ever hold. During one of the launch events, <a href="http://www.youtube.com/watch?v=qQddoyjef1k" target="_blank">Panos Panay dropped a Surface on the floor from shoulder-height</a>, picked it up, and continued his demo. <a href="http://news.cnet.com/8301-10805_3-57533996-75/windows-chief-rides-surface-like-a-skateboard-literally/" target="_blank">Steven Sinofsky rode a make-shift Surface RT skateboard</a>. It continued working after <a href="http://cnettv.cnet.com/torture-testing-microsoft-surface-tablet/9742-1_53-50135231.html" target="_blank">CNET froze it for over two hours and cooked an egg on it for another hour after that</a>. I&#8217;ve even seen a few stories about Surfaces that have been <a href="http://thenextweb.com/microsoft/2012/11/11/car-drives-over-surface-surface-laughs-and-keeps-on-truckin/" target="_blank">run over by automobiles and survived with only superficial damage to the case but not the display or innards</a>.</p>
<p>I have <em>not</em> been treating my Surface gently during the past month and haven&#8217;t had the slightest worry that it would break. I feel no trepidation tossing it around on semi-soft surfaces without a case, and generally treating it like a tool instead of something pretty and fragile.</p>
<p>Notably, I haven&#8217;t seen a single story yet about an accidental drop shattering the front glass like is so common with iDevices.</p>
<h4>The kickstand</h4>
<p>It&#8217;s interesting how much attention Microsoft&#8217;s marketing has given to the kickstand. It seems almost odd until you use it regularly, but the kickstand ends up being as <a href="http://www.microsoft.com/Surface/en-US/surface-with-windows-rt/kickstand" target="_blank">integral to the overall experience</a> as its Touch and Type Cover counterparts.</p>
<p>The kickstand&#8217;s hinge offers just enough resistance that it never flops open accidentally when you&#8217;re moving it around on soft surfaces, but easily opens into place with satisfying tactile feedback when you intentionally give a tug via the recessed groove on the side. Similarly, flipping it closed requires just enough force that you&#8217;ll never slip it shut while touching the screen when it&#8217;s upright, but shutting it with a squeeze of one hand requires only a comfortable effort.</p>
<p>It would be nice if the kickstand&#8217;s angle were more adjustable. Its 22-degree angle is usually pretty good for content creation and I&#8217;ve actually made use of its symbiosis with the rear-facing camera&#8217;s opposing 22-degree angle a couple times. On the other hand, it props the Surface up a bit steeper than I&#8217;d prefer when I&#8217;m sitting at a table and reading. However, if I had to choose between how secure and steady the kickstand is currently or a couple more angles, I&#8217;d happily take it as is.</p>
<h4>Other</h4>
<p>The front- and rear-facing cameras are about what you would expect from a tablet. They&#8217;re just passable for video conferencing and recording low-end HD video, but forget about using them for still photos of any kind. Neither camera in the Surface RT begins to compare to the camera in any smartphone you&#8217;re likely to own in 2012.</p>
<p>I&#8217;ve never really cared about the iPad&#8217;s lack of a standard I/O port, but the combination of a USB port and Windows&#8217; broad hardware support is more useful than I had expected. Ironically, I even used it to transfer photos from my iPhone without any configuration hassle.</p>
<p>The built-in speakers are underwhelming. I can live with tinny sound from such tiny speakers, and that&#8217;s the case with every tablet I&#8217;ve used, but the maximum volume is far too quiet. In a noisy environment like a coffee shop or a Microsoft Store, you can barely hear the sound at all. One consolation is that the internal sound hardware <em>does</em> drive headphones with fine volume and quality. I plugged my Bose headphones into it and the sound was loud, clear, and rich. The built-in speakers desperately need an upgrade in the next revision though.</p>
<h3 id="Touch-and-Type-Covers" style="text-align: left;">Touch and Type Covers: Surprisingly good</h3>
<p>I opted for the bundle that included a 32gb Surface RT and a <a href="http://www.microsoft.com/Surface/en-US/accessories/touch-cover" target="_blank">Touch Cover</a>. I was tempted to also get a Type Cover in case the Touch Cover didn&#8217;t work as well as advertised, but decided to make myself to give the lighter, thinner keyboard a fighting chance first. As it turns out, almost no acclimation was necessary. Typing on the Touch Cover is nothing like typing on a real keyboard, but it feels surprisingly natural to me (and <a href="http://encosia.com/a-month-with-my-zenbook-ux31/" target="_blank">I&#8217;m picky about my keyboards</a>).</p>
<p>You may have read that <a href="http://www.marco.org/2012/10/26/an-alternate-universe" target="_blank">laying your fingers on the touch cover&#8217;s home row results in unwanted &#8220;asdfjkl;&#8221; gibberish</a>, but that hasn&#8217;t been my experience at all. I can replicate that by forcefully slamming my fingers down onto the home row and wiggling them around a bit, but you&#8217;d have to be incredibly ham-fisted to have that problem during normal usage. If anything, I think the &#8220;pinky finger&#8221; keys take slightly more pressure to activate than I&#8217;d prefer for my typing technique, but it&#8217;s definitely better to err the side of extra pressure than accidental gibberish.</p>
<p>Probably for the same reason that I felt like significant pressure was necessary, I haven&#8217;t had much luck typing on soft surfaces. Using the Touch Cover in my lap or on an ottoman, I couldn&#8217;t find a good rhythm.</p>
<p>An unsung benefit of the Surface&#8217;s Touch and Type Covers, as compared to Bluetooth keyboards that work with other tablets, is that <strong>the Surface&#8217;s keyboards draw their power from the Surface itself through the magnetic connector</strong>. The tablet-friendly keyboards that companies like Logitech and Zapp sell are nice enough in theory, Bluetooth pairing and 2.4ghz interference aside, but no one talks very much about the extra hassle that comes with keeping the keyboard&#8217;s battery charged in addition to the tablet itself. You never have to think about that with the Surface.</p>
<h4>Can you hear the words that I&#8217;m&#8230; typing?</h4>
<p>I think that one of the keys to learning to use the Touch Cover is making sure the Surface&#8217;s sound isn&#8217;t muted. Similar to Windows Phone, the Windows 8 RT on-screen keyboard gives helpful audible feedback as you type &#8212; not just monotone clicks that are the same for every key, but varying beeps and bloops for different keys. It&#8217;s a surprisingly satisfying feedback mechanism. Over time, you can almost recognize the sound of distinct sequences of letters being entered.</p>
<p>The biggest drawback of a keyboard like the Touch Cover&#8217;s is that you don&#8217;t get much tactile feedback as key presses are registered. However, if you have the Surface&#8217;s sound unmuted, typing on the Touch Cover produces exactly the same audible feedback that the on-screen keyboard does. I was surprised how quickly that audible feedback trained my fingers to calibrate for pressure and rhythm while I typed.</p>
<p>So, do be sure that the device&#8217;s sound is audible if you&#8217;re trying one in a Microsoft Store or using your own Touch Cover for the first time.</p>
<h4>A cover that actually works as a cover</h4>
<p>Compared to my iPad&#8217;s Smart Cover, which I rarely use as a cover, folding either the Touch or Type Cover over the Surface and carrying it is a great experience. Where the iPad&#8217;s cover feels awkward as a stand and flimsy as a cover, the Touch and Type Covers&#8217; single panel makes a great cover and the built-in kickstand is perfect for propping the Surface up at good reading and typing angle on flat surfaces.</p>
<h4>A tiny trackpad is better than no trackpad</h4>
<p>One nice thing about both the Touch and Type Cover is that they include a tiny, but serviceable, trackpad. You might be skeptical about the usefulness of a trackpad barely bigger than the spacebar when you have an 10.6&#8243; capacitive touch display just a few inches away, but I disagree for one reason: <em>hover</em>.</p>
<p><img title="touch-cover-trackpad" src="http://encosia.com/blog/wp-content/uploads/2012/10/touch-cover-trackpad.jpg" alt="" width="490" height="100" /></p>
<p>Years into this supposed post-PC era, a depressing number of websites still depend on the mouseover event for crucial aspects of their functionality. Sometimes you can double-tap those elements, but if hovering reveals an element that isn&#8217;t in exactly the same location (e.g. many popup menus), you&#8217;re probably out of luck if all you have is touch input.</p>
<p>With the Touch Cover&#8217;s trackpad, temporarily fiddling with the mouse pointer allows you to circumnavigate those situations that would otherwise be dead-ends on other tablets.</p>
<h4>Type Cover: Perfect</h4>
<p>A couple weeks into this experiment, after I thought I&#8217;d forced myself to test the Touch Cover thoroughly enough, I also purchased a Type Cover. I&#8217;m not going to say very much about the Type Cover other than it&#8217;s perfect. I probably wouldn&#8217;t change one thing about it.</p>
<p>I use a <a href="http://www.amazon.com/gp/product/B000J43HJ8/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B000J43HJ8&amp;linkCode=as2&amp;tag=encosia-20" target="_blank">Logitech diNovo Edge</a> on my desktop PC, which is probably my favorite keyboard of all time. Even coming from that high level of expectation, I found a rhythm on the Type Cover almost immediately and can type at full speed.</p>
<p>If you don&#8217;t mind the <em>slight</em> extra thickness and feeling keys move under your fingers when you flip the cover behind the Surface, the Type Cover is good enough to directly replace almost any laptop keyboard and even some desktop keyboards.</p>
<h3 id="ClearType-Display">Display: ClearType saves the day?</h3>
<p>Most of the criticism I&#8217;ve seen targeted at the Surface RT has been directed at Microsoft&#8217;s decision to use a relatively low resolution display. Compared to the current iPad&#8217;s 2,048 x 1,536 resolution, the Surface RT&#8217;s 1,366 x 768 sounds pretty disappointing.</p>
<p><a href="http://www.neowin.net/news/microsoft-explains-why-they-chose-1366768-resolution-for-the-surface-rt" target="_blank">Microsoft has responded</a> by saying that several aspects of the Surface RT&#8217;s display, ranging from lower reflectivity to ClearType subpixel rendering, negate the resolution difference:</p>
<blockquote><p>First prong, Microsoft has the best pixel rendering technology in the industry (cleartype 1.0 and 2.0) .. these are exclusive and unique to Windows, it smooths text regardless of pixel count.</p>
<p>Second, we designed a custom 10.6” high-contrast wide-angle screen LCD screen.</p>
<p>Lastly we optically bonded the screen with the thinnest optical stack anywhere on the market.. something which is more commonly done on phones we are doing on Surface. While this is not official, our current Cleartype measurements on the amount of light reflected off the screen is around 5.5%-6.2%, the new IPad has a measurement of 9.9% mirror reflections. Doing a side by side with the new iPad in a consistently lit room, we have had many people see more detail on Surface RT than on the Ipad with more resolution.</p></blockquote>
<p>It&#8217;s easy to interpret that response as misdirection away from the core issue of display resolution, but it doesn&#8217;t seem to be wrong in my limited experience. Most of the time, the display looks fantastic. It&#8217;s clear, sharp, and images look like they&#8217;re closer to the surface of the device&#8217;s glass than other tablets that I&#8217;ve used.</p>
<p>When viewing photos, video, the start screen, and most native Windows 8 apps, the display looks perfect. Beyond my own experience, no one that I&#8217;ve shown my Surface to has had anything but positive comments about the display.</p>
<h4>They weren&#8217;t joking about the viewing angle</h4>
<p>The range of usable viewing angles on the Surface RT is unbelievable. I exclusively use <a href="http://www.codinghorror.com/blog/2007/11/not-all-lcd-panels-are-created-equal.html" target="_blank">LCD displays with IPS panels</a>, and <strong>the Surface RT still has the best off-center viewing quality I&#8217;ve ever seen</strong>.</p>
<p>I didn&#8217;t notice just how well the display looks nearly on-edge until I accidentally left laying face up on a tall kitchen counter one day and walked across the room to do something. Walking back toward the Surface, I realized that even at my ~10-15 degree viewing angle, there was almost no color distortion at all. In fact, it looked almost as bright and legible as if I were holding it at arm&#8217;s length directly in front of me.</p>
<p>That may not sound incredibly important, but keep in mind that you&#8217;ll be using a tablet in a wide range of positions. Being able to hold it at any comfortable angle and still see the screen clearly is an important feature.</p>
<h4>Ambient light sensor</h4>
<p>The biggest display-related complaint that I have after a month is that the ambient light sensor is too sensitive.</p>
<p>As with most devices, when you adjust the Surface RT&#8217;s display brightness, the device attempts to maintain that relative brightness as ambient lighting conditions change. So, if the lighting where you&#8217;re using the Surface at gets brighter, the display also gets brighter to compensate, and vice versa when the ambient lighting dims.</p>
<p>An ambient light sensor is a nice feature for a device that you&#8217;re likely to use in a variety of settings, but the Surface&#8217;s light sensor has a hair trigger. When I&#8217;m using it in a dark room, even the light from bright app or page reflecting back from my face is enough that display reacts as if lighting in the room changed.</p>
<p>At first, the effect is very disconcerting. Seeing the adjustment happen right as you&#8217;ve tapped to open an app makes it seem almost like there&#8217;s an intermittent problem with the backlight. Over time, I realized what was actually happening and it&#8217;s less alarming, but still annoying.</p>
<p>Hopefully, this is something Microsoft can address in a software update.</p>
<h3 id="Apps">Apps</h3>
<div id="attachment_1442" class="wp-caption alignnone" style="width: 500px"><img class="size-full wp-image-1442" title="angry-birds-space-on-windows-8-rt" src="http://encosia.com/blog/wp-content/uploads/2012/11/angry-birds-space-on-windows-8-rt.jpg" alt="" width="490" height="275" /><p class="wp-caption-text">Angry Birds Space running on my Surface RT (perfect shot!).</p></div>
<p>Running Windows 8 on an ARM device means that you can&#8217;t install existing x86 software (e.g. Visual Studio, QuickBooks, Comet Cursor&#8230;), so Windows 8&#8242;s new &#8220;apps&#8221; are going to be a crucial ingredient in the Surface RT&#8217;s success or failure.</p>
<h4>Built-in apps: Not bad</h4>
<p>When you see the start screen for the first time, you&#8217;ll already have a handful of Windows RT apps installed. Those built-in apps include a wide range of Metro-style apps for email, calendaring, photos, news, weather, finance, music, video, and the camera. There are also a few quasi-desktop apps, the desktop version of Internet Explorer 10 and the pre-installed Office 2013 preview.</p>
<p>Most of these built-in apps are passable.</p>
<ul>
<li>The People app is sluggish at times and difficult to navigate when you&#8217;re viewing dozens of status updates, but it does a pretty good job of what it&#8217;s intended to. I&#8217;d prefer a dedicated Facebook app to this aggregation though.</li>
<li>The Calendar app works well enough for my simple needs and its integration with the lock screen is nice. It has kept in sync with my Google Apps account and setup was hassle-free.</li>
<li>Messaging works well enough for Facebook and MSN (<a href="http://thenextweb.com/microsoft/2012/11/05/microsoft-may-retire-windows-live-messenger-in-the-coming-months-and-integrated-into-skype/" target="_blank">and/or Skype now?</a>) instant messaging. I was disappointed that it doesn&#8217;t support Google Chat though &#8212; especially since the Mail app does support Google&#8217;s services. There doesn&#8217;t seem to be a good reason to leave such a popular service unsupported.</li>
<li>The ancillary apps like Travel, Finance, and Sports work well enough and have led me to discover some interesting content that I probably wouldn&#8217;t have found otherwise.</li>
<li>Contrary to some reviews I&#8217;ve read, the Store app has worked well for me. It did give me trouble a couple times, but closing it with a downward swipe and reopening it fixed that (something I&#8217;ve experienced quite often in iOS 6&#8242;s app store as well, to be fair).</li>
<li>The SkyDrive app is nice to have right out of the box. Since I used my existing Microsoft account when I set the Surface up initially, I had immediate access to my SkyDrive files.</li>
</ul>
<h4>Mail</h4>
<p>With most of the built-in apps out of the way, let&#8217;s talk about the Mail app. The phrase &#8220;unmitigated disaster&#8221; comes to mind.</p>
<p>It&#8217;s slow. Often, it blanks out the entire message list and reading pane for several seconds after I delete or move a few emails and then redraws the whole thing. The editor&#8217;s performance when composing some messages &#8212; particularly when replying to a message with a large body of preexisting content &#8212; is unbelievably slow. It has trouble with inline images in messages on one of my accounts, prompting me to individually download each inline image and then failing every time. Dealing with multiple emails, whether moving or deleting, is cumbersome. I could go on, but you probably get the idea&#8230;</p>
<p>The Mail app is the worst email client I can remember using since Lotus Notes. This app needs to be overhauled and an update pushed out via the Store with absolutely the utmost urgency.</p>
<p>Considering that email is one of the most important tasks I used to use my iPad for, <strong>the current state of the Mail app is absolutely unacceptable to me. If anything about the Surface RT drives me back to the iPad, it will most likely be this</strong>.</p>
<h4>Store: Reminds me of the original iPad</h4>
<p><img class="alignnone size-full wp-image-1430" title="windows-store-on-surface-rt" src="http://encosia.com/blog/wp-content/uploads/2012/10/windows-store-on-surface-rt.jpg" alt="" width="490" height="275" /></p>
<p>As I mentioned earlier, one of the biggest drawbacks of running Windows 8 on an ARM device is that you can&#8217;t install existing x86 apps. With the Windows Store is still in the process of ramping up its inventory of Windows RT apps, that&#8217;s an important limitation to understand. Some notable apps like Netflix and Hulu+ are already available, but others like Dropbox and Facebook are <a href="http://venturebeat.com/2012/10/30/facebook-says-it-isnt-building-a-windows-8-app-directs-us-to-microsoft/" target="_blank">conspicuously absent</a> (though the built-in People and Messaging apps attempt to replace the latter).</p>
<p>It&#8217;s often suggested that Windows Phone 7.x has struggled to gain traction due in no small part to its lack of corresponding native apps that iOS and Android users enjoy. Following from that, some pundits claim that Windows 8 on ARM will suffer a similar chicken-or-egg problem while bootstrapping its new app store and hardware ecosystem.</p>
<p>I think the app store situation is interesting because it reminds me almost exactly of the iOS app store when the iPad was first released. It&#8217;s hard to remember now, but apps targeting the iPad&#8217;s screen size were scarce during the months after the iPad&#8217;s initial launch. As we all know now, iPads sold like hotcakes and developers responded by filling the iOS app store with compelling apps that took advantage of the iPad&#8217;s form factor, but that took time.</p>
<p>I expect that Microsoft&#8217;s massive distribution will result in such a proliferation of Windows 8 desktops and laptops that its app store will also become an irresistible development target. As a side effect, even if Windows 8 tablets don&#8217;t sell at the same pace that the iPad has immediately, they will still benefit from much of the  development that targets Windows 8 as a whole.</p>
<p>Only time will tell, but I think the Windows 8 store is a promising platform.</p>
<h4>Internet Explorer 10</h4>
<p>While the Store is still ramping up its inventory, Internet Explorer 10 is probably the most important app that ships with the Surface RT.</p>
<p>For example, while there&#8217;s no native Facebook app for Windows 8 yet, Facebook&#8217;s full desktop website works perfectly well even in the &#8220;Metro&#8221; version of IE10. The web interfaces to my email accounts have even blunted the agony of using the built-in Mail app somewhat.</p>
<p>Internet Explorer 10 is a surprisingly good browser. It lacks some features that I wish it didn&#8217;t, like WebGL, but it&#8217;s far and away better than its reputation from years past might suggest. It even supports WebSockets, which you probably wouldn&#8217;t expect if you haven&#8217;t kept up with IE10&#8242;s development.</p>
<div id="attachment_1444" class="wp-caption alignnone" style="width: 500px"><a href="http://html5test.com" target="_blank"><img class="size-full wp-image-1444 " title="internet-explorer-10-html5test" src="http://encosia.com/blog/wp-content/uploads/2012/11/internet-explorer-10-html5test.png" alt="Internet Explorer 10 scoring 320 at HTML5Test.com" width="490" height="400" /></a><p class="wp-caption-text">Testing Internet Explorer 10 on HTML5Test.com.</p></div>
<p>Even with the recent improvements, IE10 scores an underwhelming 320 at HTML5Test.com. For comparison, Mobile Safari on iOS 6 scores a 386 and Chrome 24 on my Windows desktop comes in at 453. So, IE10 will keep up with almost every mainstream website, but don&#8217;t expect it to handle the latest tech demos or sites using advanced HTML5 features.</p>
<p>One thing I&#8217;ve noticed is that IE10 seems to prioritize ongoing page rendering more than it does re-rendering the current viewport when you change zoom levels. On many pages I visit, one of the first things I do is zoom and pan to just the text I&#8217;m interested in reading. IE10 often leaves that newly-zoomed text heavily pixelated for several seconds before refining it to match the new zoom level. Not a good experience at all. By contrast, Mobile Safari on my iPad always stops everything to immediately re-render fonts when I zoom in on a page.</p>
<p>Hopefully, that&#8217;s an IE10 issue that can be solved with a software fix though, and not a long-term problem. I do think it&#8217;s a common enough scenario and jarring enough issue that it does need to be addressed long before IE11 though.</p>
<h3 id="Performance">Performance</h3>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/11/surface-rt-computer-properties.png" rel="attachment" target="_blank"><img class="alignnone size-full wp-image-1438" title="surface-rt-computer-properties-sm" src="http://encosia.com/blog/wp-content/uploads/2012/11/surface-rt-computer-properties-sm.png" alt="" width="490" height="227" /></a></p>
<p>An nVidia Tegra 3 ARM CPU and 2GB of RAM are at the heart of the Surface RT. My experience with native apps, streaming HD video, viewing web pages, and playing games has been mostly smooth and impressive.</p>
<p>Particularly, scrolling across the constantly updating live tiles on the start screen always feels satisfyingly &#8220;fast and fluid&#8221;. Where I&#8217;ve noticed that Android tablets struggle to smoothly juggle animating its widgets and moving them around at the same time, the Windows 8 on the Surface RT never feels slow or sluggish.</p>
<p>Even typing this 6,000+ word post in WordPress&#8217; &#8220;visual&#8221; editor, all of the text and several images crammed into an HTML textarea, has never appeared to be a challenge for my Surface RT.</p>
<h4>Office 2013</h4>
<p>There have been some high-visibility complaints about performance in the preview version of Office 2013 that comes pre-installed on this first wave of Surface RT devices. Mine suffered the same problems initially, to the point that even rendering newly typed characters in Word 2013 would often lag seconds behind my keystrokes.</p>
<p>However, installing the RTM version of Office 2013 via Windows Update completely solved the Office performance problems on my device. I even tried creating documents based on some of the more complex templates and typing gibberish as fast as possible at the top of the document (so the rendering engine also had to move the entire document down as a result, which previously exacerbated the performance issue previously), with no visible lag at all.</p>
<p>So, it may be true that the Surface RT&#8217;s Tegra 3 processor doesn&#8217;t have quite enough horsepower to make up for <a href="http://www.zdnet.com/microsofts-sinofsky-responds-to-complaint-over-office-2013-on-surface-rt-7000006484/" target="_blank">unoptimized preview code targeted at powerful desktop machines</a>. That&#8217;s not something I&#8217;m going to hold against it though. Running a fully functional instance of the latest version of Office on an ARM-based processor is quite a feat in any case, and updating to the optimized release version eliminates all of the performance issues that I could reproduce.</p>
<h4><span style="font-size: 1em;">Games</span></h4>
<p>One of the first things I tried on day one was installing <em>Cut the Rope</em> and <em>Jetpack Joyride</em>, both of which I&#8217;ve played on other platforms. I was disappointed to find intermittently choppy graphics performance in both games &#8212; no where near as smooth as the same games on my second generation iPad.</p>
<p>A few days later, I decided to give gaming on the Surface RT a second chance and purchased <a href="http://apps.microsoft.com/webpdp/en-us/app/angry-birds-space/8ece2571-91e0-4f2f-b7e5-b0b7944ced2d" target="_blank">Angry Birds Space</a>. Since purchases on the Surface transfer over to my other Windows 8 PCs anyway, that $5 investment would at least be worthwhile on my desktop.</p>
<p>I was pleased to find that graphics performance in Angry Birds Space on the Surface RT was nearly flawless &#8212; almost indistinguishable from playing the same game on my iPad 2 or Core i7 desktop. Compared to the other two games I had tried, the difference was night and day. The disparity was so great that it even prompted me to spend a few minutes killing processes and trying the other two games again to make sure that I hadn&#8217;t inadvertently played them during some background task I was unaware of  previously (nope; performance was the same).</p>
<p>A few weeks later, I had the same kind of positive experience with Angry Birds Star Wars (which is surprisingly fun, not a cheesy sellout).</p>
<p>I suspect that Microsoft has been lax about enforcing performance criteria when approving apps that are already popular on other platforms, putting a premium on filling the Store out with apps that iOS and Android have as quickly as possible. Over time, I doubt this will be a serious issue as developers have more time to tune their submissions, and in the shorter term the bad apples are avoidable by using the Store&#8217;s trial feature before you buy.</p>
<h4>To the cloud!</h4>
<p>Speaking of how my Angry Birds Space purchase applied to all of my Windows 8 PCs, so did my progress in the game itself. I happened to install the app on my desktop to see how well it worked with mouse (pretty well) and was surprised to see that I was already credited with the stars and achievements for the levels that I had played earlier on my Surface.</p>
<p>It&#8217;s a small thing, but I was impressed. There have been several times that I installed the same iOS game on both my iPad and iPhone, only to be faced with replaying already-defeated levels and losing interest in that proposition almost immediately.</p>
<p>Seamlessly syncing an arbitrary application&#8217;s settings and data across multiple devices is going to be a huge differentiating factor for Windows 8 tablets, PCs, Laptops, Windows Phone 8, and the Xbox when compared to the competition&#8217;s fragmentation. Microsoft has struggled to find a coherent synchronization story for years, but seems to have finally brought its entire ecosystem into firm alignment this year.</p>
<h3 id="Battery-Life">Battery Life</h3>
<div id="attachment_1439" class="wp-caption alignleft" style="width: 307px"><img class="size-full wp-image-1439  " title="viewing-surface-rt-battery-remaining" src="http://encosia.com/blog/wp-content/uploads/2012/11/viewing-surface-rt-battery-remaining.png" alt="" width="297" height="234" /><p class="wp-caption-text">54% remaining after nearly a full day&#8217;s use.</p></div>
<p>The ARM architecture&#8217;s key selling point is that it offers adequate performance at low power consumption (and produces less heat as a byproduct). So, one big question about the Surface RT is whether or not the extended battery life is worth the performance loss and significant compromise of not being able to run &#8220;legacy&#8221; x86 software.</p>
<p>Compared to any other PC running Windows that you&#8217;ve used in the past, you will be impressed with Surface RT&#8217;s battery life. I haven&#8217;t yet managed to deplete a full charge in a single day of moderate use, ranging from light tablet reading, heavy-duty content creation with the keyboard, to playing a few levels of Angry Birds Star Wars, to using Xbox SmartGlass in the living room. You&#8217;re basically looking at the same charging cycle as a good smartphone, where you can expect more than a full day of moderate usage, but probably wouldn&#8217;t want to try for two full days.</p>
<p>My initial opinion about the Surface RT&#8217;s battery life, compared to my iPad 2, wasn&#8217;t very favorable. On further reflection, I realized that the Surface&#8217;s battery was actually great. The difference is that the Surface is far more useful than the iPad and I&#8217;ve been using it more intensively than I have ever used my iPad. I think that says a lot about both the Surface RT and Windows 8.</p>
<h4>Heat</h4>
<p>Talking about battery life and the ARM architecture&#8217;s benefits wouldn&#8217;t be complete without talking about heat. The short answer is that there isn&#8217;t any.</p>
<p>I was able to make the back panel warm up <em>ever</em> so slightly at one point after I&#8217;d played Angry Birds for about fifteen minutes, but it was negligible. I wouldn&#8217;t have noticed if I hadn&#8217;t specifically been trying to stress test.</p>
<p>On the flip side of that same coin, I have no idea if the Surface RT even has a fan. I&#8217;ve never heard one spin up and heat has never been an issue anyway.</p>
<h4>Mag-not-Safe</h4>
<p>Speaking of charging the battery, the charging connection needs some work.</p>
<p>When I read that the Surface had a magnetic charging connector, I had visions of Apple&#8217;s excellent MagSafe connector. Unfortunately, the Surface RT&#8217;s connector, while magnetic, is awkward to connect to the side of the device.</p>
<p>Worse, I always feel like I&#8217;m probably scratching the area around the connector when I maneuver it into place (though I haven&#8217;t seen any visible wear in the area yet). This really should be improved in the next device &#8212; hopefully as soon as the Surface Pro.</p>
<h3 id="WiFi">WiFi</h3>
<p>I&#8217;ve always considered WiFi to be a fungible feature. Either it works or not, based primarily on whether or not my device supports the same frequency and standard that the available hotspots do, right?</p>
<p>Not so much, apparently. The dual-antenna WiFi hardware in the Surface RT changed my mind about the varying quality of WiFi hardware after two specific experiences.</p>
<h4>No more holding it wrong</h4>
<p>As a long-time iPad user, one thing that can be incredibly annoying, at least with my iPad 2, is that holding it &#8220;wrong&#8221; significantly hampers its WiFi performance. Unfortunately for me, the way I preferred to hold my iPad happens to be exactly the &#8220;wrong&#8221; way. I try to avoid holding it that way, but my hand usually slips back into that position every few minutes and websites stop loading. If I move my left hand, everything starts working great again.</p>
<p>At first, I didn&#8217;t believe that could possibly be the case. I always assume coincidence with these things until I can prove otherwise. However, running SpeedTest and varying my hand position confirmed my suspicions.</p>
<p>On the contrary, I can&#8217;t find a way to hold the Surface RT that impacts WiFi performance in the least. It&#8217;s a small thing, but a nicety that compounds over time.</p>
<h4>Can you hear me now?</h4>
<p>Since the Surface RT doesn&#8217;t support a cellular data connection, being able to reliably connect to WiFi is important. Almost immediately, I ran into a perfect example of how exceptional the Surface&#8217;s WiFi support is.</p>
<p>There&#8217;s a local restaurant a few miles from me that has a great patio where I can take the dog for a late lunch, relax, and catch up on email for a bit. The only problem is that the WiFi there is <em>terrible</em>. With my MacBook Air, I can only connect to it about half the time (and only if I sit in a particular seat) and it&#8217;s painfully slow even then. My iPhone and iPad won&#8217;t connect to it at all. Usually, they don&#8217;t even detect that the network is available.</p>
<p>With the Surface, I can sit anywhere on the patio and connect right up with 2-3 bars of signal strength. I had hoped for at least a reliably minimal connection with the Surface&#8217;s dual-antenna setup, but that result surpassed my expectations to be sure.</p>
<p>Sure, the root problem here is that the restaurant has their WiFi hotspot buried in the back of the building somewhere, but that&#8217;s hardly the exception. Not many businesses prioritize WiFi coverage, so the Surface&#8217;s ability to lock onto a weak signal and make the best of a bad scenario is welcome.</p>
<h3 id="Conclusion">Conclusion</h3>
<p>It&#8217;s been a few years since Ballmer first unveiled Microsoft&#8217;s &#8220;<a href="http://www.theverge.com/2012/6/22/3109846/three-screens-and-a-cloud-windows-8-windows-phone-8-xbox" target="_blank">three screens and the cloud</a>&#8221; strategy, but I&#8217;ve never really been very convinced by that vision very fully until these past few weeks. In a household with a litany of iDevices and a MacBook Air, like mine, an unproven device like the Surface RT is not an easy sell. Though I develop primarily on the Microsoft web platform, I&#8217;ve never been one to buy Microsoft products in other segments just for the sake of brand loyalty.</p>
<p>Yet, I recently realized that <strong>not only have I completely stopped using my iPad, I haven&#8217;t even turned on my MacBook Air since the Surface arrived</strong>. For my needs, the Surface RT really is that good. In fact, the integration between my Windows 8 desktop PC, Surface RT, and Xbox has actually made me want to try going &#8220;all in&#8221; and replacing my iPhone 5 with a Windows Phone 8.</p>
<p>Windows 8 on quality tablet hardware, like the Surface, is simply delightful to use. Even though I miss a few iOS apps, I don&#8217;t think I could go back to using iOS itself now. Everything else feels clumsy and tedious once you&#8217;ve used and mastered Windows 8 on the Surface.</p>
<p>As you might infer from all of the direct iPad comparisons in the preceding sections, I almost made the mistake of judging the Surface RT directly against the iPad. Most of the mainstream reviews I&#8217;ve seen have done exactly that, and I think that&#8217;s natural, but also a mistake. The Surface RT does fall short in some very specific niches where the iPad excels, but that&#8217;s because they aren&#8217;t really the same kind of device. I believe the combination of Windows 8 and the Surface is a subtly different type of thing than the current crop of consumer tablets, focused on a more optimal balance between content consumption <em>and creation </em>without sacrificing sleek, beautiful construction.</p>
<p>Nothing else I&#8217;ve seen or used has struck that chord so perfectly.</p>
<h4>Should you buy a Surface RT?</h4>
<p>Maybe. I personally like my Surface RT so much that it&#8217;s hard not to recommend it to everyone, but I don&#8217;t think it&#8217;s necessarily appropriate for every user (yet).</p>
<p>If you&#8217;re thinking about buying one for a non-technical friend or family member, wait. The Store needs to fill out a bit more with popular apps and a few rough edges, like the built-in Mail app, need to be smoothed out before it&#8217;s an ideal device for a non-technical user. There&#8217;s a good chance this will be an ideal device for consumer users after a few software updates and a couple months worth of Store submissions, but it&#8217;s not quite there today.</p>
<p>If you&#8217;re considering a purchase for yourself or someone else technically savvy, understand the limitations of Windows 8 RT on an ARM device, and still want to give it a try then you absolutely should. The Surface RT has met or exceeded almost all of my expectations, and completely superseded my iPad from day one.</p>
<h4><span style="font-size: 1em;">Don&#8217;t forget the Surface Pro</span></h4>
<p>The inability to develop software on the Surface RT might be a non-starter for some of you. There is a remote desktop client that you could use to develop on a remote machine, but that&#8217;s not a great experience (I&#8217;ve tried). Over time, I expect tools like <a href="http://c9.io" target="_blank">Cloud9</a> to support IE10 and good Windows 8 code editors to start showing up in the store. However, I doubt it will ever be possible to develop for ASP.NET or Windows 8 itself on the Surface RT.</p>
<p>If screen resolution, app selection, performance, and/or development are too important for to you to compromise on, you can always wait a few months for the <a href="http://www.microsoft.com/Surface/en-US/surface-with-windows-8-pro/specifications" target="_blank">Surface Pro</a>. It&#8217;s rumored to pack a 1920 x 1080 resolution into the same 10.6&#8243; package, have a full-power Intel processor, a stylus/digitizer, and other PC-class hardware. As well as my lowly Surface RT has replaced my MacBook Air, I think the Surface Pro will be a game changer for users with more demanding needs.</p>
<h3>Disclaimer</h3>
<p>To be clear, there is no disclaimer. I purchased my Surface RT, Touch Cover, and Type Cover online at the Microsoft Store with my own funds and received no promotional consideration for writing this post.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/a-month-with-my-surface-rt/">A month with my Surface RT</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/a-month-with-my-surface-rt/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/' rel='bookmark' title='Closing Windows 8 apps with Surface RT&#8217;s Touch Cover'>Closing Windows 8 apps with Surface RT&#8217;s Touch Cover</a></li>
<li><a href='http://encosia.com/a-month-with-my-zenbook-ux31/' rel='bookmark' title='A month with my Zenbook UX31'>A month with my Zenbook UX31</a></li>
<li><a href='http://encosia.com/interesting-details-on-ie10s-javascript-performance-tweaks/' rel='bookmark' title='Interesting details on IE10&#8242;s JavaScript performance tweaks'>Interesting details on IE10&#8242;s JavaScript performance tweaks</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=i35dj8yipbw:kgECBP6l45w:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=i35dj8yipbw:kgECBP6l45w:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=i35dj8yipbw:kgECBP6l45w:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=i35dj8yipbw:kgECBP6l45w:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/i35dj8yipbw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/a-month-with-my-surface-rt/feed/</wfw:commentRss>
		<slash:comments>60</slash:comments>
		<feedburner:origLink>http://encosia.com/a-month-with-my-surface-rt/</feedburner:origLink></item>
		<item>
		<title>Closing Windows 8 apps with Surface RT’s Touch Cover</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/Pgd4LBBakzY/</link>
		<comments>http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/#comments</comments>
		<pubDate>Mon, 29 Oct 2012 16:57:32 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Windows 8]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1427</guid>
		<description><![CDATA[Windows 8&#8242;s new gesture for closing programs works pretty well when you&#8217;re using a Surface in your hands as a pure tablet, but it feels a bit awkward when you have the Surface&#8217;s kickstand and a Touch/Type Cover deployed. Something about the combination of angle and distance in that configuration makes dragging from top to [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/a-month-with-my-surface-rt/' rel='bookmark' title='A month with my Surface RT'>A month with my Surface RT</a></li>
<li><a href='http://encosia.com/guidance-on-building-real-world-html-and-javascript-apps/' rel='bookmark' title='Guidance on building real-world HTML and JavaScript apps'>Guidance on building real-world HTML and JavaScript apps</a></li>
<li><a href='http://encosia.com/cheerio-faster-windows-friendly-alternative-jsdom/' rel='bookmark' title='Cheerio: A faster, Windows-friendly alternative to jsdom'>Cheerio: A faster, Windows-friendly alternative to jsdom</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>Windows 8&#8242;s new gesture for closing programs works pretty well when you&#8217;re using a Surface in your hands as a pure tablet, but it feels a bit awkward when you have the Surface&#8217;s kickstand and a Touch/Type Cover deployed. Something about the combination of angle and distance in that configuration makes dragging from top to bottom of the screen feel awkward.</p>
<p>Though Windows 8 apps don&#8217;t look like traditional Windows programs, many of Windows&#8217; traditional keyboard shortcuts still work in them. In Windows, Alt + F4 is the keyboard shortcut to quit the active application and that shortcut also closes apps running in the new UI.</p>
<p>At first glance, the Surface&#8217;s Touch Cover doesn&#8217;t appear to have traditional function keys. However, the top row doubles as function keys if you hold down the &#8220;Fn&#8221; key at the lower right. As you might expect, the fourth key from the left (marked as a play/pause key) is F4&#8242;s secret identity.</p>
<p>So, <strong>holding both Alt and Fn and then pressing play/pause works to close the active application</strong> without dealing with the vertical dragging gesture.</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/10/surface-rt-alt-f4.jpg" rel="attachment"><img class="alignnone size-full wp-image-1428" title="Using Alt + Fn + F4 to close a Windows 8 app on the Surface RT Touch Cover" src="http://encosia.com/blog/wp-content/uploads/2012/10/surface-rt-alt-f4-sm.jpg" alt="" width="490" height="219" /></a></p>
<hr />

<p>You've been reading <a href="http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/">Closing Windows 8 apps with Surface RT&#8217;s Touch Cover</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/a-month-with-my-surface-rt/' rel='bookmark' title='A month with my Surface RT'>A month with my Surface RT</a></li>
<li><a href='http://encosia.com/guidance-on-building-real-world-html-and-javascript-apps/' rel='bookmark' title='Guidance on building real-world HTML and JavaScript apps'>Guidance on building real-world HTML and JavaScript apps</a></li>
<li><a href='http://encosia.com/cheerio-faster-windows-friendly-alternative-jsdom/' rel='bookmark' title='Cheerio: A faster, Windows-friendly alternative to jsdom'>Cheerio: A faster, Windows-friendly alternative to jsdom</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=Pgd4LBBakzY:ecTh2I-MeuY:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=Pgd4LBBakzY:ecTh2I-MeuY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=Pgd4LBBakzY:ecTh2I-MeuY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=Pgd4LBBakzY:ecTh2I-MeuY:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/Pgd4LBBakzY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://encosia.com/closing-windows-8-programs-with-the-surface-rts-touch-cover/</feedburner:origLink></item>
		<item>
		<title>Technical debt is like ketchup</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/T7O3bTXJ0Nk/</link>
		<comments>http://encosia.com/technical-debt-is-like-ketchup/#comments</comments>
		<pubDate>Mon, 15 Oct 2012 18:53:07 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Short]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1417</guid>
		<description><![CDATA[Have you ever tried washing dried, day-old ketchup off a dish? It&#8217;s not fun. What would have taken just a couple seconds to rinse off while it was still fresh can take minutes and multiple attempts to scrub off later. Worse, the realisation that you&#8217;re going to have to deal with the dried ketchup is [...]<div class='yarpp-related-rss yarpp-related-none'>

No related posts.
</div>
]]></description>
				<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-1418" src="http://encosia.com/blog/wp-content/uploads/2012/10/ketchup-on-plate.jpg" alt="Image by Zieak (http://www.flickr.com/photos/zieak/431730940/)" width="490" height="225" /></p>
<p>Have you ever tried washing dried, day-old ketchup off a dish? It&#8217;s not fun. What would have taken just a couple seconds to rinse off while it was still fresh can take minutes and multiple attempts to scrub off later.</p>
<p>Worse, the realisation that you&#8217;re going to have to deal with the dried ketchup is most likely to come right when you need to do something else with that dish the most.</p>
<p>As you let ketchup (and other foods) accumulate on your dishes without cleaning them immediately, eventually your entire collection of dishes is unusable.</p>
<p>Some dishes are more disposable than others. For some dishes, you&#8217;re eventually more likely to throw the dish out and start over with a new one than find a way to make the ketchup-spackled disaster you&#8217;ve created serviceable again.</p>
<h3>Seriously though</h3>
<p>One of the hardest parts of software development is simplifying and explaining it to the non-technical people who write the checks. Technical debt is one of those crucially important concepts that <a href="http://www.joelonsoftware.com/articles/fog0000000069.html" target="_blank">can alter the course of an entire company if left unchecked</a>, but it can be incredibly difficult to clearly convey that to non-technical stakeholders.</p>
<p>Your negative notions about what debt is might be what a &#8220;business guy&#8221; considers productive leverage. You can just pay that debt back after the new feature makes us all rich, right? I wonder if that has <em>ever</em> happened?</p>
<p>Next time, tell them it&#8217;s like ketchup.</p>
<p>&nbsp;</p>
<hr />

<p>You've been reading <a href="http://encosia.com/technical-debt-is-like-ketchup/">Technical debt is like ketchup</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/technical-debt-is-like-ketchup/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss yarpp-related-none'>
<p>No related posts.</p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=T7O3bTXJ0Nk:Ka_GQA1QUfg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=T7O3bTXJ0Nk:Ka_GQA1QUfg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=T7O3bTXJ0Nk:Ka_GQA1QUfg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=T7O3bTXJ0Nk:Ka_GQA1QUfg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/T7O3bTXJ0Nk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/technical-debt-is-like-ketchup/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://encosia.com/technical-debt-is-like-ketchup/</feedburner:origLink></item>
		<item>
		<title>A harsh reminder about the importance of debug=”false”</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/1hJPFpXq5Cg/</link>
		<comments>http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/#comments</comments>
		<pubDate>Wed, 19 Sep 2012 16:09:09 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1393</guid>
		<description><![CDATA[This post was originally going to be about improving performance in ASP.NET MVC websites that use the Razor view engine. Instead, it became a cautionary tale about just how important it is to run your ASP.NET sites in release mode if you care anything at all about performance. The whole thing began when I tweeted [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/debug-and-explore-aspnet-ajax-with-firebug/' rel='bookmark' title='Debug and explore AJAX with FireBug'>Debug and explore AJAX with FireBug</a></li>
<li><a href='http://encosia.com/learn-from-my-express-js-http-status-code-blunder/' rel='bookmark' title='Learn from my Express.js HTTP status code blunder'>Learn from my Express.js HTTP status code blunder</a></li>
<li><a href='http://encosia.com/postback-ritalin-v1-0/' rel='bookmark' title='PostBack Ritalin v1.0'>PostBack Ritalin v1.0</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>This post was originally going to be about improving performance in ASP.NET MVC websites that use the Razor view engine. Instead, it became a cautionary tale about just how important it is to run your ASP.NET sites in release mode if you care anything at all about performance.</p>
<p>The whole thing began when I tweeted about some rough <a href="http://encosia.com/i/asp-net-mvc-vs-web-api-vs-self-hosted-web-api/" target="_blank">benchmarks on ASP.NET MVC controller actions vs. ASP.NET Web API endpoints</a> last week, and <a href="https://twitter.com/ashic" rel="nofollow" target="_blank">Ashic Mahtab</a> asked me to also run some benchmarks comparing MVC&#8217;s Razor and WebForms view engines. When I ran those benchmarks and replied to him with <a href="https://twitter.com/Encosia/status/242326171197526016" target="_blank">the result that Razor was running much slower than WebForms</a>, he had this suggestion:</p>
<blockquote><p>@<a href="https://twitter.com/encosia">encosia</a> did you remove the web forms view engine for the razor test?</p>
<p>— Ashic Mahtab (@ashic) <a href="https://twitter.com/ashic/status/242328832898637825" data-datetime="2012-09-02T18:31:10+00:00">September 2, 2012</a></p></blockquote>
<p>Good idea. I did that, re-ran the Razor benchmark, and the magnitude of the change really surprised me. <strong>Razor was over twice as fast with the WebForms engine removed!</strong></p>
<p>I knew that removing the WebForms view engine improves the performance of Razor view resolution, but I didn&#8217;t expect the difference to be nearly that significant. So, why was the difference so large?</p>
<h3>The search for a view</h3>
<p>Before we get to the fallacy in my benchmarks, you may be wondering why removing the WebForms engine made such a big difference. The root cause can be seen in an error message that&#8217;s probably all too familiar if you&#8217;ve spent any time working with ASP.NET MVC:</p>
<p><img class="full-width" title="asp.net-mvc-default-view-search-locations" src="http://encosia.com/blog/wp-content/uploads/2012/09/asp.net-mvc-default-view-search-locations.png" alt="An error message showing ASP.NET MVC's default view search locations." width="490" height="321" /></p>
<p>By default, MVC is configured to resolve named views by searching for files that match the WebForms view engine&#8217;s naming conventions first. Only after scanning unsuccessfully for those first four variants does MVC search for Razor views.</p>
<p>As you can imagine, running through the process of checking four unused locations first for every <code>return View()</code> and <code>Html.RenderPartial</code> is quite wasteful if you aren&#8217;t using the WebForms view engine in your project.</p>
<h3>Removing the WebForms view engine</h3>
<p>If that view resolution inefficiency bothers you, it&#8217;s easy to remove the WebForms view engine from the mix. Just drop code something like this in your Global.asax.cs&#8217; Application_Start event:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">ViewEngines.<span style="color: #0000FF;">Engines</span>.<span style="color: #0000FF;">Clear</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
ViewEngines.<span style="color: #0000FF;">Engines</span>.<span style="color: #0000FF;">Add</span><span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> RazorViewEngine<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>

<p>In debug mode, that small change results in a significant performance boost because MVC will be able to locate views four I/O operations quicker. Often, the very first location MVC searches is now the correct one for C#-based Razor views.</p>
<h3>Benchmarking bad</h3>
<p>I wanted to get a better idea of what impact removing the WebForms view engine would have on a real-world page. With the plethora of view resolutions necessary on a complex page, a real site is a more interesting test than benchmarking a simple <code>DateTime.Now</code>. So, I found an older MVC site that I had recently migrated from WebForms to Razor, benchmarked it, removed the WebForms view engine, and benchmarked it again.</p>
<p>The results spoke for themselves. Before, with the WebForms view engine&#8217;s search locations taking precedence over Razor:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-webforms-view-engine.png" rel="attachment" target="_blank"><img class="full-width" title="benchmark-with-webforms-view-engine-sm" src="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-webforms-view-engine-sm.png" alt="" width="490" height="350" /></a></p>
<p>1,225 requests per second across 1,000 concurrent connections. Not too shabby, but now let&#8217;s eliminate the WebForms view engine from the mix and try it again.</p>
<p>Running the same benchmark with only the Razor view engine, using the Clear/Add approach shown earlier in this post:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-only-razor-view-engine.png" rel="attachment" target="_blank"><img class="full-width" title="benchmark-with-only-razor-view-engine-sm" src="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-only-razor-view-engine-sm.png" alt="" width="490" height="350" /></a></p>
<p>2,671 requests per second now, testing the same page with the same benchmark settings. Two lines of code have resulted in roughly <em>twice</em> the performance!</p>
<p>That&#8217;s a pretty impressive improvement, but incredibly misleading.</p>
<h3>All for naught</h3>
<p>At this point, you might be thinking that the point of this post is to remove the WebForms view engine if you&#8217;re using Razor. After all, twice the performance is pretty compelling.</p>
<p>Quite the opposite, it turns out that my benchmarking was pointless because I was running these sites in debug mode locally. I&#8217;ll explain why that matters in a minute, but first let&#8217;s look at the same benchmarks with debug set to false.</p>
<p>First, I benchmarked the default view engine setup again. With the WebForms view engine&#8217;s search locations coming before Razor&#8217;s, these were the results:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-webforms-view-engine-release.png" rel="attachment"><img class="full-width" title="benchmark-with-webforms-view-engine-release" src="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-webforms-view-engine-release-sm.png" alt="" width="490" height="350" /></a></p>
<p>Now, with the WebForms view engine removed and only Razor&#8217;s view resolution in play:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-only-razor-view-engine-release.png" rel="attachment"><img class="full-width" title="benchmark-with-only-razor-view-engine-release" src="http://encosia.com/blog/wp-content/uploads/2012/09/benchmark-with-only-razor-view-engine-release-sm.png" alt="" width="490" height="350" /></a></p>
<p>We&#8217;ve gone from a 100% performance increase to a meager 1-2% increase. What in the world happened? Wouldn&#8217;t you expect the performance optimizations in release mode to apply equally in both scenarios?</p>
<h3>So, what happened?</h3>
<p>In debug mode, view resolution is optimized for ease of development. MVC iterates through the view resolution process each and every time your code renders a named view. That&#8217;s helpful since you obviously do want the environment to respond immediately to your changes when you&#8217;re working on a site.</p>
<p><strong>In release mode, however, MVC&#8217;s view resolution is optimized for performance</strong>. When a view location is successfully resolved in release mode, MVC caches the result of that lookup and doesn&#8217;t need to perform another filesystem search when it encounters a reference to that named view again.</p>
<p>The result is that the apparent inefficiency of having WebForms&#8217; naming conventions take precedence over Razor&#8217;s becomes negligible after the first resolution. So long as you don&#8217;t allow your production sites to run in debug mode, the view resolution issue is almost entirely eliminated.</p>
<h3>debug=&#8221;false&#8221; &#8211; not just for view engines</h3>
<p>View resolution caching is just one reason of many to ensure that you do not run your production sites in debug mode. Other serious drawbacks include:</p>
<ul>
<li><strong>Timeouts</strong> &#8211; Have you ever noticed that you can spend an indefinite amount of time fooling around in the debugger without a halted request timing out? That&#8217;s because debug=&#8221;true&#8221; disables timeouts entirely, which is never a good idea on a live site.</li>
<li><strong>Bundling and Minification</strong> &#8211; <a href="http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification" target="_blank">ASP.NET&#8217;s new web optimization feature</a> can automatically bundle and minify your JavaScript and CSS, but it only does so in release mode. When you run with debug=&#8221;true&#8221;, bundles are served as separate, unminified, uncombined script references with short caching headers. That&#8217;s important during development so you can read/debug your JavaScript code, but it defeats the entire point of the optimization exercise in production.</li>
<li><strong>WebResource.axd caching</strong> &#8211; Speaking of client-side resource optimization, resources served through WebResource.axd include aggressive caching headers in release mode. In debug mode, they are not cached at all.</li>
</ul>
<p>There are even <a href="http://weblogs.asp.net/scottgu/archive/2006/04/11/Don_1920_t-run-production-ASP.NET-Applications-with-debug_3D001D20_true_1D20_-enabled.aspx" target="_blank">more reasons to avoid debug=&#8221;true&#8221; in production</a>, but the items above are a few that I think are less obvious since they aren&#8217;t directly related to benefits associated with release mode compilation. It&#8217;s easy to think of debug and release in terms of compiler optimization and debug symbols since the configuration switch is on the &#8220;compilation&#8221; element in web.config.</p>
<p>So, it&#8217;s important to be mindful that <strong>this single &#8220;compilation&#8221; setting controls a wider range of your site&#8217;s functionality than you might expect</strong>.</p>
<h3>Conclusion</h3>
<p>Of course, you probably already know that you shouldn&#8217;t deploy a live site in debug mode, but how many times have you seen it happen anyway?</p>
<p>There&#8217;s always a &#8220;good&#8221; reason, like coaxing more detailed error messages from a site that only breaks in production, or disabling client-side resource caching to fix issues when rolling out new assets. Stretched as thin as most of us are, it&#8217;s all too easy to leave that site running in debug mode after the immediate issue is resolved.</p>
<p>So, let my benchmarking blunder be a reminder to check today and be sure that you don&#8217;t have any production sites running in debug mode.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/">A harsh reminder about the importance of debug=&#8221;false&#8221;</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/debug-and-explore-aspnet-ajax-with-firebug/' rel='bookmark' title='Debug and explore AJAX with FireBug'>Debug and explore AJAX with FireBug</a></li>
<li><a href='http://encosia.com/learn-from-my-express-js-http-status-code-blunder/' rel='bookmark' title='Learn from my Express.js HTTP status code blunder'>Learn from my Express.js HTTP status code blunder</a></li>
<li><a href='http://encosia.com/postback-ritalin-v1-0/' rel='bookmark' title='PostBack Ritalin v1.0'>PostBack Ritalin v1.0</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=1hJPFpXq5Cg:Gmg9pn3K8qg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=1hJPFpXq5Cg:Gmg9pn3K8qg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=1hJPFpXq5Cg:Gmg9pn3K8qg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=1hJPFpXq5Cg:Gmg9pn3K8qg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/1hJPFpXq5Cg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		<feedburner:origLink>http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/</feedburner:origLink></item>
		<item>
		<title>Hear me talk about drama on This Developer’s Life</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/vuuQURKzXcM/</link>
		<comments>http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/#comments</comments>
		<pubDate>Mon, 17 Sep 2012 16:19:51 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1402</guid>
		<description><![CDATA[Rob had me on This Developer&#8217;s Life recently, along with several other fine folks, talking about drama on the Internet, semicolons, and generally &#8220;why so mean?&#8221; I thought it was an interesting episode. Though I&#8217;ve occasionally been sucked into &#8220;someone&#8217;s wrong on the Internet&#8221; myself, I try to avoid drama. So many debates-turned-arguments on the [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/hear-me-talk-jquery-and-asp-net-on-the-jquery-podcast/' rel='bookmark' title='Hear me talk jQuery and ASP.NET on the jQuery Podcast'>Hear me talk jQuery and ASP.NET on the jQuery Podcast</a></li>
<li><a href='http://encosia.com/hear-me-talk-about-jquery-on-the-polymorphic-podcast/' rel='bookmark' title='Hear me talk about jQuery on the Polymorphic Podcast'>Hear me talk about jQuery on the Polymorphic Podcast</a></li>
<li><a href='http://encosia.com/hear-us-talk-about-javascript-on-hanselminutes-episode-28/' rel='bookmark' title='Hear us talk about JavaScript on Hanselminutes episode 2^8'>Hear us talk about JavaScript on Hanselminutes episode 2^8</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p><a href="http://xkcd.com/386/" target="_blank"><img class="alignleft" align="left" style="margin: 5px 5px 0 0;" src="http://encosia.com/blog/wp-content/uploads/2012/09/duty_calls.png" alt="Duty Calls - Someone's wrong on the Internet!" /></a>Rob had me on <a href="http://thisdeveloperslife.com/" target="_blank">This Developer&#8217;s Life</a> recently, along with several other fine folks, talking about drama on the Internet, semicolons, and generally &#8220;<a href="http://www.hanselman.com/blog/content/binary/WindowsLiveWriter/ExploringALT.NETSeattle_14C60/3315902622_bcce1fb3c8_3.jpg" target="_blank">why so mean?</a>&#8221;</p>
<p>I thought it was an interesting episode. Though I&#8217;ve occasionally been sucked into &#8220;someone&#8217;s wrong on the Internet&#8221; myself, I try to avoid drama. So many debates-turned-arguments on the Internet are all downside and have almost no potential upside even if you &#8220;win&#8221;.</p>
<p>So, I was really interested to hear what others had to say about the topic, and they did not disappoint. If the subject sounds interesting to you (and fair warning, there&#8217;s almost no technical content in this one), you might enjoy it too.</p>
<p>You can stream or download the episode here: <a href="http://thisdeveloperslife.com/post/2-0-9-drama" target="_blank">The Developer&#8217;s Life &#8211; 2.0.9 Drama</a></p>
<hr />

<p>You've been reading <a href="http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/">Hear me talk about drama on This Developer&#8217;s Life</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/hear-me-talk-jquery-and-asp-net-on-the-jquery-podcast/' rel='bookmark' title='Hear me talk jQuery and ASP.NET on the jQuery Podcast'>Hear me talk jQuery and ASP.NET on the jQuery Podcast</a></li>
<li><a href='http://encosia.com/hear-me-talk-about-jquery-on-the-polymorphic-podcast/' rel='bookmark' title='Hear me talk about jQuery on the Polymorphic Podcast'>Hear me talk about jQuery on the Polymorphic Podcast</a></li>
<li><a href='http://encosia.com/hear-us-talk-about-javascript-on-hanselminutes-episode-28/' rel='bookmark' title='Hear us talk about JavaScript on Hanselminutes episode 2^8'>Hear us talk about JavaScript on Hanselminutes episode 2^8</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vuuQURKzXcM:udqw0PD3Ikk:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vuuQURKzXcM:udqw0PD3Ikk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vuuQURKzXcM:udqw0PD3Ikk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vuuQURKzXcM:udqw0PD3Ikk:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/vuuQURKzXcM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/</feedburner:origLink></item>
		<item>
		<title>The crucial .0 in Google CDN references to jQuery 1.x.0</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/EL7q6KNge6E/</link>
		<comments>http://encosia.com/the-crucial-0-in-google-cdn-references-to-jquery-1-x-0/#comments</comments>
		<pubDate>Sat, 18 Aug 2012 18:43:18 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1206</guid>
		<description><![CDATA[jQuery 1.8 is out, and that new version is available on the Google CDN now. That&#8217;s good news on both counts, but reminds me of an issue that I&#8217;ve been meaning to write about for quite a while now. Unfortunately, each new 1.n jQuery release results in a new wave of sites linking to the [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/6953-reasons-why-i-still-let-google-host-jquery-for-me/' rel='bookmark' title='6,953 reasons why I still let Google host jQuery for me'>6,953 reasons why I still let Google host jQuery for me</a></li>
<li><a href='http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/' rel='bookmark' title='3 reasons why you should let Google host jQuery for you'>3 reasons why you should let Google host jQuery for you</a></li>
<li><a href='http://encosia.com/cripple-the-google-cdns-caching-with-a-single-character/' rel='bookmark' title='Cripple the Google CDN&#8217;s caching with a single character'>Cripple the Google CDN&#8217;s caching with a single character</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p><a href="http://blog.jquery.com/2012/08/09/jquery-1-8-released/" target="_blank">jQuery 1.8 is out</a>, and that new version <a href="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" target="_blank">is available on the Google CDN now</a>.</p>
<p>That&#8217;s good news on both counts, but reminds me of an issue that I&#8217;ve been meaning to write about for quite a while now. Unfortunately, each new 1.<em>n</em> jQuery release results in a new wave of sites linking to the Google CDN&#8217;s copy of jQuery in a way that seems intuitively correct, but results in needlessly poor performance.</p>
<p>If you don&#8217;t care about the hows and whys, the short story is that <strong>it&#8217;s crucial that you always specify the full <em>major</em>.<em>minor</em>.<em>patch</em> version number when you use the Google CDN</strong>. Even though jQuery itself only refers to its new releases with a <em>major</em>.<em>minor</em> version number (e.g. 1.8), it&#8217;s important that you append a trailing <code>.0</code> when you use the CDN to include a new minor revision on your page.</p>
<p>In other words, please use this URL to reference jQuery 1.8 on the Google CDN:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js</pre></div></div>

<p><strong>Under no circumstance should you omit that seemingly superfluous .0 in the version number on a production site</strong>. Failure to include the trailing zero will result in <em>significantly </em>degraded caching.</p>
<p>If you don&#8217;t care about why, you can stop here. Just be sure to add the .0 when you&#8217;re referencing jQuery 1.7, 1.8, 1.9, 2.0, 2.1, and so on. If you&#8217;re interested in why it&#8217;s so important, keep reading.</p>
<h3>My least favorite Google CDN feature</h3>
<p>One of the Google CDN&#8217;s less obvious features is that you can reference the libraries on it without specifying a full version number. If you do that, the CDN will determine what version of the library is the latest one that matches your partial version number and respond with that.</p>
<p>For example, referencing any of the following URLs will retrieve the exact same copy of jQuery 1.8 at the time this was written:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Obviously...</span>
ajax.<span style="color: #202020;">googleapis</span>.<span style="color: #202020;">com</span><span style="color: #339933;">/</span>ajax<span style="color: #339933;">/</span>libs<span style="color: #339933;">/</span>jquery<span style="color: #339933;">/</span>1.8.0<span style="color: #339933;">/</span>jquery.<span style="color: #202020;">min</span>.<span style="color: #202020;">js</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Makes sense...</span>
ajax.<span style="color: #202020;">googleapis</span>.<span style="color: #202020;">com</span><span style="color: #339933;">/</span>ajax<span style="color: #339933;">/</span>libs<span style="color: #339933;">/</span>jquery<span style="color: #339933;">/</span><span style="color:#800080;">1.8</span><span style="color: #339933;">/</span>jquery.<span style="color: #202020;">min</span>.<span style="color: #202020;">js</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Living dangerously.</span>
ajax.<span style="color: #202020;">googleapis</span>.<span style="color: #202020;">com</span><span style="color: #339933;">/</span>ajax<span style="color: #339933;">/</span>libs<span style="color: #339933;">/</span>jquery<span style="color: #339933;">/</span><span style="color: #0000dd;">1</span><span style="color: #339933;">/</span>jquery.<span style="color: #202020;">min</span>.<span style="color: #202020;">js</span></pre></div></div>

<p>Similarly, both of these URLs will retrieve the same jQuery 1.7.2 script content, probably for as long as the Google CDN hosts jQuery 1.7.x:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ajax.<span style="color: #202020;">googleapis</span>.<span style="color: #202020;">com</span><span style="color: #339933;">/</span>ajax<span style="color: #339933;">/</span>libs<span style="color: #339933;">/</span>jquery<span style="color: #339933;">/</span><span style="color:#800080;">1.7</span><span style="color: #339933;">/</span>jquery.<span style="color: #202020;">min</span>.<span style="color: #202020;">js</span>
&nbsp;
ajax.<span style="color: #202020;">googleapis</span>.<span style="color: #202020;">com</span><span style="color: #339933;">/</span>ajax.<span style="color: #202020;">libs</span><span style="color: #339933;">/</span>jquery<span style="color: #339933;">/</span>1.7.2<span style="color: #339933;">/</span>jquery.<span style="color: #202020;">min</span>.<span style="color: #202020;">js</span></pre></div></div>

<p>When you first discover this &#8220;latest version&#8221; feature, it seems clever. Whether you want to keep your site&#8217;s jQuery reference up to date automatically or don&#8217;t feel like typing the couple extra characters, using the less-specific references may be appealing. However, <strong>if you care at all about your site&#8217;s performance, you should not use this feature</strong>.</p>
<p>Since the abbreviated references return the same content, you may be wondering why it matters whether you use the 1.8 or 1.8.0 URL variation. Caching is the key.</p>
<h3>Caching makes the web go &#8217;round (faster)</h3>
<p>If you&#8217;re interested in web performance, you&#8217;ve probably already heard of <a href="http://developer.yahoo.com/performance/rules.html#expires" target="_blank">far-future caching headers as a best practice</a>. In the struggle against lethargic load times, good caching is one of the most potent tools in your arsenal.</p>
<p>As it turns out, that far-future caching mechanism is at the crux of why a fully-qualified version number is important in references to jQuery on the Google CDN. So, it&#8217;s worth talking about exactly how that works.</p>
<h4>Better than nothing: 304 &#8220;Not Modified&#8221;</h4>
<p>Even without special caching instructions, browsers automatically cache local copies of static files, like jQuery, that they download in the course of rendering pages. To speed up subsequent visits, they then attempt to use those local copies instead of downloading the same file over and over again. However, without any knowledge of how long each file is okay to reuse before it has been updated, the browser needs to check in with the server before it uses that local copy.</p>
<p>When your browser makes a request for static content that it has cached locally, it also adds an <code>If-Modified-Since</code> HTTP header to the request. That header essentially gives the server an opportunity to indicate whether or not the resource has been changed since that timestamp.</p>
<p>If that <code>If-Modified-Since</code> header that the browsers sends is more recent than the file&#8217;s last modified timestamp on the server, then the server can return a response of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5" target="_blank">304 &#8220;Not Modified&#8221;</a> instead of sending the file back at all. When the browser receives that 304 response, it will then load the file from its local cache instead of retrieving it from the server.</p>
<p>When you&#8217;re dealing with large assets, a 304 response can save significant amounts of download time. Unfortunately, with a file as small as jQuery, <strong>the ceremony necessary to retrieve that 304 response is nearly as time consuming as just downloading the file in the first place</strong>.</p>
<h4>Best: Far-future caching</h4>
<p>Eliminating the inefficient 304 &#8220;Not Modified&#8221; handshake is where far-future expires and cache-control headers come into play.</p>
<p>Returning those HTTP headers along with a resource allows you to pre-authorize the browser to reuse that content again for some period of time in the future when it encounters a reference to the same URL. Taking advantage of that mechanism <strong>empowers the browser to skip the request for a 304 check entirely and immediately use its cached copy from disk if available</strong>.</p>
<p>Even when you apply far-future caching to site-specific content served from your own servers, <a href="http://www.webpagetest.org/result/120821_VQ_CS5/" target="_blank">the impact on a visitor&#8217;s repeat page views can be dramatic</a>. Applied to a public CDN, where <em>many</em> sites reference the same URL for popular scripts like jQuery, a far-future expires header means that browsers can go weeks or months between requests for a particular version of the asset.</p>
<h3>Too much caching: Not always a good thing</h3>
<p>With that performance difference in mind, it obviously makes sense to take full advantage of far-future caching for relatively static content like jQuery.</p>
<p>However, far-future caching isn&#8217;t without its drawbacks. The same mechanism that makes it great for performance can also be a troublemaker when you instruct browsers to aggressively cache content that is eventually updated.</p>
<p>Imagine what would happen if your site served up <code>/scripts/jquery.js</code> with an expires header indicating that it was cacheable for one year. That would be great for performance initially, but <strong>what happens when a newer version of jQuery is released?</strong></p>
<p>If you replaced that same file with the new version of jQuery when it was released, browsers that had visited your site before the change would continue using their older, cached version of jQuery. Since the whole point of far-future caching is that browsers don&#8217;t need to check for a 304 &#8220;Not Modified&#8221;, browsers with older copies of the file would never know their cache was stale.</p>
<p>On the other hand, visitors with empty caches would download the newer version of the file from your server and then begin caching that revision of it for the one year expires period.</p>
<p>In other words, using a single URL for multiple versions of a well-cached script means you can never be sure that any two given users were viewing your page with the same version of that script. The only solutions are to decrease caching, which impacts performance, or use unique URLs for each version of the script.</p>
<h3>So, how does that affect the Google CDN?</h3>
<p>As you&#8217;re probably realizing, you can&#8217;t serve a constantly evolving library like jQuery from a single URL <em>and</em> use optimal expires headers. When you&#8217;re serving evolving content through a single URL, you have to make a choice between performance (longer browser cache invalidation) and reliability (quicker expiration so new versions roll out evenly).</p>
<p>Taking a look at the HTTP headers that the Google CDN sends back with the 1.8 and 1.8.0 URLs, you can see that they choose a point dramatically on the reliability end of that spectrum.</p>
<h4>&#8220;Latest Version&#8221;</h4>
<p>First, let&#8217;s look at the &#8220;latest version&#8221; reference for jQuery 1.8.x. That&#8217;s the most recent minor revision of jQuery as I&#8217;m writing this and a reference to 1.8 returns a copy of jQuery 1.8.0.</p>
<p>Looking in the network section of Chrome&#8217;s developer tools, these are the HTTP headers returned with a &#8220;latest version&#8221; request to the CDN:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/08/cdn-headers-jquery-1.8.png" rel="attachment"><img class="full-width" src="http://encosia.com/blog/wp-content/uploads/2012/08/cdn-headers-jquery-1.8-sm.png" alt="The HTTP response headers that come back from a request to the 1.8 latest version reference" width="490" height="119" /></a></p>
<p>In an attempt to minimize inconsistencies when a new version (like 1.8.1) rolls out, the 1.8 reference is served with a meager 3,600 second cache expiration. That&#8217;s just one hour of caching.</p>
<p>The Cache-Control header returned with the &#8220;latest version&#8221; response even bolsters that conservative cache timeout with additional revalidate directives. <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4" target="_blank">Those directives</a> instruct intermediate agents like caching proxies that they should not attempt to cache this resource more aggressively than stated.</p>
<h4>Fully qualified</h4>
<p>Now, let&#8217;s request exactly the same jQuery 1.8.0 content, but use the fully qualified 1.8.0 URL:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2012/08/cdn-headers-jquery-1.8.0.png" rel="attachment"><img class="full-width" src="http://encosia.com/blog/wp-content/uploads/2012/08/cdn-headers-jquery-1.8.0-sm.png" alt="The HTTP response headers that come back from a request to 1.8.0 specifically" width="490" height="119" /></a></p>
<p>Since requests to this URL will never return different content in the future, the CDN safely instructs the browser that it can continue using this same copy of the file for up to <em>31,536,000 seconds</em>. If you don&#8217;t have a calculator handy, <strong>that&#8217;s one full year, or 8,760 times longer than the &#8220;latest version&#8221; URL</strong>.</p>
<h3>Conclusion</h3>
<p>One of the greatest strengths of using a popular public CDN to serve jQuery is that <a href="http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/#caching">your users may already have the library cached</a> as a result of visiting another site that references the same URL your site does. When you use the &#8220;latest version&#8221; reference, you almost completely eliminate that possibility. The chances of a cross-site cache hit within one year are great. Within one hour? Good luck.</p>
<p>Clever as the &#8220;latest version&#8221; feature might seem at first, <strong>you should never use one of these partial version references in production</strong>.</p>
<p>In closing, I hope that I&#8217;ve convinced you just how important it is to use a fully qualified references to scripts on the Google CDN. Go forth and enjoy the best caching possible!</p>
<hr />

<p>You've been reading <a href="http://encosia.com/the-crucial-0-in-google-cdn-references-to-jquery-1-x-0/">The crucial .0 in Google CDN references to jQuery 1.x.0</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/the-crucial-0-in-google-cdn-references-to-jquery-1-x-0/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/6953-reasons-why-i-still-let-google-host-jquery-for-me/' rel='bookmark' title='6,953 reasons why I still let Google host jQuery for me'>6,953 reasons why I still let Google host jQuery for me</a></li>
<li><a href='http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/' rel='bookmark' title='3 reasons why you should let Google host jQuery for you'>3 reasons why you should let Google host jQuery for you</a></li>
<li><a href='http://encosia.com/cripple-the-google-cdns-caching-with-a-single-character/' rel='bookmark' title='Cripple the Google CDN&#8217;s caching with a single character'>Cripple the Google CDN&#8217;s caching with a single character</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=EL7q6KNge6E:aPFWBpFhrFs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=EL7q6KNge6E:aPFWBpFhrFs:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=EL7q6KNge6E:aPFWBpFhrFs:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=EL7q6KNge6E:aPFWBpFhrFs:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/EL7q6KNge6E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/the-crucial-0-in-google-cdn-references-to-jquery-1-x-0/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://encosia.com/the-crucial-0-in-google-cdn-references-to-jquery-1-x-0/</feedburner:origLink></item>
		<item>
		<title>Read my article about HTML5 Polyfills on Script Junkie</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/JsRQHVhM2PE/</link>
		<comments>http://encosia.com/read-my-article-about-html5-polyfills-on-script-junkie/#comments</comments>
		<pubDate>Fri, 10 Aug 2012 14:22:13 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1379</guid>
		<description><![CDATA[If you&#8217;re (like me) still working on projects that must work in browsers without great support for HTML5, you might be interested in this article I recently wrote for MSDN&#8217;s Script Junkie. It doesn&#8217;t go deep into particular implementations, but focuses more on what a polyfill is, why a polyfill is more useful than an [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/read-my-interview-with-the-code-project/' rel='bookmark' title='Read my interview with The Code Project'>Read my interview with The Code Project</a></li>
<li><a href='http://encosia.com/review-the-best-javascript-book-i%e2%80%99ve-read/' rel='bookmark' title='Review: The best JavaScript book I’ve read'>Review: The best JavaScript book I’ve read</a></li>
<li><a href='http://encosia.com/how-you-can-force-the-ajax-script-loader-to-use-jquery-1-4/' rel='bookmark' title='How you can force the Ajax Script Loader to use jQuery 1.4'>How you can force the Ajax Script Loader to use jQuery 1.4</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;re (like me) still working on projects that must work in browsers without great support for HTML5, you might be interested in this article I recently wrote for MSDN&#8217;s Script Junkie. It doesn&#8217;t go deep into particular implementations, but focuses more on what a polyfill is, why a polyfill is more useful than an arbitrary JavaScript utility library, and then does into a few concrete examples.</p>
<blockquote><p>Taking advantage of HTML5 in real-world sites and applications can be a daunting proposition. Though modern browsers are implementing HTML5&#8242;s new features at a rapid pace, few of us are lucky enough to write applications supporting only the latest crop of browsers. As a professional web developer, that browser fragmentation forces you to spend significant effort navigating the uncomfortable space between the promise of the future and the realities of the present. The good news is that Internet Explorer 10 and 9 support HTML5.  Users are also leaving older versions of Internet Explorer.  But the share of older versions is likely to remain just enough for developers to support in the foreseeable future.</p>
<p>However, that doesn’t mean you have to give up on supporting HTML5 in the near term. Just as there are techniques for a site to gracefully support variances like multiple screen sizes and different levels of CSS capability, it’s also possible to achieve surprisingly robust cross-browser HTML5 support. Even though older browsers lack many of HTML5’s new APIs, JavaScript is an incredibly flexible language and exposes opportunities to retroactively add new features when they aren’t natively present.</p></blockquote>
<p><a href="http://msdn.microsoft.com/en-us/magazine/jj131727.aspx" target="_blank" class="more-link">Continue reading HTML5 Now: Getting More Through Polyfills on MSDN »</a></p>
<hr />

<p>You've been reading <a href="http://encosia.com/read-my-article-about-html5-polyfills-on-script-junkie/">Read my article about HTML5 Polyfills on Script Junkie</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/read-my-article-about-html5-polyfills-on-script-junkie/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/read-my-interview-with-the-code-project/' rel='bookmark' title='Read my interview with The Code Project'>Read my interview with The Code Project</a></li>
<li><a href='http://encosia.com/review-the-best-javascript-book-i%e2%80%99ve-read/' rel='bookmark' title='Review: The best JavaScript book I’ve read'>Review: The best JavaScript book I’ve read</a></li>
<li><a href='http://encosia.com/how-you-can-force-the-ajax-script-loader-to-use-jquery-1-4/' rel='bookmark' title='How you can force the Ajax Script Loader to use jQuery 1.4'>How you can force the Ajax Script Loader to use jQuery 1.4</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=JsRQHVhM2PE:zJeupiaD4oE:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=JsRQHVhM2PE:zJeupiaD4oE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=JsRQHVhM2PE:zJeupiaD4oE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=JsRQHVhM2PE:zJeupiaD4oE:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/JsRQHVhM2PE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/read-my-article-about-html5-polyfills-on-script-junkie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://encosia.com/read-my-article-about-html5-polyfills-on-script-junkie/</feedburner:origLink></item>
		<item>
		<title>Scott Hanselman and I talk about Web APIs, #!, and more</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/UBf8afDvDcg/</link>
		<comments>http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/#comments</comments>
		<pubDate>Wed, 11 Jul 2012 15:24:43 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1367</guid>
		<description><![CDATA[Scott Hanselman recently invited me onto Hanselminutes to talk about Web APIs, &#8220;hashbang&#8221; URLs, CDNs, and web performance in general. In the turmoil around having a mid-week holiday here in the US, I hadn&#8217;t even noticed that the episode went live last week. It&#8217;s more of an open-ended conversation than us talking about the details [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/hear-us-talk-about-javascript-on-hanselminutes-episode-28/' rel='bookmark' title='Hear us talk about JavaScript on Hanselminutes episode 2^8'>Hear us talk about JavaScript on Hanselminutes episode 2^8</a></li>
<li><a href='http://encosia.com/how-30-seconds-dropped-my-bounce-rate-by-78/' rel='bookmark' title='How 30 seconds dropped my bounce rate by 78%'>How 30 seconds dropped my bounce rate by 78%</a></li>
<li><a href='http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/' rel='bookmark' title='Hear me talk about drama on This Developer&#8217;s Life'>Hear me talk about drama on This Developer&#8217;s Life</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p><a href="http://hanselman.com" target="_blank">Scott Hanselman</a> recently invited me onto <a href="http://hanselminutes.com/" target="_blank">Hanselminutes</a> to talk about Web APIs, &#8220;hashbang&#8221; URLs, CDNs, and web performance in general. In the turmoil around having a mid-week holiday here in the US, I hadn&#8217;t even noticed that the episode went live last week.</p>
<p>It&#8217;s more of an open-ended conversation than us talking about the details of a particular technology. So, we&#8217;d both welcome you joining the conversation in the comments there on Scott&#8217;s post.</p>
<p><a href="http://hanselminutes.com/326/javascript-web-apis-performance-and-more-with-dave-ward" target="_blank">Click here to head over to the Hanselminutes website</a>, give it a listen, and let us know what you think.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/">Scott Hanselman and I talk about Web APIs, #!, and more</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/hear-us-talk-about-javascript-on-hanselminutes-episode-28/' rel='bookmark' title='Hear us talk about JavaScript on Hanselminutes episode 2^8'>Hear us talk about JavaScript on Hanselminutes episode 2^8</a></li>
<li><a href='http://encosia.com/how-30-seconds-dropped-my-bounce-rate-by-78/' rel='bookmark' title='How 30 seconds dropped my bounce rate by 78%'>How 30 seconds dropped my bounce rate by 78%</a></li>
<li><a href='http://encosia.com/hear-me-talk-about-drama-on-this-developers-life/' rel='bookmark' title='Hear me talk about drama on This Developer&#8217;s Life'>Hear me talk about drama on This Developer&#8217;s Life</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=UBf8afDvDcg:bE5SkHkVspQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=UBf8afDvDcg:bE5SkHkVspQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=UBf8afDvDcg:bE5SkHkVspQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=UBf8afDvDcg:bE5SkHkVspQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/UBf8afDvDcg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/</feedburner:origLink></item>
		<item>
		<title>Expand and collapse jQuery Mobile collapsibles from code</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/F__LnUZgnzQ/</link>
		<comments>http://encosia.com/expand-and-collapse-jquery-mobile-collapsibles-from-code/#comments</comments>
		<pubDate>Thu, 28 Jun 2012 16:54:29 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[jQuery Mobile]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1364</guid>
		<description><![CDATA[I recently needed to open and close a jQuery Mobile collapsible widget from my own JavaScript code, in response to other events on the page. Unfortunately, looking at the documentation for the collapsible widget&#8217;s public methods, where you&#8217;d expect to find expand and collapse methods, you won&#8217;t find much help: Manually firing a click on the [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/why-phonegap-1-1-0-broke-jquery-mobiles-back-button/' rel='bookmark' title='Why PhoneGap 1.1.0 broke jQuery Mobile&#8217;s back button'>Why PhoneGap 1.1.0 broke jQuery Mobile&#8217;s back button</a></li>
<li><a href='http://encosia.com/learn-from-my-express-js-http-status-code-blunder/' rel='bookmark' title='Learn from my Express.js HTTP status code blunder'>Learn from my Express.js HTTP status code blunder</a></li>
<li><a href='http://encosia.com/read-my-interview-with-the-code-project/' rel='bookmark' title='Read my interview with The Code Project'>Read my interview with The Code Project</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>I recently needed to open and close a jQuery Mobile collapsible widget from my own JavaScript code, in response to other events on the page. Unfortunately, looking at <a href="http://jquerymobile.com/test/docs/content/content-collapsible-methods.html" target="_blank">the documentation for the collapsible widget&#8217;s public methods</a>, where you&#8217;d expect to find expand and collapse methods, you won&#8217;t find much help:</p>
<p><img class="full-width" title="jquery-mobile-collapsible-methods" src="http://encosia.com/blog/wp-content/uploads/2012/06/jquery-mobile-collapsible-methods.png" alt="" width="490" height="185" /></p>
<p><a href="http://api.jquery.com/click/" target="_blank">Manually firing a click</a> on the collapsible div element is one option, as if the user had tapped it. I&#8217;ve never been a fan of that approach though, and especially not in frontend JavaScript. Co-mingling your internal flow control with events that are intended to be triggered by user input is a good way to find yourself with inconsistent issues that are difficult to reproduce and track down.</p>
<p>More importantly, I needed to control whether the widget was expanded or collapsed in this case. So, I really wanted to find a clean way to deterministically open and close the collapsible instead of toggling it. Luckily, there turned out to be an easy, straightforward way to do that.</p>
<h3>Looking under the hood</h3>
<p>A nice thing about interpreted languages like JavaScript is that it&#8217;s easy to take a look at the source for a library you&#8217;re using and find undocumented behaviors when these situations arise. For example, here&#8217;s <a href="https://github.com/jquery/jquery-mobile/blob/1.1-stable/js/jquery.mobile.collapsible.js#L82" target="_blank">the relevant source for jQuery Mobile&#8217;s collapsible widget</a> (as of version 1.1):</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;expand collapse&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span> event <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span>event.<span style="color: #660066;">isDefaultPrevented</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    event.<span style="color: #660066;">preventDefault</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> $this <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      isCollapse <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> event.<span style="color: #660066;">type</span> <span style="color: #339933;">===</span> <span style="color: #3366CC;">&quot;collapse&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        contentTheme <span style="color: #339933;">=</span> o.<span style="color: #660066;">contentTheme</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Lots of CSS style toggling omitted here.</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>The CSS toggling in that event handler is less important than how that handler is triggered. Seeing that the widget bound a couple custom events named &#8220;expand&#8221; and &#8220;collapse&#8221;, it seemed logical that using <a href="http://api.jquery.com/trigger/" target="_blank">jQuery&#8217;s trigger method</a> on the collapsible div might have the same effect.</p>
<p>To test that the solution is really that simple, you can open a page with a collapsible and <a href="http://encosia.com/updated-see-how-i-used-firebug-to-learn-jquery/">experiment from that browser&#8217;s JavaScript console</a>. That approach is great for testing JavaScript ideas in any browser, but I used Chrome since it&#8217;s based on the same rendering engine that my jQuery Mobile site was targeting.</p>
<p>Sure enough, selecting a collapsible div and chaining <code>.trigger('expand')</code> or <code>.trigger('collapse')</code> opened and closed the widget just as if a user had clicked on the collapsible&#8217;s heading.</p>
<h3>Pulling the &#8220;trigger&#8221;</h3>
<p>To give you a more concrete example of how that works, here&#8217;s an excerpt of a simple jQuery Mobile page with two collapsibles on it:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>div id<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;collapsible1&quot;</span> data<span style="color: #339933;">-</span>role<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;collapsable&quot;</span><span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>p<span style="color: #339933;">&gt;</span>Collapsible <span style="color: #CC0000;">1</span><span style="color: #339933;">&lt;/</span>p<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>div<span style="color: #339933;">&gt;</span>
&nbsp;
<span style="color: #339933;">&lt;</span>div id<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;collapsible2&quot;</span> data<span style="color: #339933;">-</span>role<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;collapsible&quot;</span><span style="color: #339933;">&gt;</span>
  <span style="color: #339933;">&lt;</span>p<span style="color: #339933;">&gt;</span>Collapsible <span style="color: #CC0000;">2</span><span style="color: #339933;">&lt;/</span>p<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;/</span>div<span style="color: #339933;">&gt;</span></pre></div></div>

<p>Given those two widgets, you could use this JavaScript to select the first one and ensure that it&#8217;s expanded:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#collapsible1'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">trigger</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'expand'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Similarly, you could use this code to force the second one to be collapsed:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#collapsible2'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">trigger</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'collapse'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Nice and easy. Now we have complete control over the collapsible instead of being limited to a toggle operation.</p>
<p>Of course, since this is an undocumented behavior, there&#8217;s no guarantee this will continue working in future versions of jQuery Mobile. However, it seems straightforward enough that it&#8217;s unlikely to change in the near future.</p>
<hr />

<p>You've been reading <a href="http://encosia.com/expand-and-collapse-jquery-mobile-collapsibles-from-code/">Expand and collapse jQuery Mobile collapsibles from code</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/expand-and-collapse-jquery-mobile-collapsibles-from-code/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/why-phonegap-1-1-0-broke-jquery-mobiles-back-button/' rel='bookmark' title='Why PhoneGap 1.1.0 broke jQuery Mobile&#8217;s back button'>Why PhoneGap 1.1.0 broke jQuery Mobile&#8217;s back button</a></li>
<li><a href='http://encosia.com/learn-from-my-express-js-http-status-code-blunder/' rel='bookmark' title='Learn from my Express.js HTTP status code blunder'>Learn from my Express.js HTTP status code blunder</a></li>
<li><a href='http://encosia.com/read-my-interview-with-the-code-project/' rel='bookmark' title='Read my interview with The Code Project'>Read my interview with The Code Project</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=F__LnUZgnzQ:ZTytdLA6t-k:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=F__LnUZgnzQ:ZTytdLA6t-k:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=F__LnUZgnzQ:ZTytdLA6t-k:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=F__LnUZgnzQ:ZTytdLA6t-k:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/F__LnUZgnzQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/expand-and-collapse-jquery-mobile-collapsibles-from-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://encosia.com/expand-and-collapse-jquery-mobile-collapsibles-from-code/</feedburner:origLink></item>
		<item>
		<title>ASP.NET Web API vs. ASP.NET MVC “APIs”</title>
		<link>http://feeds.encosia.com/~r/Encosia/~3/gVkpC5ekZiM/</link>
		<comments>http://encosia.com/asp-net-web-api-vs-asp-net-mvc-apis/#comments</comments>
		<pubDate>Wed, 20 Jun 2012 18:51:55 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[Web API]]></category>

		<guid isPermaLink="false">http://encosia.com/?p=1358</guid>
		<description><![CDATA[I&#8217;ve been receiving lots of emails asking my opinion about ASP.NET Web API lately. One of the most recent messages boiled them all down pretty well in its subject line: ASP.NET Web API &#8211; Why is it so cool? That&#8217;s a great question. Too many of the answers to that question come down to subjective, [...]<div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href='http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/' rel='bookmark' title='Scott Hanselman and I talk about Web APIs, #!, and more'>Scott Hanselman and I talk about Web APIs, #!, and more</a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve been receiving lots of emails asking my opinion about ASP.NET Web API lately. One of the most recent messages boiled them all down pretty well in its subject line:</p>
<blockquote><p>ASP.NET Web API &#8211; Why is it so cool?</p></blockquote>
<p>That&#8217;s a great question.</p>
<p>Too many of the answers to that question come down to subjective, personal preference. Worse, you&#8217;ll often hear that it&#8217;s what you should use simply because it&#8217;s the new thing Microsoft is pushing (you know, like WCF once was). If you&#8217;re already making good use of ASP.NET MVC&#8217;s controller actions as a makeshift API, just hearing that Web API is &#8220;better&#8221; might not be all that compelling.</p>
<p>However, <strong>I think Web API objectively wins out over MVC controller APIs in a few key areas</strong>. In this post, I&#8217;ll cover why these three aspects of ASP.NET Web API make it a clear choice for my ASP.NET-based APIs going forward:</p>
<ul>
<li>Content negotiation</li>
<li>Flexibility</li>
<li>Separation of concerns</li>
</ul>
<h3>Content negotiation</h3>
<p>Content negotiation is one of those features that can seem overwrought at first glance. The technical demos we&#8217;ve seen most often, returning content like images and vcards based on the Accept header, are neat, but not something you&#8217;re likely to need on a daily basis.</p>
<p>However, content negotiation is still a nice feature even if you only expect to return a single type of serialization. Why? Because it decouples your API code&#8217;s intent from the mechanics of serialization.</p>
<p>For example, which would you rather write and maintain?</p>
<h4>ASP.NET MVC</h4>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> TweetsController <span style="color: #008000;">:</span> Controller <span style="color: #000000;">&#123;</span>
  <span style="color: #008080; font-style: italic;">// GET: /Tweets/</span>
  <span style="color: #000000;">&#91;</span>HttpGet<span style="color: #000000;">&#93;</span>
  <span style="color: #0600FF;">public</span> ActionResult Index<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">return</span> Json<span style="color: #000000;">&#40;</span>Twitter.<span style="color: #0000FF;">GetTweets</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, JsonRequestBehavior.<span style="color: #0000FF;">AllowGet</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<h4>ASP.NET Web API</h4>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> TweetsController <span style="color: #008000;">:</span> ApiController <span style="color: #000000;">&#123;</span>
  <span style="color: #008080; font-style: italic;">// GET: /Api/Tweets/</span>
  <span style="color: #0600FF;">public</span> List<span style="color: #008000;">&lt;</span>Tweet<span style="color: #008000;">&gt;</span> Get<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">return</span> Twitter.<span style="color: #0000FF;">GetTweets</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>The choice between those two options is an easy one for me. Not only is the return value of <code>List&lt;Tweet&gt;</code> more expressive (especially when you revisit this code in a year or two), but letting Web API handle the serialization means you don&#8217;t need to clutter the action up with the <code>Json()</code> code.</p>
<p>Of course, you never know when it might be helpful someday for that same endpoint to support returning its data as XML, <a href="http://www.tugberkugurlu.com/archive/creating-custom-csvmediatypeformatter-in-asp-net-web-api-for-comma-separated-values-csv-format" target="_blank">CSV</a>, MessagePack, or some future serialization format. Content negotiation makes adding that across an entire API relatively simple with Web API, but it would be cumbersome to update a plethora of MVC controller actions.</p>
<h3>Flexibility</h3>
<p>It&#8217;s clear that flexibility was a central goal in Web API (without resorting to the configuration tedium that burdened WCF). Content negotiation is a great example of that, but that&#8217;s only the beginning. Web API starts with sensible defaults, but then provides a <code>GlobalConfiguration</code> object that you can use to tweak a wide range of options.</p>
<p>A couple more concrete examples:</p>
<h4>Down with XML!</h4>
<p>One initially disconcerting thing about Web API is that hitting an endpoint in your browser will result in an XML response. That&#8217;s correct behavior because regular requests in browsers usually send an Accept header preferring text/html and application/xml, but not JSON.</p>
<p>If you want to bring Web API&#8217;s behavior more in line with the output of MVC&#8217;s <code>Json()</code> helper, you can remove XML support from your API entirely. Just add this to the <code>Application_Start</code> event and you&#8217;ll never see XML again:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// Normally, you'd probably be doing this in a setup method that</span>
<span style="color: #008080; font-style: italic;">// accepts the configuration as a parameter and this line wouldn't</span>
<span style="color: #008080; font-style: italic;">// be necessary, but you can do it right in Application_Start too.</span>
var config <span style="color: #008000;">=</span> GlobalConfiguration.<span style="color: #0000FF;">Configuration</span><span style="color: #008000;">;</span>
&nbsp;
config.<span style="color: #0000FF;">Formatters</span>.<span style="color: #0000FF;">Remove</span><span style="color: #000000;">&#40;</span>config.<span style="color: #0000FF;">Formatters</span>.<span style="color: #0000FF;">XmlFormatter</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>

<p>Now, even if a client&#8217;s Accept header prefers XML over JSON, Web API won&#8217;t respond with XML. Personally, I&#8217;d prefer to see Web API prefer JSON over XML by default, but it&#8217;s great that Web API is flexible enough to allow these global changes with a minimum of configuration ceremony.</p>
<h4>Tweaking your API&#8217;s JSON format</h4>
<p>You&#8217;re generally stuck with the JSON that <code>JavaScriptSerializer</code> wants to generate when you use MVC&#8217;s <code>Json()</code> helper. Luckily, JSS does a pretty good job of creating sane JSON, but it also opts you into some unusual conventions like &#8220;MSAjax&#8221; date encoding instead of the more common ISO format.</p>
<p>Web API and Json.NET allow you to tweak the JSON that your API produces very easily. For example, Json.NET defaults to using ISO dates, but you can switch that to the Microsoft format for backwards compatibility across your entire API with a simple configuration setting:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// Separate statements for purposes of fitting within my tiny</span>
<span style="color: #008080; font-style: italic;">// 492px code blocks. You could do this on one line if you wanted.</span>
var js <span style="color: #008000;">=</span> GlobalConfiguration.<span style="color: #0000FF;">Configuration</span>.<span style="color: #0000FF;">Formatters</span>.<span style="color: #0000FF;">JsonFormatter</span><span style="color: #008000;">;</span>
&nbsp;
var dfh <span style="color: #008000;">=</span> js.<span style="color: #0000FF;">SerializerSettings</span>.<span style="color: #0000FF;">DateFormatHandling</span><span style="color: #008000;">;</span>
&nbsp;
dfh <span style="color: #008000;">=</span> Newtonsoft.<span style="color: #0000FF;">Json</span>.<span style="color: #0000FF;">DateFormatHandling</span>.<span style="color: #0000FF;">MicrosoftDateFormat</span><span style="color: #008000;">;</span></pre></div></div>

<p>There&#8217;s a wide range of options you can set this way, from &#8220;pretty printing&#8221; the JSON to support for automatic translation between camelCase and PascalCase. For more examples, see <a href="http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization" target="_blank">this article on the ASP.NET site</a>.</p>
<h3>Separation of concerns</h3>
<p>All of the preceding examples highlight one of my favorite overall advantages of using Web API. It&#8217;s possible to quickly drop these high-impact changes in across an entire API largely because <strong>Web API helps separate your API from the part of your project that returns HTML</strong>.</p>
<p>MVC controller actions are optimized for building up an HTML document through the use of things like views, partial views, and HTML helpers. That whole pipeline doesn&#8217;t really make sense in the context of an API that returns entities, DTOs, or ViewModels, and I think it&#8217;s valuable to keep them separate.</p>
<h4>So separate, it&#8217;s not tied to a website at all</h4>
<p>In fact, you may eventually want to isolate API from your website to the point that it doesn&#8217;t even make sense to host the API within the same project. With Web API, you can self-host the same API code in a Windows Service or even a console app.</p>
<p>You <em>could</em> do that with an ASP.NET MVC &#8220;API&#8221; by creating a separate project for the API, but then you&#8217;re still paying the performance penalty for your API requests to filter through MVC&#8217;s rendering pipeline. In simple load testing on my local machine, I&#8217;ve found that Web API endpoints hosted in console apps are nearly 50% faster than both ASP.NET controller actions <em>and</em> Web API endpoints hosted within MVC projects.</p>
<p>It&#8217;s great to have that low-cost, high-performance option as usage of your API grows. <strong>Starting with Web API means you&#8217;re not tied to ASP.NET MVC (or any web framework) in the future</strong>. It&#8217;s quick and easy to migrate an MVC-hosted Web API to a centralized project of its own as your needs organically grow.</p>
<h3>Conclusion</h3>
<p>These are the three main reasons why I&#8217;m using Web API controllers for client-side callbacks in my ASP.NET MVC projects going forward. Even though many of those &#8220;APIs&#8221; will never grow into more than endpoints for AJAX callbacks, using Web API for those endpoints is still easier and more flexible than other built-in alternatives.</p>
<p>What do you think? Are you using Web API yet? Do you plan to migrate from MVC controller actions to Web API in the future? Did I miss an aspect of the MVC-centric approach that makes it work better than Web API for you (I can think of one, but I haven&#8217;t seen many projects actually doing this in the real-world anymore)?</p>
<hr />

<p>You've been reading <a href="http://encosia.com/asp-net-web-api-vs-asp-net-mvc-apis/">ASP.NET Web API vs. ASP.NET MVC &#8220;APIs&#8221;</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>

<p>If you've got any feedback, please click through and leave a comment; I'd love to hear from you. You can <a href="http://encosia.com/asp-net-web-api-vs-asp-net-mvc-apis/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p><div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href='http://encosia.com/hear-scott-hanselman-and-i-talk-about-web-apis-and-more/' rel='bookmark' title='Scott Hanselman and I talk about Web APIs, #!, and more'>Scott Hanselman and I talk about Web APIs, #!, and more</a></li>
</ol></p>
</div>
<div class="feedflare">
<a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=gVkpC5ekZiM:UA1XMVscysg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=gVkpC5ekZiM:UA1XMVscysg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=gVkpC5ekZiM:UA1XMVscysg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=gVkpC5ekZiM:UA1XMVscysg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Encosia/~4/gVkpC5ekZiM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://encosia.com/asp-net-web-api-vs-asp-net-mvc-apis/feed/</wfw:commentRss>
		<slash:comments>59</slash:comments>
		<feedburner:origLink>http://encosia.com/asp-net-web-api-vs-asp-net-mvc-apis/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 2.452 seconds. --><!-- Cached page generated by WP-Super-Cache on 2013-05-23 10:01:20 -->
