<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>David Calhoun&#039;s Blog</title>
	<atom:link href="http://davidbcalhoun.com/feed" rel="self" type="application/rss+xml" />
	<link>http://davidbcalhoun.com</link>
	<description>Just another blog</description>
	<lastBuildDate>Mon, 07 May 2012 02:06:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Why is Philosophy still important?</title>
		<link>http://davidbcalhoun.com/2012/why-is-philosophy-still-important</link>
		<comments>http://davidbcalhoun.com/2012/why-is-philosophy-still-important#comments</comments>
		<pubDate>Mon, 07 May 2012 02:06:20 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[philosophy]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=884</guid>
		<description><![CDATA[This was posted on reddit recently, so I thought I&#8217;d copy my response here. First, just a quick introduction! There&#8217;s been a lot of thought recently that philosophy is useless. The main arguments seem to be that science has replaced any need for philosophy philosophy is a useless subject to study in college For the [...]]]></description>
			<content:encoded><![CDATA[<p>This was posted on <a href="http://www.reddit.com/r/philosophy/comments/sw0t2/why_is_philosophy_still_important/">reddit</a> recently, so I thought I&#8217;d copy my response here.</p>
<p>First, just a quick introduction!  There&#8217;s been a lot of thought recently that philosophy is useless.  The main arguments seem to be that</p>
<ol>
<li>science has replaced any need for philosophy</li>
<li>philosophy is a useless subject to study in college</li>
</ol>
<p>For the latter argument, I recently recorded my thoughts, <a href="http://davidbcalhoun.com/b/2012-03-17-the-value-of-a-philosophy-degree.mp3">and you can hear them here</a>.  For the first argument, read on&#8230;</p>
<p>In short: science helps us live longer, whereas philosophy helps us live better.</p>
<p>It&#8217;s true that there&#8217;s a lot of philosophy that is very academic and not so useful, but at its core, philosophy is a striving towards figuring out what is true and worthwhile, and what it means to live a meaningful and worthwhile life. That&#8217;s something off-limits for science, because science can tell us how things are empirically, but it can&#8217;t prescribe how we should then live.</p>
<p>It so happens that we already believe many things to be true and have many attitudes and dispositions towards things, whether we realize it or not. That&#8217;s what you might call a person&#8217;s personal philosophy. A person may hate philosophy, but it would be true to say that their &#8220;anti-philosophy&#8221; is a type of philosophy. In short, we all have a philosophy already. Shouldn&#8217;t we then examine it logically and try to improve it, and make sure it gets closer to the truth?</p>
<p>It also happens that our world is saturated with manipulation of people&#8217;s philosophies. Advertisements and an envy of other&#8217;s belongings has saturated our consumer culture and has turned into a sort of philosophy of its own, and sadly a way of life. There&#8217;s also much manipulation of attitudes and thought in politics, which is how politics have turned into a game of image and often times broad, false promises. Money and a lust for fame have also corrupted the sciences to some degree, and have turned it into a bit of a game to get research funding from large corporations, so nothing in the world is off-limits it seems.</p>
<p>Philosophy gives us the tools to recognize these things for what they are, and gives us some defenses against them that the common person might not have. (incidentally, I recommend reading On Bullshit for more of a taste of how our world is saturated in BS)</p>
<p>I believe there&#8217;s a few big reasons philosophy is downplayed and ridiculed in our culture today. The main reason is that there&#8217;s no real way to make it profitable, unlike the sciences. If we&#8217;re living in a consumer culture that assigns some value to things based on money, then naturally we will value less the things which aren&#8217;t profitable. When it comes down to it, we really are living in a culture that values more the computer science graduate who goes to join a company such as Zynga to produce banal (borrowing a favorite word from David Foster Wallace) ripoff games. We value this person more than someone who stays in academia to pursue truth and knowledge, and we ridicule them for not coming out into the real world, working a real job, and making a ton of money, which is after all the highest end according to to our current thinking (which is in itself a philosophy).</p>
<p>I have more to say about all this, but I&#8217;ll keep this short. <img src='http://davidbcalhoun.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>(For a bit of perspective, I&#8217;m saying this as someone who makes way more money than I need working for big corporations doing web dev work, but is looking to go back and study more philosophy in school eventually.)</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2012/why-is-philosophy-still-important/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
<enclosure url="http://davidbcalhoun.com/b/2012-03-17-the-value-of-a-philosophy-degree.mp3" length="5131792" type="audio/mpeg" />
		</item>
		<item>
		<title>New direction (&#8220;Developer Blog&#8221; -&gt; &#8220;Blog&#8221;)</title>
		<link>http://davidbcalhoun.com/2012/new-direction-developer-blog-to-blog</link>
		<comments>http://davidbcalhoun.com/2012/new-direction-developer-blog-to-blog#comments</comments>
		<pubDate>Mon, 07 May 2012 01:54:38 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=881</guid>
		<description><![CDATA[Lately I&#8217;ve come to terms with the fact I need to try something new in my life &#8211; a true change in direction. I anticipate that this blog will take the same direction, so there will likely be less and less &#8220;developer&#8221; posts and more and more posts of me living this new path. (TLDR: [...]]]></description>
			<content:encoded><![CDATA[<p>Lately I&#8217;ve come to terms with the fact I need to try something new in my life &#8211; a true change in direction.  I anticipate that this blog will take the same direction, so there will likely be less and less &#8220;developer&#8221; posts and more and more posts of me living this new path.  (TLDR: unsubscribe now, probably!)</p>
<p>Why the change in direction?  I&#8217;ve had my fun, I&#8217;ve lived a comfortable life where I really haven&#8217;t had to worry about money (yet), but I&#8217;ve learned the hard way that buying &#8220;stuff&#8221; doesn&#8217;t buy happiness.  It&#8217;s trite and it&#8217;s something you always hear, but I guess it&#8217;s something you have to figure out for yourself, the hard way.  I read Walden in high school and thought I&#8217;d learned from its lessons.  But I re-read it recently and came away completely changed.  I can get by with a lot less, and most importantly &#8211; with a more meaningful job that pays much less.</p>
<p>I&#8217;ve worked at a few big companies and become a somewhat competent (and surely incompetent in some ways) frontend web developer.  It&#8217;s a great way to grow right out of college and a really comfortable way to live out on your own for a little while.  It&#8217;s probably a way to continue making a living while supporting a family, but that hasn&#8217;t happened to me yet.</p>
<p>And in any case, it&#8217;s not for me.</p>
<p>At the end of the day I can&#8217;t really say I&#8217;ve made a real difference in the world.  I can work as hard as I can, but at the end of the day I&#8217;m just making websites for entertainment.  Which is not to say there aren&#8217;t good causes out there, I suppose.  And it&#8217;s not to say I can&#8217;t funnel some of this money into good causes, which I&#8217;m been forcing myself to do more and more in very small ways (I seem to be a naturally selfish person, but I&#8217;m trying to get better in that respect).  But I can&#8217;t get past the feeling that my time can be better spent.</p>
<p>Now&#8217;s a fantastic time for web development, with so many opportunities to learn and grow as a developer, and so many opportunities to publish new findings and pioneer new methods.  There will be trailblazers and figureheads, and people making an awesome use of technology.  But it won&#8217;t be me.  I&#8217;m taking steps to make sure of that.</p>
<p>At one time I viewed my web development skill as simply a means to an end &#8211; and only within the past few years has it been considered what philosophers would call &#8220;an end in itself&#8221;.  I picked up this hammer to learn how to build.  For a few years I joined the company of some of the best hammersmiths in the world.  I even attended hammersmith conferences.  But now I&#8217;m resting this hammer down for a little bit of a rest.</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2012/new-direction-developer-blog-to-blog/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Post a status update to the native Facebook app from a web link</title>
		<link>http://davidbcalhoun.com/2012/post-a-status-update-to-the-native-facebook-app-from-a-web-link</link>
		<comments>http://davidbcalhoun.com/2012/post-a-status-update-to-the-native-facebook-app-from-a-web-link#comments</comments>
		<pubDate>Fri, 03 Feb 2012 01:18:48 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=864</guid>
		<description><![CDATA[The skinny Copy this code: &#60;a href=&#34;fb://publish/profile/me?text=foo&#34;&#62;Post to Facebook&#60;/a&#62; Explanation As you may know, Facebook has a URL scheme fb:// which seems to be mainly used by native developers. What most folks don&#8217;t realize is that it&#8217;s just a URL scheme, like http://, and that we can use it within our mobile browsers! The only [...]]]></description>
			<content:encoded><![CDATA[<h3>The skinny</h3>
<p>Copy this code:</p>
<blockquote><p><code>&lt;a href=&quot;fb://publish/profile/me?text=foo&quot;&gt;<a href="fb://publish/profile/me?text=foo">Post to Facebook</a>&lt;/a&gt;</code></p></blockquote>
<h3>Explanation</h3>
<p>As you may know, Facebook has a URL scheme <code>fb://</code> which seems to be mainly used by native developers.  What most folks don&#8217;t realize is that it&#8217;s just a URL scheme, like http://, and that we can use it within our mobile browsers!  The only problem is that there&#8217;s no official documentation for it, so folks have had to hunt down the particulars.</p>
<p>After poking around a bit, you might find <a href="http://stackoverflow.com/questions/5707722/what-are-all-the-custom-url-schemes-supported-by-the-facebook-iphone-app/">this topic on Stackoverflow</a>, which contains a ton of protocols for getting to specific sections of the Facebook app, as well as this interesting snippet:</p>
<blockquote><p><code><a href="fb://publish/profile/#ID#?text=#BODY#">fb://publish/profile/#ID#?text=#BODY#</a></code></p></blockquote>
<p>Trying that as a link does work, but it takes you to this blank screen:</p>
<p><img src="http://davidbcalhoun.com/wp-content/uploads/2012/02/facebook-blank-screen.png" alt="Facebook app - blank screen" title="Facebook app - blank screen" width="320" height="480" class="aligncenter size-full wp-image-878" /></p>
<p>That blank screen isn&#8217;t too exciting, but it is peaceful, like a Zen rock garden.  Bookmark that page so you can come back later, when you&#8217;re overwhelmed by friends flooding your updates screen with baby pictures.</p>
<h3>Google to the rescue!</h3>
<p>Ok, now back to work!</p>
<p>After poking around and trying to find my Facebook id, I inserted it and got the link to work.  But that&#8217;s not ideal, since everyone has different user ids.  And I&#8217;m not about to load in all the bloatware that comes with the Facebook API just to find a user id!</p>
<p>After poking around a bit, I found <a href="http://stackoverflow.com/questions/9077817/open-facebook-app-with-text-from-ipad-app">this link</a> which showed this generic pattern:</p>
<blockquote><p><code><a href="fb://publish/profile/me">fb://publish/profile/me</a></code></p></blockquote>
<p>Whoo!  And that works!  But I still want to prepopulate the status field.  We can do that by passing in a URL parameter:</p>
<blockquote><p><code><a href="fb://publish/profile/me?text=foo">fb://publish/profile/me?text=foo</a></code></p></blockquote>
<p>Clicking on it will get you to a screen which looks like this:</p>
<p><img src="http://davidbcalhoun.com/wp-content/uploads/2012/02/facebook-status-disabled.png" alt="Facebook status update with share button disabled" title="Facebook status update with share button disabled" width="320" height="480" class="aligncenter size-full wp-image-865" /></p>
<p>This, interestingly enough, appears to be the old implementation of the status screen.  Here&#8217;s what it looks like if you launch it through the button on the native app:</p>
<p><img src="http://davidbcalhoun.com/wp-content/uploads/2012/02/facebook-status-normal.png" alt="Facebook status - what it looks like normally" title="Facebook status - what it looks like normally" width="320" height="480" class="aligncenter size-full wp-image-867" /></p>
<p>Also note that the Share button is disabled until the user types in text themselves.  This might be a little confusing for some users, but it&#8217;s probably the best way to prevent spam.</p>
<h3>Detecting if the Facebook app is installed</h3>
<p>There&#8217;s another issue with <em>folks who don&#8217;t have the native Facebook app installed</em>.  There doesn&#8217;t seem to be a perfect way to detect if the link failed and went nowhere.  What we have to work with are <a href="http://stackoverflow.com/questions/7231085/how-to-fall-back-to-marketplace-when-android-custom-url-scheme-not-handled">hacky workarounds involving setTimeout</a>.</p>
<p>It looks like native iOS apps have an ideal URL scheme checking ability with a <a href="http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-working-with-url-schemes/">canOpenURL</a> method.  Unfortunately it doesn&#8217;t look like the web has this function (yet).  Let&#8217;s bug Apple to implement it!  <img src='http://davidbcalhoun.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Related</h3>
<p>Just a heads up &#8211; I&#8217;m definitely not the first one to figure this out, as I found a <a href="http://jsfiddle.net/ThinkingStiff/dpUKh/">jsfiddle</a> with the same information, plus an example for posting to Twitter.  That was surprisingly the only result!  I couldn&#8217;t find anyone who blogged about it yet, so here you are!</p>
<p><a href="http://wiki.akosma.com/IPhone_URL_Schemes">More URI schemes for other launching other native apps</a></p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2012/post-a-status-update-to-the-native-facebook-app-from-a-web-link/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Web development / Silicon Valley rant</title>
		<link>http://davidbcalhoun.com/2011/web-development-silicon-valley-rant</link>
		<comments>http://davidbcalhoun.com/2011/web-development-silicon-valley-rant#comments</comments>
		<pubDate>Sun, 23 Oct 2011 01:41:45 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=844</guid>
		<description><![CDATA[(if you didn&#8217;t read the title &#8211; warning: rant&#8230;) As far as web development goes, I guess I could rant on and on about the generalities. Of all things ephemeral. The lust after money, gadgets, and other worthless material crap that we use to stuff inside our oversized houses. The startling creativity and in equal [...]]]></description>
			<content:encoded><![CDATA[<p>(if you didn&#8217;t read the title &#8211; warning: rant&#8230;)</p>
<p>As far as web development goes, I guess I could rant on and on about the generalities. Of all things ephemeral. The lust after money, gadgets, and other worthless material crap that we use to stuff inside our oversized houses.</p>
<p>The startling creativity and in equal amounts the lack of creativity. The amount of amazing invention and the equal amount of copying and ripping off.</p>
<p>I could complain of amazing shortsightedness, of fads, and of constant new waves of developers that have to relearn and be convinced of old tried-and-true best practices (while still being able to identify the outdated best practices).</p>
<p>I could possibly ponder some of the stupid things we concern ourselves with, which are criticisms more aimed at the Silicon Valley mentality in general. The sheer amount of idiotic startups. The desire to have a startup only for the payout, for the acquisition. The one worthwhile and meaningful startup surrounded in a sea of hangers-ons, social network clones, photo sharing service clones, Facebook game clones, and on and on ad nauseum.</p>
<p>I could complain about the few passionate ones, surrounded by a pool of passionless jumpers-on-the-bandwagon, people looking for a free ride, and people looking to coast through their secure jobs, content with nothing more than receiving their paycheck.</p>
<p>I could complain about the lack of real heroes. People who made a difference to our small isolated communities, spoke at conferences, authored books, wrote popular blog articles, but were perhaps never themselves. People who we could not look up to as model human beings, but as model toolmakers and nothing more. I suppose it&#8217;s folly to look for too much else there anyhow.</p>
<p>I could complain about the praise of life imbalance. Of prideful people showing off, working longer hours than their peers, feeling like they have to in order to keep up, and bragging about losing sleep and becoming unbalanced and unhinged individuals. Competition is good and pushes everyone to be more detailed and more polished, but there seems to be no admission of a limit, of reaching a life imbalance. The more time spent coding, the better. If you don&#8217;t code in your free time, you must not be a true coder. If you don&#8217;t enjoy learning new languages, you must be a crappy coder. The amount of pride and self-delusion here is scary.</p>
<p>I could talk about corporations seeking young programmers without commitments in order to suck dry every last ounce of their passion, essence, and thirst, distracting their focus away from all things important.  Of those same corporations sticking those young impressionables onto outdated projects, maintaining and fixing bugs.  All for what?</p>
<p>I could speak of self-delusion that programming language X will save the world, and on self-delusion in general, which I believe is rampant here and elsewhere, and is possibly our greatest weakness as human beings.</p>
<p>I suppose now you&#8217;ll tell me I&#8217;ve lost my head and gone crazy, but I would disagree. These things have never been so clear and the arguments have never been so cogent as they are now. There is no utopia, no perfect occupation, but I believe there are some that are better than others. Everything has its faults, and web development isn&#8217;t for everyone. Perhaps it&#8217;s simply not for me?</p>
<p>I got into web development as a means to an end &#8211; as a way of publishing what I enjoyed doing. As a tool I picked up and put down when I was finished, and then got on with my life. Perhaps it&#8217;s time to move it back to that corner of my life, and even better, to use it as a tool to help me build new, meaningful, less ephemeral things. Something I could be proud of in more than a few years. Something more than being an &#8220;HTML5 expert&#8221; or &#8220;Mobile expert&#8221; or &#8220;JavaScript expert&#8221;.</p>
<p>No.  I want to use these things as tools that are put back in their shed after I&#8217;m done.  Tools to build something greater than the sum of its parts. Tools to make a meaningful contribution that may not amount to a hill a beans in this crazy world, but could at least be something I&#8217;m proud of.</p>
<blockquote><p>Programming as a profession is only moderately interesting. It can be a good job, but you could make about the same money and be happier running a fast food joint. You&#8217;re much better off using code as your secret weapon in another profession.</p>
<p>People who can code in the world of technology companies are a dime a dozen and get no respect. People who can code in biology, medicine, government, sociology, physics, history, and mathematics are respected and can do amazing things to advance those disciplines.</p>
<p>(<a href="http://learnpythonthehardway.org/book/advice.html">Advice From an Old Programmer</a>)
</p></blockquote>
<p>Somewhat related: <a href="http://ask.slashdot.org/story/05/12/16/1833210/where-do-all-of-the-old-programmers-go">Where Do All of the Old Programmers Go?</a>, <a href="http://vimeo.com/2723800">The ACL is Dead</a>, <a href="http://techcrunch.com/2010/08/28/silicon-valley%E2%80%99s-dark-secret-it%E2%80%99s-all-about-age/">Silicon Valley’s Dark Secret: It’s All About Age</a> [and the <a href="http://www.reddit.com/r/programming/comments/d6kqg/silicon_valleys_dark_secret_its_all_about_age/">disturbing reddit thread to accompany that</a>])</p>
<h3>Addendum</h3>
<p>It&#8217;s notable to add that I&#8217;ve been comparing &#8220;Kyoto culture&#8221; to &#8220;Silicon Valley culture&#8221;.  They are so dissimilar that it&#8217;s doubtful we&#8217;re even using &#8220;culture&#8221; in the same sense in both cases.  Kyoto culture, a long proud, rich, colorful history of a people, and Silicon Valley culture: an atmosphere of tech, founded by money and driven by money.  In one, it&#8217;s almost a crime to stay inside and not to explore and enjoy the city.  In the other, our wealth lets us build up a castle, buy devices and home entertainment to keep us busy in our little fiefdom.  Silicon Valley is more like a boomtown which exists only for one sick purpose, and consequentially lacks a soul even more severely.  Would you rather be underpaid in a city with a soul or overpaid in a soulless city?</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/web-development-silicon-valley-rant/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>iOS5 SunSpider: iPhone 4S vs iPhone 4 vs iPhone 3GS</title>
		<link>http://davidbcalhoun.com/2011/ios5-sunspider-iphone-4s-vs-iphone-4-vs-iphone-3gs</link>
		<comments>http://davidbcalhoun.com/2011/ios5-sunspider-iphone-4s-vs-iphone-4-vs-iphone-3gs#comments</comments>
		<pubDate>Sat, 15 Oct 2011 01:39:14 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=831</guid>
		<description><![CDATA[Result table (SunSpider 0.9.1, all devices running iOS 5) Test iPhone 4S iPhone 4 iPhone 3GS Total 2270ms 3483ms 4903ms 3D 281ms 486ms 672ms Access 279ms 410ms 614ms Bitops 177ms 200ms 270ms Controlflow 20ms 26ms 34ms Crypto 164ms 211ms 315ms Date 332ms 528ms 770ms Math 219ms 433ms 553ms Regexp 88ms 117ms 151ms String 711ms 1072ms [...]]]></description>
			<content:encoded><![CDATA[<h3>Result table (SunSpider 0.9.1, all devices running iOS 5)</h3>
<table>
<thead>
<tr>
<td>Test</td>
<td>iPhone 4S</td>
<td>iPhone 4</td>
<td>iPhone 3GS</td>
</tr>
</thead>
<tfoot></tfoot>
<tbody>
<tr>
<td>Total</td>
<td class="positive">2270ms</td>
<td>3483ms</td>
<td>4903ms</td>
</tr>
<tr>
<td>3D</td>
<td class="positive">281ms</td>
<td>486ms</td>
<td>672ms</td>
</tr>
<tr>
<td>Access</td>
<td class="positive">279ms</td>
</td>
<td>410ms</td>
<td>614ms</td>
</tr>
<tr>
<td>Bitops</td>
<td class="positive">177ms</td>
<td>200ms</td>
<td>270ms</td>
</tr>
<tr>
<td>Controlflow</td>
<td class="positive">20ms</td>
<td>26ms</td>
</td>
<td>34ms</td>
</tr>
<tr>
<td>Crypto</td>
<td class="positive">164ms</td>
<td>211ms</td>
<td>315ms</td>
</tr>
<tr>
<td>Date</td>
<td class="positive">332ms</td>
<td>528ms</td>
<td>770ms</td>
</tr>
<tr>
<td>Math</td>
<td class="positive">219ms</td>
<td>433ms</td>
<td>553ms</td>
</tr>
<tr>
<td>Regexp</td>
<td class="positive">88ms</td>
<td>117ms</td>
<td>151ms</td>
</tr>
<tr>
<td>String</td>
<td class="positive">711ms</td>
<td>1072ms</td>
<td>1525ms</td>
</tr>
</tbody>
</table>
<h3>Raw results</h3>
<p><a href="http://www.webkit.org/perf/sunspider-0.9.1/sunspider-0.9.1/results.html?%7B%22v%22:%20%22sunspider-0.9.1%22,%20%223d-cube%22:%5B98,100,97,101,98,98,99,99,100,105%5D,%223d-morph%22:%5B72,75,72,74,72,74,72,72,72,73%5D,%223d-raytrace%22:%5B107,107,108,111,108,108,108,109,110,108%5D,%22access-binary-trees%22:%5B48,48,53,51,47,49,51,54,52,47%5D,%22access-fannkuch%22:%5B121,120,124,120,121,121,120,120,125,120%5D,%22access-nbody%22:%5B70,72,71,71,71,72,70,70,69,70%5D,%22access-nsieve%22:%5B35,40,38,38,37,35,35,36,38,37%5D,%22bitops-3bit-bits-in-byte%22:%5B29,29,29,28,29,29,29,29,29,29%5D,%22bitops-bits-in-byte%22:%5B39,36,37,39,37,36,36,37,38,37%5D,%22bitops-bitwise-and%22:%5B47,48,48,46,49,48,49,51,48,47%5D,%22bitops-nsieve-bits%22:%5B65,63,62,62,62,62,63,63,63,62%5D,%22controlflow-recursive%22:%5B19,20,20,20,19,20,20,19,20,20%5D,%22crypto-aes%22:%5B94,96,96,100,103,102,96,96,96,99%5D,%22crypto-md5%22:%5B36,37,37,38,37,36,39,36,38,39%5D,%22crypto-sha1%22:%5B29,28,30,28,30,29,29,28,29,29%5D,%22date-format-tofte%22:%5B171,182,167,168,170,172,167,170,181,172%5D,%22date-format-xparb%22:%5B160,159,161,158,160,168,162,156,159,158%5D,%22math-cordic%22:%5B81,79,76,77,77,77,78,77,76,77%5D,%22math-partial-sums%22:%5B92,92,92,92,94,92,92,91,92,94%5D,%22math-spectral-norm%22:%5B49,49,49,49,51,49,49,50,48,52%5D,%22regexp-dna%22:%5B91,87,88,87,88,88,88,87,88,87%5D,%22string-base64%22:%5B89,88,86,92,87,91,96,87,87,87%5D,%22string-fasta%22:%5B91,92,92,91,94,94,95,95,89,89%5D,%22string-tagcloud%22:%5B144,147,147,145,144,145,144,144,148,150%5D,%22string-unpack-code%22:%5B246,243,238,244,254,249,243,249,240,238%5D,%22string-validate-input%22:%5B145,134,136,137,140,137,137,137,141,149%5D%7D">iPhone 4S (iOS5)</a></p>
<p><a href="http://www.webkit.org/perf/sunspider-0.9.1/sunspider-0.9.1/results.html?%7B%22v%22:%20%22sunspider-0.9.1%22,%20%223d-cube%22:%5B175,179,192,175,180,174,181,174,173,182%5D,%223d-morph%22:%5B138,137,136,135,136,135,136,137,144,135%5D,%223d-raytrace%22:%5B166,171,174,174,166,178,168,167,169,168%5D,%22access-binary-trees%22:%5B61,61,62,58,57,56,57,56,60,57%5D,%22access-fannkuch%22:%5B141,142,143,146,141,142,148,142,146,148%5D,%22access-nbody%22:%5B154,152,147,146,144,148,146,154,146,149%5D,%22access-nsieve%22:%5B59,59,57,67,58,60,57,58,59,59%5D,%22bitops-3bit-bits-in-byte%22:%5B29,29,29,28,34,29,28,28,29,28%5D,%22bitops-bits-in-byte%22:%5B40,40,41,40,41,40,42,41,41,41%5D,%22bitops-bitwise-and%22:%5B58,59,60,58,60,58,59,62,58,58%5D,%22bitops-nsieve-bits%22:%5B71,76,70,75,71,69,72,71,70,70%5D,%22controlflow-recursive%22:%5B26,25,25,26,25,26,25,25,26,27%5D,%22crypto-aes%22:%5B124,132,124,124,126,123,123,125,122,127%5D,%22crypto-md5%22:%5B48,48,48,50,50,50,50,50,50,50%5D,%22crypto-sha1%22:%5B36,37,36,35,36,37,36,37,36,36%5D,%22date-format-tofte%22:%5B265,267,265,314,259,260,257,266,263,260%5D,%22date-format-xparb%22:%5B258,265,258,259,265,259,259,264,259,260%5D,%22math-cordic%22:%5B291,141,141,141,147,140,140,141,178,140%5D,%22math-partial-sums%22:%5B174,173,179,180,171,174,171,179,177,171%5D,%22math-spectral-norm%22:%5B102,98,97,98,97,97,99,100,99,98%5D,%22regexp-dna%22:%5B115,114,114,116,115,119,122,112,120,122%5D,%22string-base64%22:%5B120,123,116,121,114,118,116,115,117,117%5D,%22string-fasta%22:%5B128,125,122,129,122,130,129,131,123,128%5D,%22string-tagcloud%22:%5B208,209,209,206,215,210,210,209,211,219%5D,%22string-unpack-code%22:%5B401,412,410,413,406,422,412,413,410,414%5D,%22string-validate-input%22:%5B205,208,199,200,205,207,206,212,206,211%5D%7D">iPhone 4 (iOS5)</a></p>
<p><a href="http://www.webkit.org/perf/sunspider-0.9.1/sunspider-0.9.1/results.html?%7B%22v%22:%20%22sunspider-0.9.1%22,%20%223d-cube%22:%5B245,251,245,317,247,244,250,249,250,250%5D,%223d-morph%22:%5B191,184,186,189,186,190,202,190,194,188%5D,%223d-raytrace%22:%5B222,226,223,222,229,227,234,229,227,231%5D,%22access-binary-trees%22:%5B86,87,87,93,89,89,92,92,94,85%5D,%22access-fannkuch%22:%5B189,188,190,189,350,187,188,189,188,190%5D,%22access-nbody%22:%5B195,194,193,204,585,196,198,199,194,194%5D,%22access-nsieve%22:%5B83,94,86,82,84,83,83,83,82,84%5D,%22bitops-3bit-bits-in-byte%22:%5B38,40,37,38,38,43,40,38,38,40%5D,%22bitops-bits-in-byte%22:%5B70,54,53,58,62,55,59,55,54,54%5D,%22bitops-bitwise-and%22:%5B78,78,79,79,82,79,77,76,77,79%5D,%22bitops-nsieve-bits%22:%5B93,94,94,95,93,94,93,93,101,99%5D,%22controlflow-recursive%22:%5B34,34,32,34,33,34,33,33,36,35%5D,%22crypto-aes%22:%5B365,173,173,174,174,184,177,172,170,171%5D,%22crypto-md5%22:%5B101,65,64,68,67,69,65,66,65,67%5D,%22crypto-sha1%22:%5B75,49,48,50,51,48,49,54,49,49%5D,%22date-format-tofte%22:%5B618,358,357,361,373,365,367,482,379,372%5D,%22date-format-xparb%22:%5B408,360,349,354,371,365,371,369,359,363%5D,%22math-cordic%22:%5B199,191,192,188,188,188,190,188,190,191%5D,%22math-partial-sums%22:%5B228,227,228,225,229,232,227,232,229,227%5D,%22math-spectral-norm%22:%5B160,132,131,131,130,131,131,130,133,130%5D,%22regexp-dna%22:%5B158,149,148,151,150,149,152,148,153,148%5D,%22string-base64%22:%5B164,163,176,167,171,172,175,172,181,174%5D,%22string-fasta%22:%5B227,187,176,179,167,175,176,189,176,172%5D,%22string-tagcloud%22:%5B303,288,270,277,284,289,282,284,281,284%5D,%22string-unpack-code%22:%5B1029,531,527,523,543,545,553,545,538,541%5D,%22string-validate-input%22:%5B296,300,297,299,299,293,298,320,296,296%5D%7D">iPhone 3GS (iOS5)</a></p>
<h3>Bonus: <a href="http://ie.microsoft.com/testdrive/Performance/FishIETank/">FishIETank</a> (10 fish) (Canvas test)</h3>
<table>
<thead>
<tr>
<td>Test</td>
<td>iPhone 4S</td>
<td>iPhone 4</td>
<td>iPhone 3GS</td>
</tr>
</thead>
<tfoot></tfoot>
<tbody>
<tr>
<td>Total</td>
<td class="positive">50fps</td>
<td>35fps</td>
<td>25fps</td>
</tr>
</tbody>
</table>
<p>One thing to note here: the 3GS has a bit of an advantage because of a non-retina screen.  However, it&#8217;s still outperformed easily by the iPhone 4 and 4S.</p>
<h3>Related</h3>
<p><a href="http://davidbcalhoun.com/2011/javascript-sunspider-benchmark-ios-4-3-vs-ios-4-0">JavaScript SunSpider benchmark: iOS 4.3 vs iOS 4.0</a><br />
<a href="http://davidbcalhoun.com/2010/blackberry-torch-sunspider-results-javascript-benchmark">BlackBerry Torch SunSpider results (JavaScript benchmark)</a><br />
<a href="http://davidbcalhoun.com/2010/iphone-4-sunspider-test-results">iPhone 4 SunSpider test results (22% faster than iPhone 3GS)</a><br />
<a href="http://davidbcalhoun.com/2010/sunspider-ios-3-1-3-versus-ios-4-gm">JavaScript SunSpider test: iOS 3.1.3 versus iOS 4 GM</a><br />
<a href="http://davidbcalhoun.com/2010/javascript-sunspider-htc-evo-versus-htc-incredible-versus-nexus-one">JavaScript SunSpider: HTC Evo versus HTC Incredible versus Nexus One</a></p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/ios5-sunspider-iphone-4s-vs-iphone-4-vs-iphone-3gs/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>iPhone 4S, iPhone 4, and iPhone 3GS photo comparison</title>
		<link>http://davidbcalhoun.com/2011/iphone-4s-iphone-4-and-iphone-3gs-photo-comparison</link>
		<comments>http://davidbcalhoun.com/2011/iphone-4s-iphone-4-and-iphone-3gs-photo-comparison#comments</comments>
		<pubDate>Fri, 14 Oct 2011 23:28:24 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[mobile]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=823</guid>
		<description><![CDATA[More photos likely to come.. this is just after I unboxed my new 4S. Time to play with it a bit! iPhone 4S iPhone 4 iPhone 3GS iPhone 3GS (alternate white balance point)]]></description>
			<content:encoded><![CDATA[<p>More photos likely to come.. this is just after I unboxed my new 4S.  Time to play with it a bit!</p>
<h3>iPhone 4S</h3>
<p><a href="http://davidbcalhoun.com/wp-content/uploads/2011/10/4S.jpg"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/4S-1024x768.jpg" alt="Canon 7D, shot with an iPhone 4S" title="Canon 7D, shot with an iPhone 4S" width="1024" height="768" class="aligncenter size-large wp-image-824" /></a></p>
<h3>iPhone 4</h3>
<p><a href="http://davidbcalhoun.com/wp-content/uploads/2011/10/4.jpg"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/4-1024x764.jpg" alt="Canon 7D, shot with an iPhone 4" title="Canon 7D, shot with an iPhone 4" width="1024" height="764" class="aligncenter size-large wp-image-825" /></a></p>
<h3>iPhone 3GS</h3>
<p><a href="http://davidbcalhoun.com/wp-content/uploads/2011/10/3GS.jpg"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/3GS-1024x768.jpg" alt="Canon 7D, shot with an iPhone 3GS" title="Canon 7D, shot with an iPhone 3GS" width="1024" height="768" class="aligncenter size-large wp-image-826" /></a></p>
<h3>iPhone 3GS (alternate white balance point)</h3>
<p><a href="http://davidbcalhoun.com/wp-content/uploads/2011/10/3GS-alt.jpg"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/3GS-alt-1024x768.jpg" alt="Canon 7D, shot with an iPhone 3GS" title="Canon 7D, shot with an iPhone 3GS" width="1024" height="768" class="aligncenter size-large wp-image-827" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/iphone-4s-iphone-4-and-iphone-3gs-photo-comparison/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mobile Performance Manifesto</title>
		<link>http://davidbcalhoun.com/2011/mobile-performance-manifesto</link>
		<comments>http://davidbcalhoun.com/2011/mobile-performance-manifesto#comments</comments>
		<pubDate>Tue, 11 Oct 2011 07:44:45 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=768</guid>
		<description><![CDATA[Earlier this year I gave a talk (slides) outlining the latest and greatest in mobile performance, including a bit of my own unscientific research into carrier latency and bandwidth thanks to boomerang.js. I realized that interest in mobile performance has exploded recently, especially with Steve Souders announcing his focus on mobile, and I thought it [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/odometer.jpg" alt="" title="Dashboard with odometer" width="800" height="299" class="aligncenter size-full wp-image-806" /></p>
<p>Earlier this year I gave a <a href="http://www.meetup.com/SF-Web-Performance-Group/events/16116764">talk</a> (<a href="http://davidbcalhoun.com/present/mobile-performance/">slides</a>) outlining the latest and greatest in mobile performance, including a bit of my own unscientific research into carrier latency and bandwidth thanks to <a href="https://github.com/yahoo/boomerang">boomerang.js</a>.</p>
<p>I realized that interest in mobile performance has exploded recently, especially with <a href="http://www.stevesouders.com/blog/2011/01/10/announcing-my-focus-on-mobile/">Steve Souders announcing his focus on mobile</a>, and I thought it was time for an update, this time in blog form.  Also, my old <a href="http://davidbcalhoun.com/present/mobile-performance/">slides</a> have been somewhat embarrassing.  For some strange reason, at the time I wanted to give <a href="http://meyerweb.com/eric/tools/s5/">S5</a> a try &#8211; that outdated, ancient, not-performant slideshow framework.  The result is a slideshow on performance that loads slowly&#8230; doh!  (incidentally, I recommend <a href="http://imakewebthings.github.com/deck.js/">deck.js</a> as an alternative).</p>
<p>In any case, it was time for a roundup of mobile performance best practices, in blog form.  I&#8217;m not sure if it&#8217;s properly called a manifesto, but it is what it is!  Onward!</p>
<h3>For fun: Latency and bandwidth tests</h3>
<p>Before we start.. just a little fun data!  It&#8217;s always been a pleasure to fiddle around with <a href="https://github.com/yahoo/boomerang">boomerang.js</a> and compare results.  With my latest trip to Japan, I had the opportunity to run Boomerang on Japan&#8217;s <a href="http://en.wikipedia.org/wiki/EMOBILE_Limited">e-mobile</a> 3G network in the remotest of places, up in Hakuba/Nagano in the Japanese alps.</p>
<p>When I got back, I ran the same tests from downtown San Francisco, which was closer to my California-based test server, and should&#8217;ve been faster, right?  Theoretically&#8230;</p>
<h4>Boomerang Tests (running on a California-hosted server)</h4>
<table>
<th>
<td>Verizon 3G (SF)</td>
<td>ATT 3G (SF)</td>
<td>e-mobile 3G (Hakuba)</td>
</th>
<tr>
<td>Latency</td>
<td class="positive">251ms</td>
<td>901ms</td>
<td>401ms</td>
</tr>
<tr>
<td>Bandwidth</td>
<td>62kbps</td>
<td>3kbps</td>
<td class="positive">95kbps</td>
</tr>
</table>
<p>Yes, e-mobile didn&#8217;t have the greatest ping, but it handily beat ATT, even though it was going across the entire Pacific Ocean!  Note that it came out the best in the bandwidth tests however&#8230;  </p>
<p>(Note: it&#8217;s unknown if or how <a href="http://stevesouders.com/ms/">Steve Souders&#8217;s latest research</a> affects these findings)</p>
<p>There&#8217;s a lot of factors that could&#8217;ve been involved, so look to something like <a href="http://opensignalmaps.com/">OpenSignalMaps</a> for more data.</p>
<p>Ok, onto the tips!</p>
<h3>Page Organization</h3>
<p><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/mobile-site-organization.png" alt="" title="Smart phone versus feature phone website organization" width="645" height="633" class="aligncenter size-full wp-image-793" /></p>
<p>For feature phones that have little to no caching, aggressively combine requests (deliver HTML/CSS/JS all in one package).  For smart phones, take advantage of caching by mirroring desktop frontend best practices: separate HTML, CSS, and JS so they can be cached (per-session and across sessions).</p>
<p>There&#8217;s old research about <a href="http://www.yuiblog.com/blog/2008/02/06/iphone-cacheability/">extremely small cache sizes on iOS in particular</a>, but this research has been followed up on by more recent research by <a href="http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/">Ryan Grove (Yahoo!)</a> and <a href="http://www.stevesouders.com/blog/2010/07/12/mobile-cache-file-sizes/">Steve Souders (Google)</a>, which shows that we shouldn&#8217;t be so paranoid, since caching is pretty decent across all the major mobile browsers.</p>
<p>Of particular interest is a browser&#8217;s capability to cache files in a current session, browsing from page-to-page, which is what most users will end up doing (caching of the page across sessions is another matter).  What is the maximum file size a browser will cache during a session?  The <a href="http://www.browserscope.org/user/tests/table/agt1YS1wcm9maWxlcnINCxIEVGVzdBj_1OsBDA?v=3&#038;layout=simple&#038;f=Max%20js%20Cache%20Size%20(kB)">results (via Browserscope)</a> end up being encouraging:</p>
<table>
<th>
<td>Maximum Cache Size (MB)</td>
</th>
<tr>
<td>Android 2.1</td>
<td>4+</td>
</tr>
<tr>
<td>Android 2.2</td>
<td>2</td>
</tr>
<tr>
<td>Android 2.3</td>
<td>2</td>
</tr>
<tr>
<td>Android 3.0</td>
<td>4+</td>
</tr>
<tr>
<td>Blackberry 6.0.0</td>
<td>4+</td>
</tr>
<tr>
<td>iPad 4.3.5</td>
<td>4+</td>
</tr>
<tr>
<td>iPad 5.0</td>
<td>4+</td>
</tr>
<tr>
<td>iPhone 4.3.5</td>
<td>4+</td>
</tr>
<tr>
<td>iPhone 5.0</td>
<td>4+</td>
</tr>
<tr>
<td>Opera Mini 4</td>
<td>4+</td>
</tr>
<tr>
<td>Opera Mini 5</td>
<td>4+</td>
</tr>
<tr>
<td>Opera Mini 6</td>
<td>4+</td>
</tr>
<tr>
<td>webOS 2.0</td>
<td>1</td>
</tr>
</table>
<h3>Avoid redirects (foo.com -> m.foo.com)</h3>
<p>If possible, perform the redirection behind the scenes on the server, which should be transparent to the user.  When a user performs a Google search and clicks on your page, they&#8217;re already getting redirected once by Google (check it yourself).  Your own redirects are adding a second redirect where there need not be one.</p>
<h3>Optimize Images</h3>
<p><a href="http://filamentgroup.com/examples/responsive-images-new/demos/A-Default/demo.html"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/responsive-images.jpg" alt="" title="Responsive images" width="600" height="423" class="aligncenter size-full wp-image-796" /></a><br />
Deliver appropriately-sized images to devices.  The philosophy of responsive design makes it easy to simply downscale images to fit the screen, but avoid this where possible, as this means wasted bandwidth.</p>
<p>You can optimize images through CSS media queries or in JavaScript (see below).  Though you want to reduce your dependence on cookies, it may be a good idea to store these width/height values into a cookie (or localStorage if you are fetching images in nontraditional ways) so the values can be read by the server, which can deliver appropriately-sized images.  This technique has been <a href="http://filamentgroup.com/lab/responsive_images_experimenting_with_context_aware_image_sizing/">implemented by Filament Group</a>, so you should probably read about their experiences before trying to roll your own.</p>
<p>Also note that where applicable, at the expense of performance you may want to serve higher resolution images for better screens, such as for Retina displays (which can be detected with JavaScript or CSS).</p>
<h4>JavaScript examples</h4>
<pre name="code" class="JScript">
window.innerHeight;       // max height actually available
window.innerWidth;        // max width actually available
window.devicePixelRatio;  // pixel density (standard is 1, high resolution is generally > 1)
</pre>
<p>(note that <code>screen.width</code> and <code>screen.height</code> are also available to tell you the dimensions of the entire screen, but this isn&#8217;t all available due to the space taken by the OS and browser chrome)</p>
<h4>Media query examples</h4>
<pre name="code" class="css">
@media only screen and (max-width: 480px) {
  /* small screen styles */
}

@media only screen and (min-width: 481px) {
  /* large screen styles */
}

@media (-webkit-min-device-pixel-ratio: 1.5),
       (-o-min-device-pixel-ratio: 3/2),
       (min--moz-device-pixel-ratio: 1.5),
       (min-device-pixel-ratio: 1.5) {
  /* high resolution styles */
}
</pre>
<h3>navigator.connection (Android only)</h3>
<p>Use <a href="http://davidbcalhoun.com/2010/using-navigator-connection-android">navigator.connection</a> if it&#8217;s available to serve different assets based on connection speed (3G vs WIFI, for instance).</p>
<p>Here&#8217;s the contents of the <code>navigator.connection</code> object (with a phone running on a 3G connection):</p>
<pre name="code" class="JScript">
{
  type: 4,
  UNKNOWN: 0,
  ETHERNET: 1,
  WIFI: 2,
  CELL_2G: 3,
  CELL_3G: 4
}
</pre>
<p>And an example of how you could write code for each type:</p>
<pre name="code" class="JScript">
(function(){  // sandbox our code
  if(!navigator.connection) navigator.connection = {type:0, UNKNOWN: 0};  // polyfill
  var connection = navigator.connection;

  if(connection.type === connection.WIFI || connection.type === connection.ETHERNET) {
    // high bandwidth
  } else {
    // normal bandwidth
  }
})();
</pre>
<p>Here&#8217;s how we might be able to use <a href="http://modernizr.com/">Modernizr</a> to help us out:</p>
<pre name="code" class="JScript">
(function(){  // sandbox our code
  if(!navigator.connection) navigator.connection = {type:0, UNKNOWN: 0};  // polyfill
  var connection = navigator.connection;

  // add a custom test to Modernizr
  Modernizr.addTest('highbandwidth', function(){
    return connection.type === connection.WIFI || connection.type === connection.ETHERNET;
  });

})();
</pre>
<p>We can now target special high-bandwidth assets with CSS:</p>
<pre name="code" class="css">
.highbandwidth .logo {background-image:url('logo-high.jpg');}
.no-highbandwidth .logo {background-image:url('logo.jpg');}
</pre>
<h3>base64 encode small UI images</h3>
<p>You can base64 encode binary image data in HTML and CSS:</p>
<h4>HTML</h4>
<pre name="code" class="html">
&lt;img src=&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==&quot; alt=&quot;Red dot&quot;&gt;
</pre>
<h4>CSS</h4>
<pre name="code" class="css">
.dot {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==');
}
</pre>
<p>There seems to be the mistaken belief floating around that base64 images aren&#8217;t cacheable.  However, because you can embed them in your CSS, base64 encoded images will be cached along with the rest of your CSS.</p>
<p>You&#8217;ll probably just want to limit this to small UI icons however.  I wrote a <a href="http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to">quick post on the drawbacks, and also a comparison with sprites</a>.</p>
<p>If you&#8217;re using Compass/SASS, base64 encoding images is pretty trivial and easy to maintain with the <a href="http://compass-style.org/reference/compass/helpers/inline-data/">inline-image helper</a>.</p>
<h3>Unicode and Emoji</h3>
<p>&#9734; (HTML entity: #9734)<br />
<img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/emoji3.png" alt="" title="Emoji" width="18" height="18" /> (HTML entity: <code>#x1f468</code>)</p>
<p>Before even considering base64 images, take advantage of icons that are already made for you: unicode characters and <a href="http://pukupi.com/post/1964">emoji</a> (where supported).  Keep in mind that these will look different across browsers, so this might not be an option for everyone.</p>
<p>Because of inconsistent implementations of Emoji character codes between Asian carriers, representatives from Apple and Google made a <a href="http://en.wikipedia.org/wiki/Emoji#Emoji_in_the_Unicode_standard">proposal to add Emoji to the Unicode standard</a>.  Unfortunately it seems that only iPhone supports them for now.  Here&#8217;s a <a href="http://www.unicode.org/charts/PDF/U1F300.pdf">handy chart of all the Unicode emoji characters available</a>.</p>
<h3>Take advantage of CSS3</h3>
<p>CSS3 offers many replacements for things we needed images for previously.  RGBA values replace the need for a semitransparent image for overlays and such.  Likewise, border-radius, box shadow, linear-gradients, radial-gradients all reduce the need for images.</p>
<p>However, do be aware that though phones support these new features, it doesn&#8217;t mean they&#8217;re necessarily ready for primetime.  Something I&#8217;ve encountered recently to remind me of this fact is <a href="http://code.google.com/p/android/issues/detail?id=767">severe color banding issues when using a CSS radial gradient</a>.  The solution was to fake the radial gradient using two linear gradients, or to (unfortunately) use an old-fashioned image.</p>
<h3>Avoid using cookies</h3>
<p>Cookies get thrown into <em>every</em> request on a per-domain basis, so limit your usage of them.  Use localStorage/sessionStorage instead, where possible.</p>
<h3>App cache</h3>
<p>Take advantage of the HTML5 app cache, though it&#8217;s an unwieldy beast to tame.  This will mean you will need to make your site work offline, which might be tricky.</p>
<p>Assets that are traditionally cached get rechecked on page refresh (the server sends back a 304 response if your cache is still up-to-date).  Whereas with the app cache, only one file (your manifest) is rechecked on page load.</p>
<h3>Deferred JavaScript execution</h3>
<p><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/gmail-deferred-javascript-execution.png" alt="" title="Gmail deferred JavaScript execution" width="497" height="450" class="aligncenter size-full wp-image-810" /></p>
<p>We know that deferring downloading of scripts is advantageous (by placing scripts at the bottom of a page or by using the <code>async</code> attribute), but deferred execution of JavaScript is even more important.  Sure, we can use the <code>defer</code> attribute, but that&#8217;s only really relevant for when the page is loading (<code>defer</code> lets the browser know that the UI doesn&#8217;t depend on the JavaScript, so it can be safely deferred).</p>
<p>But what about JavaScript that runs after the page loads, such as XHR and JSONP requests?  What does this mean for the user?  It means that the UI freezes up unexpectedly when JavaScript is being downloaded and executed in the background.  But this doesn&#8217;t mean that you want to completely avoid background downloading of JavaScript.  The Gmail mobile team came up with a <a href="http://googlecode.blogspot.com/2009/09/gmail-for-mobile-html5-series-reducing.html">clever solution</a>: by commenting all of their code and dynamically eval&#8217;ing it when needed, they split up the JavaScript downloading from its execution.</p>
<h3>Perceived performance</h3>
<p>Do whatever you have to do to let the user know that the UI is still responding.  This sometimes means faking that something is happening.  Communication is key!  If they clicked on a button, give some indication that they clicked on it.  If they clicked on something that requires a request to the network, show a spinner right away, even if it means you haven&#8217;t even sent out a request.  The user doesn&#8217;t need to know the nitty-gritty details &#8211; they just want to know that their intent was communicated.</p>
<h3>Onclick delay</h3>
<p><iframe width="853" height="480" src="http://www.youtube.com/embed/k1M4L3TAyEU" frameborder="0" allowfullscreen></iframe></p>
<p>On several major mobile operating systems there&#8217;s a several hundred millisecond delay on the onclick event.  This is because of the double-tap-to-zoom functionality.  When a user first taps on the screen, there&#8217;s a hard-coded delay that waits for the second tap.  If there&#8217;s no second tap, the onclick event is then fired.  Unfortunately the only way to get around the delay is to tap into touch events instead, which is a bit more complicated than it appears on first glance.</p>
<p>For an overview of some of the challenges of implementing the workaround, see <a href="http://code.google.com/mobile/articles/fast_buttons.html">this article by Google&#8217;s Ryan Fioravanti</a>.</p>
<h3>Take advantage of hardware acceleration</h3>
<p>Use hardware-accelerated CSS transforms where possible (translate3d, translateZ, rotate3d, and scale3d).  An element that is hardware accelerated is turned into a graphic, which is perfect for the GPU to manipulate, taking away the burden from the CPU.</p>
<p>However, the GPU isn&#8217;t all-powerful, so don&#8217;t try to apply hardware accelerations to everything.  Also, these elements still need to be refreshed periodically, and it turns out that you can make some good optimizations here.  First, you&#8217;ll want to debug the composited layers on your desktop browser:</p>
<h4>Debugging hardware acceleration</h4>
<p><a href="http://www.webkit.org/blog-files/3d-transforms/poster-circle.html"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/debug-composited-layers-hardware-acceleration.png" alt="" title="WebKit&#039;s poster circle demo with and without the debug information" width="767" height="399" class="aligncenter size-full wp-image-803" /></a><br />
<em>Chrome</em></p>
<ol>
<li>Type the following in the address bar: about:flags</li>
<li>&#8220;Composited render layer borders&#8221; -> Enable</li>
</ol>
<p><em>Safari</em></p>
<ol>
<li>Open a terminal</li>
<li>$ defaults write com.apple.Safari IncludeInternalDebugMenu 1</li>
<li>$ defaults write com.apple.Safari CA_COLOR_OPAQUE 1</li>
<li>Open (or restart) Safari</li>
<li>Debug -> Show Compositing Borders</li>
</ol>
<p>(to turn these off, run the same commands with a boolean FALSE: i.e. <code>defaults write com.apple.Safari CA_COLOR_OPAQUE FALSE</code>)</p>
<p>Keep in mind that each composited layer has a limited width and height.  For instance, if you&#8217;re creating an image carousel, chances are the dimensions of the element will be too big to fit the layer into memory as one piece.  This means that when the element is animated, the GPU has to break up the layer manually into several manageable chunks.  It&#8217;s much better to chunk it yourself.  To do this, you trigger hardware acceleration on each chunk.</p>
<p>So you will change this:</p>
<pre name="code" class="css">
.carousel {
  -webkit-transform: translate3d(0,0,0);  /* or translateZ(0); */
}
</pre>
<p>To this:</p>
<pre name="code" class="css">
.carousel {
  -webkit-transform: translate3d(0,0,0);  /* or translateZ(0); */
}

.carousel-pane {
  -webkit-transform: translate3d(0,0,0);  /* or translateZ(0); */
}
</pre>
<p>Where carousel-pane represents each child element of the carousel.</p>
<p>More info: <a href="http://dl.dropbox.com/u/5618867/mseeley-2011-09-27-html5devconf.pdf">(slides) WebKit in Your Living Room (Matt Seeley, Netflix)</a></p>
<p>Also see <a href="http://www.html5rocks.com/en/mobile/optimization-and-performance.html">HTML5 Techniques for Optimizing Mobile Performance</a>.</p>
<h3>HTTP Pipelining</h3>
<p><a href="http://www.blaze.io/mobile/http-pipelining-big-in-mobile/"><img src="http://davidbcalhoun.com/wp-content/uploads/2011/10/pipelining.png" alt="HTTP Pipelining diagram" title="HTTP Pipelining (via Blaze.io)" width="640" height="445" class="aligncenter size-full wp-image-783" /></a></p>
<p>Take advantage of <a href="http://www.blaze.io/mobile/http-pipelining-big-in-mobile/">HTTP Pipelining</a>, which is often overlooked, but has broad support on mobile.  This virtually eliminates round trip times, for all but the first request.</p>
<p>Opera and Android support pipelining, and the newly released iOS 5 has added support for it.</p>
<p>Great! So how do you make sure your server is taking advantage of pipelining?</p>
<blockquote><p>The first request to every server is sent by itself (only one request on the connection), and the browser looks for two properties in the response:</p>
<ol>
<li>Use of HTTP/1.1</li>
<li>An explicit “Connection: Keep-Alive” header (required by Android)</li>
</ol>
<p><a href="http://www.blaze.io/mobile/http-pipelining-big-in-mobile/">-Blaze.io</a>
</p></blockquote>
<p>If these criteria are met, subsequent requests will be pipelined.  Sweet!</p>
<h3>DNS Prefetching</h3>
<p>Take advantage of <a href="https://developer.mozilla.org/En/Controlling_DNS_prefetching">DNS Prefetching</a>.  This theoretically speeds up load times, but there have been <a href="http://www.mydigitallife.info/turn-off-dns-prefetching-in-google-chrome-to-fix-resolving-host-and-cannot-load-page-error/">some issues</a>, so be sure to test it.</p>
<p>To turn off DNS Prefetching, serve this meta tag:</p>
<pre name="code" class="html">
&lt;meta http-equiv=&quot;x-dns-prefetch-control&quot; content=&quot;off&quot;&gt;
</pre>
<p>You can also explicitly force a DNS lookup:</p>
<pre name="code" class="html">
&lt;link rel=&quot;dns-prefetch&quot; href=&quot;http://www.example.com/&quot;&gt;
</pre>
<h3>Avoid library code bloat</h3>
<p>If you&#8217;re developing for smart phones, you may be able to dramatically reduce the data over the wire by simply using new JavaScript APIs instead of a full-blown library or framework such as jQuery Mobile (which is rather a UI framework and depends on the desktop version of jQuery).</p>
<p>Among the things offered by newer browsers, which should reduce your dependence on a library:</p>
<ul>
<li><a href="https://developer.mozilla.org/En/DOM/Document.querySelector">querySelector</a>/<a href="https://developer.mozilla.org/en/DOM/document.querySelectorAll">querySelectorAll</a>: CSS selectors that replace the need for a selector engine</li>
<li><a href="https://developer.mozilla.org/en/DOM/document.getElementsByClassName">getElementsByClassName</a></li>
<li><a href="https://developer.mozilla.org/en/DOM/element.classList">classList</a> &#8211; replaces the need for hasClass, addClass, removeClass helpers (available on iOS5, but not sure what else)</li>
<li><a href="https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest">XMLHttpRequest</a> &#8211; it&#8217;s probably time to learn how to do this natively instead of using a wrapper that takes care of  IE&#8217;s old implementation that requests an ActiveX object.  <a href="http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/">Cross-Origin Resource Sharing</a> also means we can easily share resources across domains.</li>
<li><a href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">HTML5 history (pushState, etc)</a> &#8211; though an <a href="https://bugs.webkit.org/show_bug.cgi?id=42940">older bug</a> means you should maybe hold off for now (note: the fix is present in iOS 5, which is based on a newer WebKit)</li>
<li><a href="http://www.the-art-of-web.com/html/html5-form-validation/">HTML5 Form Validation</a> reduces our need for JavaScript-based validation</li>
<li>HTML5 input types that reduce our need for custom UI controls (date, time, slider [range], etc)</li>
</ul>
<p>You&#8217;ll want to consider using either a library that was optimized for the browsers you&#8217;re targeting (such as <a href="http://zeptojs.com/">Zepto.js</a>) or simply bring in <a href="http://microjs.com/">a microlibrary for specific tasks you want to perform</a>.</p>
<h3>Clientside databases</h3>
<p>Most mobile browsers currently support WebSQL, which is being phased out in support of indexedDB, which is not widely implemented.  However, if you use a wrapper such as <a href="http://westcoastlogic.com/lawnchair/">Lawnchair</a>, the transition from one to the other is relatively painless.</p>
<h3>TODO: testing</h3>
<h3>More</h3>
<p>(to be expanded on later)</p>
<ul>
<li>use standard desktop best practices (for smart phones)</li>
<li>requestAnimationFrame instead of setTimeout</li>
<li>setImmediate (where available) instead of setTimeout(fn(){},0)</li>
<li>Ajax parsing times: you might want to use Multipart XHR so you can yield the process as it&#8217;s going through big responses (to prevent the UI locking up)</li>
<li>avoid rgba, box shadows, text shadow, etc, as this greatly degrades performance (especially on animations)</li>
<li>high resolution screens may suffer from animation/transition slowness &#8211; it&#8217;s been shown that manipulating the viewport tag to scale the page <a href="http://29a.ch/2011/5/27/fast-html5-canvas-on-iphone-mobile-safari-performance">will speed up canvas rendering</a>, and <a href="http://paulbakaus.com/2011/10/10/scroller-vs-scrollability-deathmatch/">high-dpi scaling concerns are also evident in CSS transforms</a></li>
<li><a href="http://joehewitt.com/2011/10/05/fast-animation-with-ios-webkit">WebKit animations are faster than animations done via JavaScript</a></li>
<li>if you do use JavaScript-based animations, limit the UI updates to ~17ms, which is equivalent to 60fps, which is the fastest your display will refresh anyway, so it&#8217;s pointless to try to do anything faster than that.  Keep track of the time since the last UI update and don&#8217;t do anything if 17ms haven&#8217;t passed.</li>
</ul>
<h3>On the horizon&#8230;</h3>
<ul>
<li><a href="http://www.chromium.org/spdy">SPDY</a>: already implemented in Amazon&#8217;s Silk browser for Kindle.  Will possibly be on Android phones <a href="http://androidandme.com/2011/10/news/google-chrome-is-finally-coming-to-an-android-device-near-you/">when the browser is powered by Chrome</a></li>
<li>indexedDB replacing WebSQL</li>
</ul>
<h3>Tools</h3>
<p><a href="http://stevesouders.com/mobileperf/mobileperfbkm.php">Mobile Perf bookmarklet</a><br />
<a href="http://calendar.perfplanet.com/2010/mobile-performance-analysis-using-pcapperf/">pcapperf (Packet Capture Web Performance Analyzer)</a><br />
<a href="http://www.blaze.io/mobile/">Blaze Mobitest</a> &#8211; tests the loading time of your site on actual phones</p>
<h3>More Resources</h3>
<p><a href="http://www.w3.org/TR/mwabp/">Mobile Web Application Best Practices</a><br />
<a href="http://stevesouders.com/mobileperf/">Mobile Performance (Steve Souders)</a><br />
<a href="http://www.strangeloopnetworks.com/web-performance-optimization-hub/topics/mobile/">Strangeloop Web Performance Hub / Mobile</a></p>
<p>(odometer image via <a href="http://www.flickr.com/photos/henrybloomfield/4442900025/">henrybloomfield on Flickr</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/mobile-performance-manifesto/feed</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>When to base64 encode images (and when not to)</title>
		<link>http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to</link>
		<comments>http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to#comments</comments>
		<pubDate>Sun, 28 Aug 2011 09:19:58 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=737</guid>
		<description><![CDATA[Introduction Ever since Steve Souders started evangelizing web performance, it&#8217;s been pounded into our heads that extra HTTP requests add a lot of additional overhead, and that we should combine them if possible to dramatically decrease the load time of our web pages. The practical implication of this has been to combine our JavaScript and [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Ever since Steve Souders started evangelizing web performance, it&#8217;s been pounded into our heads that extra HTTP requests add a lot of additional overhead, and that we should combine them if possible to dramatically decrease the load time of our web pages.</p>
<p>The practical implication of this has been to combine our JavaScript and CSS files, which is relatively easy and straightforward, but the harder question has been what to do with images.</p>
<h4>Sprites</h4>
<p>Image sprites are a concept taken from video games: the idea is to cram a ton of image assets into one file, and rearrange a &#8220;viewport&#8221; of sorts to view only specific pieces of that file at a time.  For instance, a simple sprite that holds two images might have one viewport that only looks at the top half of the sprite (image #1), and another viewport that only looks at the bottom half (image #2).</p>
<p>On the web side of things, this means that those multiple requests have now been combined into one request.  This is nice because it saves both the overhead of additional HTTP requests as well as the overhead of setting up an image&#8217;s <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header">file header</a> each time.</p>
<p>But there&#8217;s a few drawbacks with using image sprites:</p>
<ul>
<li>hard to maintain and update: without some tool to help, manually editing and putting together image sprites is quite a chore</li>
<li><a href="http://blog.vlad1.com/2009/06/22/to-sprite-or-not-to-sprite/">increased memory consumption</a> (possibly very dramatic): this is often overlooked.  The time to deliver the images is decreased at the expense of a bigger memory and CPU footprint, especially for large sprites and sprites with a lot of whitespace.  </li>
<li>bleedthrough: for sprites that don&#8217;t have much whitespace to separate images, there&#8217;s an increased chance of nearby images visibly bleeding through other elements</li>
</ul>
<h4>Data URIs and Base64 encoding</h4>
<p>Data URIs (see <a href="http://www.phpied.com/data-urls-what-are-they-and-how-to-use/">this</a>, <a href="http://css-tricks.com/5970-data-uris/">this</a>, and <a href="http://www.nczonline.net/blog/2010/07/06/data-uris-make-css-sprites-obsolete/">this</a>) and Base64 encoding goes hand-in-hand.  This method allows you to embed images right in your HTML, CSS, or JavaScript.</p>
<p>Just like sprites, you save HTTP requests, but there&#8217;s also some drawbacks:</p>
<ul>
<li>base64 encoding makes file sizes <a href="http://en.wikipedia.org/wiki/Base64">roughly 33% larger</a> than their original binary representations, which means more data down the wire (this might be exceptionally painful on mobile networks)</li>
<li>data URIs aren&#8217;t supported on IE6 or IE7</li>
<li>base64 encoded data may possibly take longer to process than binary data (anyone want to do a study on this?) (again, this might be exceptionally painful for mobile devices, which have more limited CPU and memory) (side note: <a href="http://twitter.com/#!/stoyanstefanov/status/106605257265655809">CSS background-images seem to actually be faster than img tags</a>)</li>
</ul>
<p>The &#8220;33% larger&#8221; claim is generally accepted truth now, despite the fact that the figure varies wildly depending on the type of content.  This is exactly what I wanted to test, albeit in a pretty limited and nonscientific way.</p>
<p>Before I tested, I wanted to keep in mind a few <em>unverified intuitions</em> (which aren&#8217;t entirely my own, but seem to be ideas that are floating around out there).  Here&#8217;s a few questions I had before going to test:</p>
<ul>
<li>Is base64 encoding with gzipping roughly equal to the original filesize of the binary file?</li>
<li>Is base64 encoding best for small images?</li>
<li>Is base64 encoding best for small and simple icons and not good for pictures and photos?</li>
<li>Is base64 encoding best when multiple files are merged together?</li>
</ul>
<p>There&#8217;s something else I wanted to test: whether Gzipping binary image data made much difference.  I know text compresses well, but is it even worth compressing JPEG files with Gzip, for instance?</p>
<p>I ran three tests: one with a set of small UI icons, one with a set of small photographs, and one with a set of the same photographs in a larger size.  Though my tests were by no means extensive, they do show that care should be taken in making assumptions about base64.</p>
<p>Just a note about the tables: they are comparing the binary form (original png or jpeg) with the base64 form as it would appear in a CSS stylesheet, and comparing each of those with their gzipped form, which is most likely how they would be sent down the wire.  The CSS representation has a few practical declarations and looks something like this:</p>
<pre name="code" class="css">
.address-book--arrow {
	background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAp1JREFUeNqEU21IU1EYfu7unW5Ty6aBszYs6MeUjGVYokHYyH5E1B9rZWFEFPQnAwmy6Hc/oqhfJsRKSSZGH1JIIX3MNCsqLTD9o1Oj6ebnnDfvvefezrnbdCHhCw/n433P8z7nPe/hBEEAtX0U7hc164uwuvVSXKwZLoOmaRDim+7m9vZa0WiEKSUFFpNpCWlmMyypqTDRuYn6t3k8vmQ2gRDCxs0t9fW45F52aBTROJLtZl7nEZad2m+KtoQCQ0FBARyOCGRZ/q92I1WgqqXlfdd95VsrK8/pChIEqqpCkiQsiCII0aBQZZoWl8lzFDwsFjMl0DBLY8Lj41hBwK4jSQrWOIphL6xYyhwJDWGo6wFSaH1Y3PTCAsITE1oyAa8flhWkbSiCLX8vun11eiGIpiJ/z2nYdx5HqLdVV7elrOzsuqysL3rmBIGiKPizKCHHWY4PLVeQbnXAdegqdhy+hu8dDTBnbqQJZJ1A7u+vz7RaiymWCZgCRSF6Edk8b9cx+B/W6WuVxPaZnyiqXoPpyUmVYvkKTIFClHigEieKjYuSvETUllaF4GAUM1NT6ooaJDKx+aDfC9fByxj90REb+9ppmIoAscH/6leg8MS9DJXPAM9xHCM443K57C6biMjcHDaVVCHw9RmCA2/RGC5C00AqXk/m4p20HZK4CM/J3Zk9n0ecMBhDQnJHcrTisyMfdQXOilrdMfxcwoHq/fg5R59TiQV3hYGKo6X2J/c7LyQIjOx9GXhOw/zoJ8wEevRGyp53o/lGMNYsBgPtEwLecwov7/jGDKa1twT6o3KpL4MdZgGsWZLtfPr7f1q58k1JNHy7YYaM+J+K3Y2PmAIbRavX66229hrGVvvL5uzsHDEUvUu+NT1my78CDAAMK1a8/QaZCgAAAABJRU5ErkJggg==);
	width: 16px;
	height: 16px;
	background-repeat: no-repeat;
}
</pre>
<p>Ok, onto the tests!</p>
<h3>Test #1: Five 16&#215;16 icons from the <a href="http://p.yusukekamiyamane.com/">Fugue Icon set</a> (PNG)</h3>
<table>
<thead>
<tr>
<td>File</td>
<td>Binary</td>
<td>Binary Gzipped</td>
<td>CSS + Base64</td>
<td>CSS + Base64 Gzipped</td>
</tr>
</thead>
<tbody>
<tr>
<td>abacus</td>
<td>1443</td>
<td class="positive">1179</td>
<td>2043</td>
<td>1395</td>
</tr>
<tr>
<td>acorn</td>
<td>1770</td>
<td class="positive">1522</td>
<td>2478</td>
<td>1728</td>
</tr>
<tr>
<td>address-book&#8211;arrow</td>
<td class="positive">763</td>
<td>810</td>
<td>1153</td>
<td>948</td>
</tr>
<tr>
<td>address-book&#8211;exclamation</td>
<td class="positive">795</td>
<td>848</td>
<td>1199</td>
<td>988</td>
</tr>
<tr>
<td>address-book&#8211;minus</td>
<td class="positive">734</td>
<td>781</td>
<td>1113</td>
<td>919</td>
</tr>
<tr>
<td>Total</td>
<td>5,505</td>
<td class="positive">5,140</td>
<td>7,986</td>
<td>5,978</td>
</tr>
<tr>
<td>Combined file</td>
<td>(5,505)</td>
<td class="positive">(4,128)</td>
<td>7,986</td>
<td>4,423</td>
</tr>
</tbody>
</table>
<p>* All numbers are byte sizes<br />
** Numbers in parenthesis represent actual but impractical data.  Unfortunately, images cannot be combined and delivered together in their binary form.</p>
<p>Takeaways:</p>
<ul>
<li>The binaries are always smaller.</li>
<li>Sometimes Gzipping makes the files larger.</li>
<li>Gzipping the base64 version brings the filesize close to the size of the original binary, but this ignores the fact that the binaries get Gzipped as well.  The Gzipped binaries (how they would be delivered to the client) are always smaller than the Gzipped base64 images</li>
<li>Combining files together dramatically reduces filesizes.</li>
</ul>
<p>Practically, the developer has two options: deliver 5,140 bytes to the user in 5 separate HTTP requests, or 4,423 bytes in one HTTP request (CSS with base64 encoded image data).  Base64 is the clear winner here, and seems to confirm that small icons compress extremely well.</p>
<h3>Test #2: Five Flickr 75&#215;75 Pictures (JPEG)</h3>
<table>
<thead>
<tr>
<td>File</td>
<td>Binary</td>
<td>Binary Gzipped</td>
<td>CSS + Base64</td>
<td>CSS + Base64 Gzipped</td>
</tr>
</thead>
<tbody>
<tr>
<td><a href="http://www.flickr.com/photos/franksvalli/6064665766/sizes/sq/in/photostream/">1</a></td>
<td>6734</td>
<td class="positive">5557</td>
<td>9095</td>
<td>6010</td>
</tr>
<tr>
<td><a href="http://www.flickr.com/photos/franksvalli/6064638202/sizes/sq/in/photostream/">2</a></td>
<td>5379</td>
<td class="positive">4417</td>
<td>7287</td>
<td>4781</td>
</tr>
<tr>
<td><a href="http://www.flickr.com/photos/franksvalli/6063380824/sizes/sq/in/photostream/">3</a></td>
<td>25626</td>
<td class="positive">18387</td>
<td>34283</td>
<td>20103</td>
</tr>
<tr>
<td><a href="http://www.flickr.com/photos/franksvalli/6062803159/sizes/sq/in/photostream/">4</a></td>
<td>7031</td>
<td class="positive">6399</td>
<td>9491</td>
<td>6702</td>
</tr>
<tr>
<td><a href="http://www.flickr.com/photos/franksvalli/6017796233/sizes/sq/in/photostream/">5</a></td>
<td>5847</td>
<td class="positive">4655</td>
<td>7911</td>
<td>5077</td>
</tr>
<tr>
<td>Total</td>
<td>50,617</td>
<td class="positive">39,415</td>
<td>68,067</td>
<td>42,673</td>
</tr>
<tr>
<td>Combined file</td>
<td>(50,617)</td>
<td class="positive">(36,838)</td>
<td>68,067</td>
<td>40,312</td>
</tr>
</tbody>
</table>
<p>Takeaways:</p>
<ul>
<li>(some of the same takeaways as Test #1)</li>
<li>Separately, photos aren&#8217;t too much bigger when base64 encoded and Gzipped.  It&#8217;s very much within reason.</li>
</ul>
<p>Practically, the developer can deliver 39,415 bytes in 5 separate requests, or 40,312 in 1 request.  Not much filesize difference here, but 1 request seems preferable when we&#8217;re talking about 40kb.</p>
<h3>Test #3: Five Flickr 240&#215;160 Pictures (JPEG)</h3>
<table>
<thead>
<tr>
<td>File</td>
<td>Binary</td>
<td>Binary Gzipped</td>
<td>CSS + Base64</td>
<td>CSS + Base64 Gzipped</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>24502</td>
<td class="positive">23403</td>
<td>32789</td>
<td>23982</td>
</tr>
<tr>
<td>2</td>
<td>20410</td>
<td class="positive">19466</td>
<td>27333</td>
<td>19954</td>
</tr>
<tr>
<td>3</td>
<td>43833</td>
<td class="positive">36729</td>
<td>58561</td>
<td>38539</td>
</tr>
<tr>
<td>4</td>
<td>31776</td>
<td class="positive">31180</td>
<td>42485</td>
<td>31686</td>
</tr>
<tr>
<td>5</td>
<td>21348</td>
<td class="positive">20208</td>
<td>28581</td>
<td>20761</td>
</tr>
<tr>
<td>Total</td>
<td>141,869</td>
<td class="positive">130,986</td>
<td>189,749</td>
<td>134,922</td>
</tr>
<tr>
<td>Combined file</td>
<td>(141,869)</td>
<td class="positive">(129,307)</td>
<td>189,749</td>
<td>133,615</td>
</tr>
</tbody>
</table>
<p>Takeaways:</p>
<ul>
<li>(some of the same takeaways as Test #1)</li>
<li>Larger photos seem to bring the Gzipped binary and Gzipped base64 filesizes MUCH closer together, making the difference very minimal</li>
</ul>
<p>The developer must choose between delivering 130,986 bytes in 5 HTTP requests, or 133,615 bytes in one HTTP request.  Any good Souders follower would opt for the one request, BUT I would be careful here&#8230;</p>
<h4>Caution: things aren&#8217;t always as they seem</h4>
<p>There&#8217;s a huge caveat here: it may actually be more beneficial for perceived performance to deliver the images in 5 separate requests.</p>
<p>Why?  Because 133,615 bytes is a lot to deliver all in one package to an end user who will be staring at blank placeholders for the duration.  If the 5 base64 images all come in one request, that request will have to complete before ANYTHING is shown on the screen.  All 5 images go from blank placeholders to almost immediately decoded from base64 and displayed in place.</p>
<p>Compare this with 5 requests that are most likely made in parallel and actually give a visual indicator to the user that actual image content is being downloaded, by showing parts of the images as they&#8217;re downloaded (you can also try a throwback to progressive JPEGs &#8211; really anything will be better than just a blank screen).  That&#8217;s why it might actually be beneficial for <em>perceived</em> performance to just load images in the good old fashioned way.  They will most likely load in parallel anyway, so the extra HTTP requests may actually not really make a difference.  Not to mention it will be easier to let the browser manage the cache for each file instead of having to make your JavaScript manage your cache and prevent you from downloading an image that&#8217;s already stored away in localStorage or sessionStorage.</p>
<p>This being said, it&#8217;s generally advisable to put your common UI icons in base64 in your CSS, then let that whole chunk get cached by the browser.  Those are usually clean vector icons as well, which seem to get compressed quite well (see Test #1).</p>
<p>But for image content, where there is nothing to be saved but HTTP requests, you should definitely think twice about base64 encoding to save requests.  Yes, you will save a few HTTP requests, you won&#8217;t really be saving bytes, and the user might actually think the experience is slower because they can&#8217;t see the image content as it&#8217;s being downloaded.  Even if you shave off a few milliseconds of wait time, the <em>perceived</em> performance is what matters most.</p>
<p>(EDIT: changed the wording of the &#8220;unverified intuitions&#8221; section from &#8220;not verified&#8221; to actual questions, to make it clearer)</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Different ways of defining functions in JavaScript (this is madness!)</title>
		<link>http://davidbcalhoun.com/2011/different-ways-of-defining-functions-in-javascript-this-is-madness</link>
		<comments>http://davidbcalhoun.com/2011/different-ways-of-defining-functions-in-javascript-this-is-madness#comments</comments>
		<pubDate>Fri, 24 Jun 2011 17:20:02 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=709</guid>
		<description><![CDATA[This is madness! This&#8230; is&#8230; JavaScript! In JavaScript, there&#8217;s many different ways of doing something. This is both a good thing and a bad thing. To the newcomer this is definitely a bad thing, as it means not only more things to learn, but more little caveats and more places to go wrong. And so [...]]]></description>
			<content:encoded><![CDATA[<h3>This is madness!  This&#8230; is&#8230; JavaScript!</h3>
<p>In JavaScript, there&#8217;s many different ways of doing something.  This is both a good thing and a bad thing.  To the newcomer this is definitely a bad thing, as it means not only more things to learn, but more little caveats and more places to go wrong.  And so it is with declaring functions!</p>
<p>The aim of this is just an accessible tour of the landscape, just so you know what&#8217;s out there and what the basic differences are.  Do be sure to check out the &#8220;further reading&#8221; section as well!  Much of this is based on <a href="http://kangax.github.com/nfe/">Juriy &#8220;kangax&#8221; Zaytsev&#8217;s article</a>, which goes into more depth.  But I found that there wasn&#8217;t just one reference to show all the different variable declarations.</p>
<p>How about ways to execute functions?  That opens up another can of worms, and incidentally opens up the possibility for a future post on that topic.  <img src='http://davidbcalhoun.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Overview: different ways of declaring functions</h3>
<pre name="code" class="jscript">
function A(){};             // function declaration
var B = function(){};       // function expression
var C = (function(){});     // function expression with grouping operators
var D = function foo(){};   // named function expression
var E = (function(){        // immediately-invoked function expression (IIFE) that returns a function
  return function(){}
})();
var F = new Function();     // Function constructor
var G = new function(){};   // special case: object constructor
</pre>
<h3>Function declarations: function A(){};</h3>
<p>Function declarations are probably the most familiar and oldest way of doing things in JavaScript land.  This creates a variable A which is accessible in the current scope.  Scope is a separate topic, so we&#8217;ll do everything in the global scope for all these examples (something you want to avoid usually).</p>
<h4>1. Hoisting</h4>
<p>The interesting thing about these is that they are &#8220;hoisted&#8221; to the top of their scope, which means this code:</p>
<pre name="code" class="jscript">
A();
function A(){
  console.log('foo');
};
</pre>
<p>Gets executed as this code:</p>
<pre name="code" class="jscript">
function A(){
  console.log('foo');
};
A();
</pre>
<p>Which practically means that, yes, you can call the functions before they&#8217;re written in your code.  It won&#8217;t matter, because the entire function gets hoisted to the top of its containing scope.  (This is contrasted with variables, which only have their declaration hoisted, not their contents, as we&#8217;ll see in the next section).</p>
<h4>2. No function declarations in <code>If</code> statements (or loops, etc)</h4>
<p>You can&#8217;t define functions this way in expressions, for example <code>if</code> statements, which is common if we want to define different versions of a function for different circumstances, usually to address browser inconsistencies.  Well, you <em>can</em> in some implementations, but the way the code is processed is inconsistent (kangax has documented the inconsistencies <a href="http://kangax.github.com/nfe/">here</a>).  If you want to use this pattern, use function expressions instead.</p>
<h4>3. Functions declarations must have names</h4>
<p>This method doesn&#8217;t allow you to create anonymous functions, meaning that you always have to give it an identifier (in this case we&#8217;ve used &#8220;A&#8221;).</p>
<h3>Function expressions: var B = function(){};</h3>
<p>A function expression looks similar to function declarations, except that the function is assigned to a variable name.  Though functions are not primitive values in JavaScript, this is the way they can be utilized to their full effect in this functional language.  Functions are &#8220;<a href="http://en.wikipedia.org/wiki/First-class_function">first class</a>&#8220;:</p>
<blockquote><p>&#8220;[JavaScript] supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures&#8221;</p></blockquote>
<h4>1. Anonymous functions (they don&#8217;t need names)</h4>
<p>The function name is optional in function expressions, and we call these anonymous.  Here we&#8217;re setting the variable B equal to an anonymous function:</p>
<pre name="code" class="jscript">
var B = function(){};
</pre>
<h4>2. Variable declaration hoisting</h4>
<p>Variable declarations are hoisted to the top of their scope, somewhat similarly to function hoisting <em>except</em> the contents of the variable are not hoisted as well.  This happens with all variables, and it means it&#8217;s now happening with our functions, now that we&#8217;re assigning them to variables.</p>
<p>This code:</p>
<pre name="code" class="jscript">
var A = function(){};
var B = function(){};
var C = function(){};
</pre>
<p>Will be executed as this:</p>
<pre name="code" class="jscript">
var A, B, C;  // variable declarations are hoisted
A = function(){};
B = function(){};
C = function(){};
</pre>
<p>Therefore the order of setting and calling this type of function is important:</p>
<pre name="code" class="jscript">
// this works
var B = function(){};
B();

// this doesn't work
B2();  // TypeError (B2 is undefined)
var B2 = function(){};
</pre>
<p>The second example gives us an error because only the variable B2&#8242;s declaration is hoisted, but not its definition, thus the &#8220;undefined&#8221; error.</p>
<h3>Function expressions with grouping operators: var C = (function(){});</h3>
<p>These really aren&#8217;t different from plain old function expressions and aren&#8217;t really seen in the wild (so maybe they&#8217;re just good for JavaScript quizzes?).  Recently this way of declaring functions was brought up in <a href="http://ironjs.wordpress.com/2011/06/22/my-gripes-with-javascript/">this article</a> and confused some folks including myself.</p>
<p>Here&#8217;s a good way to see what&#8217;s happening:</p>
<pre name="code" class="jscript">
function(){};  // SyntaxError
(function(){});
</pre>
<p>Why does one work and the other doesn&#8217;t?  The first example is a function declaration, and we learned above that we can&#8217;t declare them anonymously &#8211; that is, they must have a name.  That&#8217;s why we&#8217;re getting the syntax error.</p>
<p>The second example is using parenthesis &#8211; grouping operators &#8211; and is therefore evaluated differently, as a function expression.  The grouping operators are the things we use to help show what should be evaluated first, as in mathematical problems.  We&#8217;re saying &#8220;evaluate this first, then take the result and do something with it&#8221;:</p>
<pre name="code" class="jscript">
(1 + 2) * 3;  // 9
1 + (2 * 3);  // 7
</pre>
<p>In the first example we&#8217;re saying &#8220;first add 1 and 2, then take the result and multiply by 3&#8243;, whereas in the second example we&#8217;re saying &#8220;first multiply 2 and 3, then take the result and add 1&#8243;.</p>
<p>Because functions are first class, we can use similar grouping operators.  Here&#8217;s a facetious example, but it shows how we can essentially drop in a function in the same way:</p>
<pre name="code" class="jscript">
(function(){} + 1);  // function(){}1
</pre>
<p>The result is a string (because toString is being called on the function, then added/appended with 1), but you get the idea I hope.</p>
<p>When the JavaScript engine encounters the opening parenthesis here, we&#8217;re essentially saying &#8220;ok, start grouping this together with something else&#8221;.  Using our technical terms, we&#8217;re telling the engine that we&#8217;re not making a function declaration, but instead a function expression.  And then we can assign the result to a variable:</p>
<pre name="code" class="jscript">
(function(){});           // resulting function not assigned
var foo = (function(){}); // resulting function assigned to foo
var bar = function(){};   // resulting function assigned to bar
</pre>
<p>Here we can see that foo and bar are really just the same, because in foo we&#8217;re not grouping the function together with anything but itself.</p>
<h3>Named function expression: var D = function foo(){};</h3>
<p>Here we have our same old friend, the function expression.  But instead of assigning the variable to an anonymous function, we&#8217;re assigning it to a named function (with the name foo).</p>
<h4>1. The function name is only accessible within the function</h4>
<p>We haven&#8217;t exposed the function name (foo) to the enclosing scope (in this case the global scope):</p>
<pre name="code" class="jscript">
var D = function foo(){
  console.log(typeof foo);
};
D();                       // function
console.log(typeof foo);   // undefined
</pre>
<h4>2. Useful for recursion</h4>
<p>Because the function&#8217;s name is accessible in the function itself, this turns out to be useful for recursive functions, much more useful than the plain old anonymous function.</p>
<p>Here&#8217;s a trivial recursive function to illustrate calling itself from within the named function expression:</p>
<pre name="code" class="jscript">
var countdown = function a(count){
  if(count > 0) {
    count--;
    return a(count);  // we can also do this: a(--count), which is less clear
  }
  console.log('end of recursive function');
}
countdown(5);
</pre>
<h4>3. Useful for debugging</h4>
<p>As a <a href="http://kangax.github.com/nfe/">few</a> <a href="http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/">have</a> pointed out, giving previously anonymous functions names helps in debugging, since the function name shows up on the call stack.</p>
<h4>4. Quirks: JScript&#8217;s bad implementation</h4>
<p><a href="http://kangax.github.com/nfe/">kangax</a> points out that named function expressions are basically poison to JScript, Internet Explorer&#8217;s implementation of JavaScript.</p>
<p>The named function becomes a global variable, is hoisted like a function declaration, and actually ends up creating multiple instances of the same function.</p>
<h3>Immediately-invoked function expressions (IIFE): var E = (function(){return function(){}})();</h3>
<p>&#8220;Execute this function, whose return value is another function, and assign that to the variable E&#8221;.  This may seem like magic, but it&#8217;s actually quite simple, and the pattern is powerful and has useful applications, the most famous of which is the <a href="http://www.klauskomenda.com/code/javascript-programming-patterns/#module">module pattern</a>.</p>
<p>First we&#8217;ll use an example that doesn&#8217;t look like magic:</p>
<pre name="code" class="jscript">
var foo = function(){
  return 'bar';
};
var output = foo();
console.log(output);  // 'bar'
</pre>
<p>We already learned about grouping operators above, so you should feel comfortable with saying this is equivalent:</p>
<pre name="code" class="jscript">
var foo = function(){
  return 'bar';
};
var output = (foo)(); // note the extra grouping operators
console.log(output);  // 'bar'
</pre>
<p>Since foo is pointing to our function expression, we know that we can simply refrain from using the variable &#8220;foo&#8221; and drop in the entire function as an anonymous function (since functions are first class, after all!):</p>
<pre name="code" class="jscript">
var output = (function(){
  return 'bar';
})();
console.log(output);  // 'bar'
</pre>
<p>Hey wait, we just arrived at the magical resulting function!  It turns out to be not so magical after all, once we break it down and see it for what it is.  It&#8217;s simply shorthand for the code we wrote originally, where we defined a function, executed it, and defined output to be its return value.</p>
<p>I&#8217;ve included this method on the list of declaring functions because we can assign the return value to itself be a function:</p>
<pre name="code" class="jscript">
var E = (function(){
  return function(){}
})();
</pre>
<h4>Applications</h4>
<p>There are good applications for this, including information hiding using in the module pattern, (<a href="http://ejohn.org/blog/partial-functions-in-javascript/">partial application</a>, for example), and other clever uses of it.  It&#8217;s definitely not a trivial pattern.</p>
<h3>Function constructor: var F = new Function();</h3>
<p>This method is extremely old and it&#8217;s not recommended to be used.  You pass in an unlimited number of arguments in the front, then the actual function body appears as a string in the last argument (because it&#8217;s a string, it&#8217;s effectively the equivalent of eval(), and isn&#8217;t recommended).</p>
<h4>1. Defining the function</h4>
<p>You can create a function like this:</p>
<pre name="code" class="jscript">
var F = new Function('arg1', 'arg2', 'console.log(arg1 + ", " + arg2)');
F('foo', 'bar');  // 'foo, bar'
</pre>
<h4>2. You don&#8217;t need the <code>new</code> operator</h4>
<p>You can simply write <code>var F = Function();</code> to get the same result.</p>
<h4>3. Quirks</h4>
<p>The <a href="https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression">MDN docs</a> have some good examples of the quirks, including the fact that functions declared with the Function constructor don&#8217;t inherit their current scope properly (i.e. a closure isn&#8217;t formed).</p>
<p>What this means is that they don&#8217;t have access to variables in their enclosing scope, which isn&#8217;t particularly useful:</p>
<pre name="code" class="jscript">
function foo(){
  var bar = 'blah';

  var first = new Function('console.log(typeof bar)');
  first();   // undefined

  var second = function(){
    console.log(typeof bar);
  }
  second();  // string
}
foo();
</pre>
<p>In the function &#8220;first&#8221;, we&#8217;re using the Function constructor, so it doesn&#8217;t have access to the variable bar.  However, if we use the function &#8220;second&#8221;, which is a function expression, it does in fact have access to variables defined in its enclosing scope (via closure).</p>
<p>In other words, <em>don&#8217;t use the Function constructor</em>.</p>
<h3>Special case &#8211; object constructor: var G = new function foo(){};</h3>
<p>I saved this for last because we&#8217;re not really defining a function, though we are using the function keyword, so it&#8217;s worth noting at least.</p>
<p><code>new function(){};</code> creates a new object and invokes the anonymous function as its constructor.  If an object is returned from the function, that becomes the resulting object, otherwise a new object is created from scratch and function is executed in the context of that new function (let&#8217;s save the details for another post!).</p>
<p>It&#8217;s a bit unusual to see it in this form.  Let&#8217;s do it the proper way:</p>
<pre name="code" class="jscript">
var Person = function(){
  console.log(this);  // Person
}
var joe = new Person();
</pre>
<p>So really with the new operator, we are giving it a new &#8216;this&#8217; context and then executing the given function with that new context.  Much different than the function definitions we&#8217;ve been dealing with above!  This does into a whole new topic, and we&#8217;ll save that for later!</p>
<h3>Further reading</h3>
<p><a href="http://kangax.github.com/nfe/">Named function expressions demystified</a> (kangax)</p>
<p><a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/">Immediately-Invoked Function Expression (IIFE) (Ben Alman)</a></p>
<p><a href="https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope">Functions and function scope</a> (Mozilla Developer Network &#8211; MDN)</p>
<p><a href="http://stackoverflow.com/questions/1140089/how-does-an-anonymous-function-in-javascript-work">How does an anonymous function in JavaScript work? (StackOverflow)</a></p>
<p><a href="http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/">Function Declarations vs. Function Expressions (JavaScript, JavaScript by Angus Croll)</a></p>
<p><a href="http://www.amazon.com/gp/product/0596805527/">JavaScript: The Definitive Guide</a> (classic book by David Flanagan)</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/different-ways-of-defining-functions-in-javascript-this-is-madness/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>On professional self-worth</title>
		<link>http://davidbcalhoun.com/2011/on-professional-self-worth</link>
		<comments>http://davidbcalhoun.com/2011/on-professional-self-worth#comments</comments>
		<pubDate>Tue, 21 Jun 2011 12:42:59 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbcalhoun.com/?p=703</guid>
		<description><![CDATA[Huge huge rant incoming, but all is not said and done, and much is open for debate of course. Counterpoints and criticisms are more than welcome in the comments. This is just my opinion based on my experience at this point in time. Self-worth: the rich man and the poor man For a long while [...]]]></description>
			<content:encoded><![CDATA[<p>Huge huge rant incoming, but all is not said and done, and much is open for debate of course.  Counterpoints and criticisms are more than welcome in the comments.  This is just my opinion based on my experience at this point in time.</p>
<h3>Self-worth: the rich man and the poor man</h3>
<p>For a long while there have been places in the world that view self-worth as largely tied to wealth.  No doubt there is more than just money, as even within the rich community there&#8217;s a distinction between the established rich and the &#8220;nouveau riche&#8221;, or the newly rich.  One is ranked higher than the other, but nonetheless the rich are themselves seen as being more important than the average person.</p>
<p>You might not believe me.  That means it&#8217;s time for a thought experiment!</p>
<p>One way to hammer home this point is to posit a classic thought experiment.  There are two people &#8211; one rich and one poor &#8211; and this is all the information we have about them (this is important).  Assuming that one of them will die in some horrific way and we can only choose to save one, most people would probably save the rich person (assuming they don&#8217;t have a bias or some psychological complex against rich folks).  Remember, we have no other information about them other than one is rich and one is poor.  The aim of the thought experiment, rather than trying to give a realistic scenario, is to simply try to show us that we give the rich person preference.  At least ij the case where we have no other information.</p>
<p>And it&#8217;s not even that we think we might receive a reward from the rich person!  Even if we figure that in, we still give preference to the rich person, probably in part because we think that they must be somewhat more important than the poor person.  They must have acquired that money some way, after all.  Possobly even through hard work.  The poor person, we assume, must be poor for a reason, and that might be through sheer laziness.  So we have a hard worker versus a lazy worker&#8230; which one is more worthy to live?  And it&#8217;s only those hasty assumptions that we have to deal with.</p>
<h3>Professional worth: employees of famous and nonfamous companies</h3>
<p>Laying aside issues of money for a moment, let&#8217;s perform a similar thought experiment, except with different people.  One person works at company X, which no one has really heard of, and the other person works at company Y, which at the time is a wildly famous and reputable company.  Because this industry is so fickle and subject to change, at the time of this writing this famous company might be Facebook, Google, or Twitter.  Or any other company which has the tech zeitgeist or mojo at the time.</p>
<p>Assuming we know nothing else but the people&#8217;s employers (and laying aside biases and hatred for certain companies), if we put these people on the line, the one employee of a no-name company and the other employee of a famous company, we would probably choose to save the latter.  For much of the same reasons as above.  For instance, this person got a job at Facebook, so they must be smart and a hard worker.  On the other hand, the person at the no-name company (i.e. the vast majority of people out there) is probably not as smart or not as hard-working.  After all, if they were, then they would&#8217;ve been at (famous company) by now!  Therefore they are undoubtedly less worthy professionally, and by hasty extension, less worthy as a human being (remember, we have no other information to base our conclusion off of).</p>
<p>So it is!  Death to the employee of the nonfamous company!</p>
<h3>Work history, first impressions, and professional self-worth</h3>
<p>We chose to save the rich person and the Facebook engineer. The good thing is that luckily almost no one thinks in these horrible black-and-white terms, and we always take into account other available factors.  For instance, as an example of a poor person we might have Mother Teresa and as a rich person we might have mean old Donald Trump.  No one in their right mind would send Mother Teresa off to the gallows while letting Trump off (regardless of what you think of Trump really).</p>
<p>The problem here is that although we do take into account different factors, professionally we (and recruiters) weigh our work history much too heavily in the grand scheme of things.  We take other factors into consideration, sure, but work history is a huge deciding factor as far as people are paid attention to, give off good first impressions, or are even given a single glance by recruiters.</p>
<p>This isn&#8217;t totally unwarranted, I should say.  Chances are, if someone worked at a few famous companies, there&#8217;s a good chance they are a better than average engineer, even though there&#8217;s no guarantee of this (there are always exceptions).  But that&#8217;s not the problem here.  The problem is because this is given a disproportionate amount of weight, people start to view this as THE deciding factor in whether to work for a company.  Name-brand recognition becomes a goal-in-itself.  Money always matters, sure, but professionally there is little that can beat having a reputable name brand on a resume.</p>
<p>So what happens in practice?  An engineer becomes employed at a famous big company, is put to work maintaining some existing platforms, and at the end of a year perhaps learns some things that make them a better engineer.  But the same person instead working for some no-name startup might in the same period of time learn many more technologies, solve many more problems, and have a bit more freedom and opportunity to create (though they won&#8217;t necessarily learn best practices or scaling issues that typically come with famous large companies, but there&#8217;s more to being a good engineer than that!).  Each gets an opportunity to get their hands dirty with different varieties of dirt.  At the end of the day, I would say the latter very well becomes a more well-rounded engineer, instead of a generic single-functioned cog in some big company machine.</p>
<p>Ok, now my bias is showing through brilliantly!</p>
<p>Let&#8217;s at least say, for the purposes of argument, that both engineers are equally skilled (though this is hard to quantify, though, obviously).  So who do the recruiters contact, the employee at the famous company or the employee at the nonfamous company?  Who gets more attention from people in general when they&#8217;re asked where they work?  In short, whose professional life is a priori more highly valued?  You already know the answer.</p>
<h3>Final thoughts</h3>
<p>We MUST become more confident of our skills (I need to work on this myself), and we must be tough enough and realistic enough to know our own professional worth.  Appearances count for much in this world, and too much at that.  But what better to maintain if we are authentic human beings: an appearance or something deeper?</p>
<p>Famous companies do look good on resumes in the same way Ivy Leagues colleges look good on the very same piece of paper.  But don&#8217;t make this a deciding factor when choosing an employer.  It&#8217;s true that it will help you find more jobs and get more respect in the long run, but then you are wasting your time doing something you don&#8217;t want to do for the duration, for a company that exists for its own ends, not the ends of its employees (this is true of most companies out there, to be fair).  If you are ok wasting your time for a cause such as this, then go for it. It seems some people are ok with that.  At the very least be aware of it.</p>
<p>So what happens to the passionate engineers who actually do want to work for a famous company for reasons other than brand recognition?  They might not always get the job.  But it&#8217;s definitely not the end of the world.  No one should be disheartened because Google turned them away for not being able to answer today&#8217;s technological equivalent of &#8220;how many angels can dance on the head of a pin&#8221; (or other mental masturbation puzzles).  In the end it&#8217;s you that makes you a worthy professional and a good engineer.  If your job doesn&#8217;t actually give you a chance to be one, you can still become one on your own.  I would say most people are capable of this if they invest the effort.</p>
<p>But working for a famous company, and for its own sake?  It doesn&#8217;t necessarily make you a good engineer, any more than wearing glasses and dressing in a suit gives more validity to your opinions (even though many people sadly tend to think otherwise).</p>
<p>(Note to self: I wrote this on the banks of the Kamogawa River in Kyoto on my iPad.  I was enjoying the moment and obviously in a contemplative mood!)</p>
]]></content:encoded>
			<wfw:commentRss>http://davidbcalhoun.com/2011/on-professional-self-worth/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

