<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEMFR3kyeyp7ImA9WhJbEE4.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010</id><updated>2012-09-19T01:33:36.793-05:00</updated><category term="ruby" /><category term="selfindulgence" /><category term="haml" /><category term="google app engine" /><category term="meh" /><category term="wiki" /><category term="javascript" /><category term="s3" /><category term="java" /><category term="sass" /><category term="web" /><category term="pivotal tracker" /><category term="politics" /><category term="startup" /><category term="maven" /><category term="snipsnipe" /><category term="terracotta" /><category term="compass" /><category term="toons" /><category term="gae" /><category term="databases" /><category term="hungover" /><category term="seo" /><category term="jquery" /><category term="interview" /><category term="git" /><category term="python" /><category term="tips" /><category term="code te ching" /><category term="textbarf" /><category term="sorry" /><category term="organ grinder" /><category term="review" /><category term="macfanboy" /><category term="rant" /><title>過労死 Coderoshi</title><subtitle type="html">Death by Overcoding</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.coderoshi.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.coderoshi.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>168</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/coderoshi" /><feedburner:info uri="coderoshi" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/2.0/" /><entry gd:etag="W/&quot;DEMFR3Y7eSp7ImA9WhJbEE4.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-6567703466327236055</id><published>2012-09-19T01:33:00.001-05:00</published><updated>2012-09-19T01:33:36.801-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-19T01:33:36.801-05:00</app:edited><title>On Eggheads</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Some people are too smart for their own good.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-LLIO-PeJ1QI/UFliTD841lI/AAAAAAAAAiI/w6ITlUhb64Q/s1600/lisa-simpson-graph.jpeg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-LLIO-PeJ1QI/UFliTD841lI/AAAAAAAAAiI/w6ITlUhb64Q/s1600/lisa-simpson-graph.jpeg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I don't mean this in any mean or&amp;nbsp;derogatory&amp;nbsp;way. I'm a firm believer that it's always better to be more, rather than less smart--even if it causes you some degree of discomfort when attempting to communicate with others.&lt;br /&gt;
&lt;br /&gt;
However. You cannot ignore&amp;nbsp;the oft-quoted "IQ gap"--the theory that&amp;nbsp;a 30-point difference in IQ renders communication difficult--goes both ways. Not only do those of a lower IQ find it hard to follow a conversation lead by the more intelligent agent (or as I prefer the more technical nomenclature "Egghead"), so too does the higher IQ person find it difficult to know what it's like to be lower.&lt;br /&gt;
&lt;br /&gt;
In other words, you don't know what you don't know.&lt;br /&gt;
&lt;br /&gt;
I find this to be the case in certain organizations as well. An organization can actually be too smart for its own good... they can be too Egghead to talk to your average person. If your group is run by ten 160 IQ people, you're probably going to do amazing work. Sadly, most people probably won't ever know it.&lt;br /&gt;
&lt;br /&gt;
Just as the &lt;a href="http://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect" target="_blank"&gt;Dunning-Kruger Effect&lt;/a&gt; points out, it takes knowledge to recognize genuine knowledge in others. If the average person is 100 IQ (and they always are), your 160 IQ company will have a hard sell. Sure, you'll get a few adopters. They'll sing your praises. But when people ask: "yes, yes... but what do you &lt;i&gt;do&lt;/i&gt;?", you might end up like &lt;a href="http://www.zeromq.org/" target="_blank"&gt;ZeroMQ&lt;/a&gt;, and so many other academic curiosities. Something brilliant, amazing, and very, very hard to explain.&lt;br /&gt;
&lt;br /&gt;
I'm not advocating hiring dumber people. Far from it. I just wanted to bring up the point that, oh you rare brilliant companies... pay close attention. Don't discount what the average person thinks about you. Make an effort to help them see your brilliance. In software, this is documentation, tools, and constant communication.&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-ngo3hF3O54:mU3wbovkNl0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-ngo3hF3O54:mU3wbovkNl0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=-ngo3hF3O54:mU3wbovkNl0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-ngo3hF3O54:mU3wbovkNl0:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-ngo3hF3O54:mU3wbovkNl0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=-ngo3hF3O54:mU3wbovkNl0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=6567703466327236055" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6567703466327236055?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6567703466327236055?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/-ngo3hF3O54/on-eggheads.html" title="On Eggheads" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-LLIO-PeJ1QI/UFliTD841lI/AAAAAAAAAiI/w6ITlUhb64Q/s72-c/lisa-simpson-graph.jpeg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2012/09/on-eggheads.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQHR3c4cSp7ImA9WhJUF0o.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-6101609593050016586</id><published>2012-09-16T01:08:00.003-05:00</published><updated>2012-09-16T01:18:56.939-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-16T01:18:56.939-05:00</app:edited><title>On Resurgence</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
It's been quite a while since I visited this blog. A lot has changed.&lt;br /&gt;
&lt;br /&gt;
I moved to &lt;a href="http://www.ifc.com/shows/portlandia" rel="nofollow" target="_blank"&gt;Portland&lt;/a&gt;. I changed &lt;a href="http://basho.com/blog/technical/2012/07/18/Eric-Redmond-Joins-Basho-Eng-Team/" rel="nofollow" target="_blank"&gt;careers&lt;/a&gt;. I took up &lt;a href="https://sphotos-b.xx.fbcdn.net/hphotos-ash3/47518_10100152425629748_4313151_n.jpg" rel="nofollow" target="_blank"&gt;glass&lt;/a&gt; &lt;a href="https://sphotos-b.xx.fbcdn.net/hphotos-ash3/67491_10100177981420738_6098604_n.jpg" rel="nofollow" target="_blank"&gt;blowing&lt;/a&gt;, published a &lt;a href="http://www.amazon.com/Seven-Databases-Weeks-Modern-Movement/dp/1934356921" rel="nofollow" target="_blank"&gt;book&lt;/a&gt;, &lt;a href="https://sphotos-b.xx.fbcdn.net/hphotos-ash3/163083_10100250993459028_3358205_n.jpg" rel="nofollow" target="_blank"&gt;traveled&lt;/a&gt; the world, &lt;a href="http://railsberry.com/2012/speakers/ericredmond" rel="nofollow" target="_blank"&gt;spoke&lt;/a&gt;&amp;nbsp;at and &lt;a href="http://railsgirls.com/portland" rel="nofollow" target="_blank"&gt;organized&lt;/a&gt; some conferences, and built a &lt;a href="http://www.meetup.com/pdxweb" target="_blank"&gt;community&lt;/a&gt;. Where I used to obsess about the minutiae of project management and building an optimized development team, I now care much more about the people around me, and building a better community.&amp;nbsp;In some ways I'm probably better known than when I once obsessed about being well known -- when I stopped writing so much&amp;nbsp;&lt;i&gt;about&lt;/i&gt; doing, and simply just &lt;i&gt;did&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
But at my core I still crave the act of authorship, no longer for any overtly self-serving purposes, but simply because I care enough to contribute. In truth, I have been writing a bit,&amp;nbsp;not on this blog, but rather &lt;a href="http://sevenweeks.org/" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="http://crudcomic.com/" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="http://wiki.basho.com/" target="_blank"&gt;here&lt;/a&gt;&amp;nbsp;and &lt;a href="http://www.amazon.com/Seven-Databases-Weeks-Modern-Movement/dp/1934356921" target="_blank"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
So what should I write about?&amp;nbsp;&lt;i&gt;NoSQL&lt;/i&gt;? I'm uniquely positioned to have worked professionally with and for a&amp;nbsp;&lt;a href="http://wiki.basho.com/Riak.html" target="_blank"&gt;number&lt;/a&gt;&amp;nbsp;&lt;a href="http://redis.io/" target="_blank"&gt;of&lt;/a&gt;&amp;nbsp;&lt;a href="http://neo4j.org/" target="_blank"&gt;NoSQL&lt;/a&gt;&amp;nbsp;&lt;a href="http://mongodb.org/" target="_blank"&gt;databases&lt;/a&gt;.&amp;nbsp;&lt;i&gt;Tech writing&lt;/i&gt;? I've certainly done more than most coders will ever consider by their own&amp;nbsp;&lt;a href="http://wiki.basho.com/" target="_blank"&gt;volition&lt;/a&gt;.&amp;nbsp;&lt;i&gt;Community building&lt;/i&gt;? My&amp;nbsp;&lt;a href="http://railsgirls.com/portland" target="_blank"&gt;favorite&lt;/a&gt;&amp;nbsp;thankless&amp;nbsp;&lt;a href="http://www.meetup.com/pdxweb" target="_blank"&gt;task&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This is just another space, adding to the noise, contributing to the information heat death of the internet. Maybe I'll return, maybe my one-time 10,000+ readers will return. Maybe not. But I felt compelled to announce to this space that I have not forgotten about this site I once so eagerly built (seemingly) a lifetime ago, now populated exclusively by stragglers and bots.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=B7WYtZECWtE:x6ElhxIQPDw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=B7WYtZECWtE:x6ElhxIQPDw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=B7WYtZECWtE:x6ElhxIQPDw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=B7WYtZECWtE:x6ElhxIQPDw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=B7WYtZECWtE:x6ElhxIQPDw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=B7WYtZECWtE:x6ElhxIQPDw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=6101609593050016586" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6101609593050016586?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6101609593050016586?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/B7WYtZECWtE/on-resurgence.html" title="On Resurgence" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2012/09/on-resurgence.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMBRHYzeCp7ImA9Wx5QFEk.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-1768954893498701159</id><published>2010-09-02T11:47:00.002-05:00</published><updated>2010-09-02T11:54:15.880-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-02T11:54:15.880-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 58</title><content type="html">The ten thousand things are presented by &lt;span style="font-weight:bold;"&gt;Code&lt;/span&gt;.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Code&lt;/span&gt; is, and is presented by, abstraction.&lt;br /&gt;Abstraction is presented by &lt;span style="font-style:italic;"&gt;code&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Code helps the ten thousand things by entailing understanding.&lt;br /&gt;abstraction helps understanding by entailing structure.&lt;br /&gt;code helps abstraction by giving definition.&lt;br /&gt;comments help code by giving direction.&lt;br /&gt;&lt;br /&gt;Like the mountain directs the storm without restraining the sun,&lt;br /&gt;Comments direct the coder without restraining the code.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=DvWAHBP8n5c:zXCSL69MZVE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=DvWAHBP8n5c:zXCSL69MZVE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=DvWAHBP8n5c:zXCSL69MZVE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=DvWAHBP8n5c:zXCSL69MZVE:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=DvWAHBP8n5c:zXCSL69MZVE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=DvWAHBP8n5c:zXCSL69MZVE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=1768954893498701159" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/1768954893498701159?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/1768954893498701159?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/DvWAHBP8n5c/code-te-ching-verse-58.html" title="Code Te Ching - Verse 58" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/09/code-te-ching-verse-58.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIGRH06eCp7ImA9WxFXFk4.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-2001650392037455375</id><published>2010-05-23T11:28:00.002-05:00</published><updated>2010-05-23T12:08:45.310-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-23T12:08:45.310-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery" /><title>Multiple to Single Select</title><content type="html">&lt;span style="font-style:italic;"&gt;(If you're in a hurry - you can get the &lt;a href="http://github.com/coderoshi/multi_single_select"&gt;Multi Single Select code&lt;/a&gt; from Github. I also have a &lt;a href="http://coderoshi.appspot.com/multi_single_select/test.html"&gt;Multi Single Select example&lt;/a&gt; on &lt;abbr title="Google App Engine" style="border-bottom:1px dashed grey;"&gt;GAE&lt;/abbr&gt;).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have a problem. I've become addicted to &lt;a href="http://en.wikipedia.org/wiki/Progressive_enhancement"&gt;progressive enhancement&lt;/a&gt;. I can't bring myself to write a single line of CSS or Javascript until I'm certain my web application could work in &lt;a href="http://en.wikipedia.org/wiki/Lynx_(web_browser)"&gt;Lynx&lt;/a&gt;. But this is 2010 - and since 99% of users have every right to expect a little more zazz than standard control widgets, I've been cranking out &lt;abbr title="Unobtrusive JavaScript" style="border-bottom:1px dashed grey;"&gt;UJS&lt;/abbr&gt; libs. This is one of them.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://coderoshi.appspot.com/multi_single_select/test.html"&gt;Multi Single Select&lt;/a&gt; is an onload library which uses jquery to turn a boring old multi select tag like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_E3_4LXYT1LI/S_lYRG2r8lI/AAAAAAAAAUw/3-OwkTuEeEk/s1600/Multi-Single+Select-1.jpg"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 99px; height: 76px;" src="http://3.bp.blogspot.com/_E3_4LXYT1LI/S_lYRG2r8lI/AAAAAAAAAUw/3-OwkTuEeEk/s320/Multi-Single+Select-1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5474503872966554194" /&gt;&lt;/a&gt;&lt;br /&gt;Into a sexy single select box, where all choices become tags (which can be removed by clicking the X)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_E3_4LXYT1LI/S_lYh_GgwxI/AAAAAAAAAU4/Z6lEUw__7Z4/s1600/Multi-Single+Select-1-2.jpg"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 158px; height: 66px;" src="http://3.bp.blogspot.com/_E3_4LXYT1LI/S_lYh_GgwxI/AAAAAAAAAU4/Z6lEUw__7Z4/s320/Multi-Single+Select-1-2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5474504162943222546" /&gt;&lt;/a&gt;&lt;br /&gt;Build your multi select as normal html. Then in your header add the jquery.multi_single_select.js library, and code similar to this in your script tag:&lt;pre&gt;jQuery(document).ready(function() {&lt;br /&gt;  $('#whopper').multi_single_select({list_class:'toppings', title:'Topping'});&lt;br /&gt;});&lt;/pre&gt;Selecting from the "add" group in the drop-down adds the item to the submit list. Selecting from the "remove" group will remove them (or just click the external tag's "x").&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_E3_4LXYT1LI/S_lZObOwaFI/AAAAAAAAAVA/S79HJVWb5t4/s1600/System.jpg"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 129px; height: 169px;" src="http://1.bp.blogspot.com/_E3_4LXYT1LI/S_lZObOwaFI/AAAAAAAAAVA/S79HJVWb5t4/s320/System.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5474504926408239186" /&gt;&lt;/a&gt;&lt;br /&gt;This library is completely unobtrusive. It submits values in the same way a normal multi select would. Your server-side actions will know no difference.&lt;br /&gt;&lt;br /&gt;Also, the &lt;a href="http://github.com/coderoshi/multi_single_select"&gt;Multi Single Select&lt;/a&gt; code on github contains a sample css lib to make your tags look all pretty.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m8NzhuF8qXw:8Z_CliSBrLU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m8NzhuF8qXw:8Z_CliSBrLU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=m8NzhuF8qXw:8Z_CliSBrLU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m8NzhuF8qXw:8Z_CliSBrLU:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m8NzhuF8qXw:8Z_CliSBrLU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=m8NzhuF8qXw:8Z_CliSBrLU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=2001650392037455375" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2001650392037455375?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2001650392037455375?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/m8NzhuF8qXw/multiple-to-single-select.html" title="Multiple to Single Select" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_E3_4LXYT1LI/S_lYRG2r8lI/AAAAAAAAAUw/3-OwkTuEeEk/s72-c/Multi-Single+Select-1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/02/multiple-to-single-select.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcERXo-eyp7ImA9WxFTEEg.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-3346709614135562870</id><published>2010-03-31T07:23:00.000-05:00</published><updated>2010-03-31T10:40:04.453-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-31T10:40:04.453-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 57</title><content type="html">When managers manage teams, management manages to manage management.&lt;br /&gt;When teams manage management, the means manage to manage management.&lt;br /&gt;&lt;br /&gt;Thus when managers do not manage management, the team manages to manage.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=AIbThhBWHck:wzSp_4IhSLw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=AIbThhBWHck:wzSp_4IhSLw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=AIbThhBWHck:wzSp_4IhSLw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=AIbThhBWHck:wzSp_4IhSLw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=AIbThhBWHck:wzSp_4IhSLw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=AIbThhBWHck:wzSp_4IhSLw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=3346709614135562870" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3346709614135562870?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3346709614135562870?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/AIbThhBWHck/code-te-ching-verse-57.html" title="Code Te Ching - Verse 57" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/03/code-te-ching-verse-57.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EGQH04eSp7ImA9WxBaE0o.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-3335939394528840762</id><published>2010-03-23T16:15:00.005-05:00</published><updated>2010-03-23T16:27:01.331-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-23T16:27:01.331-05:00</app:edited><title>On Eraser Stains</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_E3_4LXYT1LI/S6kx0NmkARI/AAAAAAAAAUg/7BJzDBT8RSM/s1600-h/Plastic_eraser.jpeg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_E3_4LXYT1LI/S6kx0NmkARI/AAAAAAAAAUg/7BJzDBT8RSM/s320/Plastic_eraser.jpeg" border="0" alt=""id="BLOGGER_PHOTO_ID_5451943596983058706" /&gt;&lt;/a&gt;&lt;br /&gt;Have you ever written something wrong in pencil on a piece of paper? Of course. That's why erasers were invented. Have you ever done it twice? Three times? Four? Eventually, the ability of your eraser to function properly will wear out - leaving a dark greasy stain on the paper.&lt;br /&gt;&lt;br /&gt;Have you ever made a mistake designing software? Of course. That's why refactoring was invented. In much the same way, the constant writing and rewriting of software creates artifacts over time which can't be blamed on any one person, or idea, or decision. It's simply a function of imposing incremental development changes on the substrate of the real world, without a clear idea in mind.&lt;br /&gt;&lt;br /&gt;These are eraser stains in development. Sometimes the best course of action is a new piece of paper (I mean, a rewrite).&lt;br /&gt;&lt;br /&gt;Before you 'static process' people use this as an example for why agile development has flaws - you have your own problems: you write with a pen.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=hHbQhuwH3zY:5slExVJKkZg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=hHbQhuwH3zY:5slExVJKkZg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=hHbQhuwH3zY:5slExVJKkZg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=hHbQhuwH3zY:5slExVJKkZg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=hHbQhuwH3zY:5slExVJKkZg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=hHbQhuwH3zY:5slExVJKkZg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=3335939394528840762" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3335939394528840762?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3335939394528840762?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/hHbQhuwH3zY/on-eraser-stains.html" title="On Eraser Stains" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_E3_4LXYT1LI/S6kx0NmkARI/AAAAAAAAAUg/7BJzDBT8RSM/s72-c/Plastic_eraser.jpeg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/03/on-eraser-stains.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AHRnc_cCp7ImA9WxBbFE8.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-6558801788936691682</id><published>2010-03-12T07:21:00.000-06:00</published><updated>2010-03-12T13:22:17.948-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-12T13:22:17.948-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 56</title><content type="html">Over-dependence on coding rules?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Uncreative.&lt;br /&gt;Under-appreciation of coding rules?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Unwise.&lt;br /&gt;&lt;br /&gt;Take the middle path.&lt;br /&gt;&lt;br /&gt;But what if a fork must&lt;br /&gt;be chosen? Which way to walk?&lt;br /&gt;&lt;br /&gt;Know this:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Remain in the center where understanding lies.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The path will&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;adjust&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;its&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-NomcH4lai4:sFSEDBnFiAw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-NomcH4lai4:sFSEDBnFiAw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=-NomcH4lai4:sFSEDBnFiAw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-NomcH4lai4:sFSEDBnFiAw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=-NomcH4lai4:sFSEDBnFiAw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=-NomcH4lai4:sFSEDBnFiAw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=6558801788936691682" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6558801788936691682?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6558801788936691682?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/-NomcH4lai4/code-te-ching-verse-56.html" title="Code Te Ching - Verse 56" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/03/code-te-ching-verse-56.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MBRng9eyp7ImA9WxBbEkg.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-7607255426679213504</id><published>2010-03-10T15:01:00.005-06:00</published><updated>2010-03-10T15:10:57.663-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-10T15:10:57.663-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="pivotal tracker" /><title>Pivotal Tracker Scrum Script</title><content type="html">At &lt;a href="http://www.thefutureis.mobi"&gt;Mobi&lt;/a&gt; we use &lt;a href="http://www.pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt; to keep track of new features, chores, bugs, etc. (if you don't use it, drop everything and SIGN UP NOW... I'll wait). Like many PT users, we also have daily Scrum updates.&lt;br /&gt;&lt;br /&gt;Since much of what we talk about in our standup meeting is information that is readily available in PT, I wrote this handy little script to spit out what I've done in the past 24 hours. You'll need to populate your own PT project id, token, and have ruby and curl installed. Enjoy.&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;#!/usr/bin/env ruby&lt;br /&gt;require 'date'&lt;br /&gt;&lt;br /&gt;PROJECT_ID = 'YOUR_PROJECT_ID'&lt;br /&gt;TOKEN = 'YOUR_PT_TOKEN'&lt;br /&gt;NAME = 'YOUR PT NAME'&lt;br /&gt;&lt;br /&gt;date = (Date.today - 1).strftime('%m/%d/%Y').gsub('/', '%2F')&lt;br /&gt;name = NAME.gsub(' ', '%20')&lt;br /&gt;&lt;br /&gt;val = `curl -s -H "X-TrackerToken: #{TOKEN}" -X GET https://www.pivotaltracker.com/services/v3/projects/#{PROJECT_ID}/stories?filter=state%3Afinished%2Cdelivered%2Caccepted%20owner%3A%22#{name}%22%20modified_since:#{date}`&lt;br /&gt;&lt;br /&gt;totes = []&lt;br /&gt;by_story_type = {}&lt;br /&gt;val.scan(/\&amp;lt;story\&gt;(.*?)\&amp;lt;\/story\&gt;/m){|story|&lt;br /&gt;  story = story.to_s&lt;br /&gt;  id = story.scan(/\&amp;lt;id[^&gt;]*\&gt;(.*?)\&amp;lt;\/id\&gt;/m)[-1].to_s&lt;br /&gt;  name = story.scan(/\&amp;lt;name\&gt;(.*?)\&amp;lt;\/name\&gt;/m).to_s&lt;br /&gt;  desc = story.scan(/\&amp;lt;description\&gt;(.*?)\&amp;lt;\/description\&gt;/m).to_s&lt;br /&gt;  state = story.scan(/\&amp;lt;current_state\&gt;(.*?)\&amp;lt;\/current_state\&gt;/m).to_s&lt;br /&gt;  story_type = story.scan(/\&amp;lt;story_type\&gt;(.*?)\&amp;lt;\/story_type\&gt;/m).to_s&lt;br /&gt;  next if totes.include?(id)&lt;br /&gt;  (by_story_type[story_type] ||= []) &lt;&lt; { :state =&gt; state, :name =&gt; name, :desc =&gt; desc}&lt;br /&gt;  totes &lt;&lt; id&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for story_type, datas in by_story_type&lt;br /&gt;  puts "#{story_type.capitalize}s"&lt;br /&gt;  for data in datas&lt;br /&gt;    puts "  #{data[:state]}: #{data[:name]}"&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=UC_rUyldBT8:xxMuvjSS9Wk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=UC_rUyldBT8:xxMuvjSS9Wk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=UC_rUyldBT8:xxMuvjSS9Wk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=UC_rUyldBT8:xxMuvjSS9Wk:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=UC_rUyldBT8:xxMuvjSS9Wk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=UC_rUyldBT8:xxMuvjSS9Wk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=7607255426679213504" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7607255426679213504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7607255426679213504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/UC_rUyldBT8/pivotal-tracker-scrum-script.html" title="Pivotal Tracker Scrum Script" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/03/pivotal-tracker-scrum-script.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8CQHs9fSp7ImA9WxBUEkw.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-5457644635349508555</id><published>2010-02-26T07:19:00.001-06:00</published><updated>2010-02-26T15:14:21.565-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-26T15:14:21.565-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 55</title><content type="html">Can anyone give a pattern for refactoring?&lt;br /&gt;Then there is no algorithm to follow?&lt;br /&gt;Yet there it happens, without steps?&lt;br /&gt;&lt;br /&gt;Order exists beyond our ability to capture it.&lt;br /&gt;&lt;br /&gt;A wise man once knew true granularity:&lt;br /&gt;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;&amp;nbsp;Write down the problem&lt;br /&gt;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;&amp;nbsp;Think real hard&lt;br /&gt;&amp;nbsp;&amp;nbsp;3.&amp;nbsp;&amp;nbsp;Write down the solution&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=vzSMSN97L70:KbOZj7ewwK4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=vzSMSN97L70:KbOZj7ewwK4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=vzSMSN97L70:KbOZj7ewwK4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=vzSMSN97L70:KbOZj7ewwK4:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=vzSMSN97L70:KbOZj7ewwK4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=vzSMSN97L70:KbOZj7ewwK4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=5457644635349508555" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/5457644635349508555?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/5457644635349508555?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/vzSMSN97L70/code-te-ching-verse-55.html" title="Code Te Ching - Verse 55" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/02/code-te-ching-verse-55.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IBQXs6fCp7ImA9WxBVFkU.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-7086254968078194734</id><published>2010-02-20T18:33:00.001-06:00</published><updated>2010-02-20T09:59:10.514-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-20T09:59:10.514-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery" /><title>Drop Down Like It's Hot</title><content type="html">I've never run across a search drop-down box that functioned exactly how I wanted. Most code for drop-down boxes seem bound up in a particular heavyweight framework (like dojo, or exjs), which are fine if you use them, but I don't. I use jQuery (an altogether different heavyweight framework).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;(Before getting too far along, grab the js and test &lt;a href="http://github.com/coderoshi/hotdrop"&gt;libs from github&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another problem is they always seem bent on a particular setup (a text input rather than a textarea) - or performing a particular function (load via ajax or pre-loaded array data) or assume a particular use-case (drop down for a search box). I want the flexibility to define my own client-side datasource parser, to have multiple drop-downs on a single page, or search from several data-sources at once, separating each type of data by title, or work like the gmail email text-area, where all non-word chars after the last comma performs a search of contacts - choosing an item appends to the list.&lt;br /&gt;&lt;br /&gt;Anyway, I have a big itch to scratch - to channel the Cathedral and Bazaar. Here is the problem scope, broken down:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Must work in text input fields and textareas&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow single or multiple elements chosen (separated by custom char)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow datasource from a local array, object, or remote (ajax, on-demand javascript, json, etc)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow custom parsing of datasource&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow multiple simulates datasources of various types (eg. 1 local + 2 ajax)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must optionally limit result sets, both by total and per datasource&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must optionally seperate datasources with a non-clickable header&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must optionally pre-parse input data (eg. ignore all non-word characters for purposes of searching)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must optionally suspend drop-down until a minimum number of chars are typed&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow for submission throttling&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must allow for caching return values&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must be able to move though elements via keyboard up/down, tab/enter to choose item, esc to close&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must close the drop-down when bluring the input field or clicking outside the drop-down&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must highlight matching typed characters in the dropdown data set&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must work on as many browsers as possible, otherwise degrade&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must use no toolkit beyond standard jquery&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must be unobtrusive javascript&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must look nice (or hot!), and feel natural to the user (not heavyweight or klunky)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must be easy to use (every choice must have reasonable defaults and at least one implementation)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;All above items must be optional and customizable&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Must be well documented so I don’t have to talk to anyone&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Basically, I'm taking the shotgun approach: cram as many features into this thing before it becomes absurd, and stop just shy of that.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://coderoshi.appspot.com/hotdrop/test.html"&gt;Here are several examples&lt;/a&gt; on usage. I appreciate any thoughts.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=yV41R4Mm5Rk:TWOzqm3Kg6Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=yV41R4Mm5Rk:TWOzqm3Kg6Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=yV41R4Mm5Rk:TWOzqm3Kg6Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=yV41R4Mm5Rk:TWOzqm3Kg6Q:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=yV41R4Mm5Rk:TWOzqm3Kg6Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=yV41R4Mm5Rk:TWOzqm3Kg6Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=7086254968078194734" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7086254968078194734?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7086254968078194734?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/yV41R4Mm5Rk/drop-down-like-its-hot.html" title="Drop Down Like It's Hot" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/08/drop-down-like-its-hot.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYERHk8eCp7ImA9WxBWEk0.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-3513576443351074106</id><published>2010-02-03T07:17:00.000-06:00</published><updated>2010-02-03T08:25:05.770-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-03T08:25:05.770-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 54</title><content type="html">The lamer prides himself on his skill.&lt;br /&gt;He spends ten times longer than necessary and says:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"This way is the best!"&lt;br /&gt;How much more has gone undone?&lt;br /&gt;&lt;br /&gt;The elite does not dwell on his skill.&lt;br /&gt;He leans into the job, code falls forth:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;“This way will work.”&lt;br /&gt;What more can he do?&lt;br /&gt;&lt;br /&gt;Because he focuses on the use, his work is never useless.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=0xkx891yDlk:mEYaZTdGV0c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=0xkx891yDlk:mEYaZTdGV0c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=0xkx891yDlk:mEYaZTdGV0c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=0xkx891yDlk:mEYaZTdGV0c:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=0xkx891yDlk:mEYaZTdGV0c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=0xkx891yDlk:mEYaZTdGV0c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=3513576443351074106" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3513576443351074106?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3513576443351074106?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/0xkx891yDlk/code-te-ching-verse-54.html" title="Code Te Ching - Verse 54" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/02/code-te-ching-verse-54.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EER344fCp7ImA9WxBQFEo.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-7831451959566924260</id><published>2010-01-14T07:24:00.002-06:00</published><updated>2010-01-14T07:26:46.034-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-14T07:26:46.034-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 53</title><content type="html">A manager is soft, like a buffer&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A buffer in memory?&lt;br /&gt;VPs hammer down hard&lt;br /&gt;developers rustle up.&lt;br /&gt;&lt;br /&gt;The man stands up, like a prized warrior, to an army&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=sQUzFJ3uvXY:kXq3fXSodBw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=sQUzFJ3uvXY:kXq3fXSodBw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=sQUzFJ3uvXY:kXq3fXSodBw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=sQUzFJ3uvXY:kXq3fXSodBw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=sQUzFJ3uvXY:kXq3fXSodBw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=sQUzFJ3uvXY:kXq3fXSodBw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=7831451959566924260" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7831451959566924260?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7831451959566924260?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/sQUzFJ3uvXY/code-te-ching-verse-53.html" title="Code Te Ching - Verse 53" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2010/01/code-te-ching-verse-53.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IMQn48cSp7ImA9WxNRFko.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-8090868339365118797</id><published>2009-09-11T09:12:00.012-05:00</published><updated>2009-09-11T09:33:03.079-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-11T09:33:03.079-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="seo" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>Subdomains on Github</title><content type="html">I've been using &lt;a href="http://github.com"&gt;Github&lt;/a&gt; for a while, and it didn't really occur to me to write about it. It's just something that I assume everyone uses, but don't talk much about. Like toilet paper.&lt;br /&gt;&lt;br /&gt;But I just discovered some two-ply goodness that I had to share. Github &lt;a href="http://www.netlingo.com/word/link-juice.php"&gt;link juice&lt;/a&gt;; or more correctly - instant SEO credibility by owning a github subdomain. If you visit &lt;a href="http://coderoshi.github.com"&gt;http://coderoshi.github.com&lt;/a&gt;, you'll be redirected to this site. But how?&lt;br /&gt;&lt;br /&gt;There are two way of going about it. If you visit a subdomain that hasn't been used you'll get this page:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.skitch.com/20090911-x7yx62yjycqm5hm5s5stqj7wes.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 750px; height: 536px;" src="http://img.skitch.com/20090911-x7yx62yjycqm5hm5s5stqj7wes.jpg" border="0" alt="" /&gt;&lt;/a&gt;Try it: &lt;a href="http://alice.github.com/"&gt;http://alice.github.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's most of the trick. Create a new public repository (don't worry, it's free) of "yourusername.github.com" (don't forget the ".github.com part). Add an index.html file and push to master. Viola.&lt;br /&gt;&lt;br /&gt;(for you non-git people, when you create the repository, github gives you clearer instructions than I could here)&lt;br /&gt;&lt;br /&gt;But there's more. To do a simple redirect, just paste in some html with a meta refresh tag, or to keep the nice subdomain url to mask your GeoCities site (look it up, kids) - just upload a page with a blank iframe, which contains your site.&lt;br /&gt;&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;style&amp;gt;body,html{padding:0px;margin:0px;}&amp;lt;/style&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;iframe src="http://www.coderoshi.com" width="100%" height="100%"&lt;br /&gt;  style="border:0px" marginheight="0" marginwidth="0" frameborder="0"&amp;gt;&lt;br /&gt;  &amp;lt;a href="http://www.coderoshi.com"&amp;gt;Coderoshi - Death By Overcoding&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;/pre&gt;&lt;br /&gt;But there's more! If you don't want something so sloppy, and merely want a URL redirect to your site, instead of an index.html file, upload a file named CNAME, which contains your domain. Mine looks like this:&lt;pre&gt;coderoshi.com&lt;/pre&gt;That's it! Instant credibility from google (you're a real subdomain of the very popular github.com domain).&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=CQne6gRxzY8:ZvPxJVelIVo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=CQne6gRxzY8:ZvPxJVelIVo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=CQne6gRxzY8:ZvPxJVelIVo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=CQne6gRxzY8:ZvPxJVelIVo:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=CQne6gRxzY8:ZvPxJVelIVo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=CQne6gRxzY8:ZvPxJVelIVo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=8090868339365118797" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8090868339365118797?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8090868339365118797?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/CQne6gRxzY8/subdomains-on-github.html" title="Subdomains on Github" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/09/subdomains-on-github.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4NSH4-cSp7ImA9WxBWEkw.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-8768301954155504498</id><published>2009-09-02T14:46:00.023-05:00</published><updated>2010-02-03T10:03:19.059-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-03T10:03:19.059-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="haml" /><category scheme="http://www.blogger.com/atom/ns#" term="sass" /><category scheme="http://www.blogger.com/atom/ns#" term="review" /><category scheme="http://www.blogger.com/atom/ns#" term="compass" /><title>I Hate Sass, but I Love Compass</title><content type="html">Generally speaking, I have a rule about generators. &lt;span style="font-style:italic;"&gt;Don't ever use markup that generates more markup&lt;/span&gt; if the final product is straightforward anyway, and doesn't require too much typing.&lt;br /&gt;&lt;br /&gt;I have another rule: don't get involved with code generators that remove your ability to use good existing tooling, unless they generate orders of magnitude more code and are orders of magnitude easier to understand. This is why I never got into &lt;a href="http://modello.codehaus.org/"&gt;Modello&lt;/a&gt; - not even when working on the Maven or Plexus. It takes nearly as much XML to generate a trivial amount of fairly trivial code.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/en/0/0f/Wonder_Twins.jpg"&gt;&lt;img style="float:left; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 352px; height: 262px;" src="http://upload.wikimedia.org/wikipedia/en/0/0f/Wonder_Twins.jpg" border="0" alt="" /&gt;&lt;/a&gt;For these reasons, amongst others, I hate &lt;a href="http://sass-lang.com/"&gt;SASS&lt;/a&gt;. It takes something trivial and straightforward with great tooling (CSS) and turns it into marginally less, but equally readable code (YAMLish). It also convolutes two styles of markup (stylesheet language which &lt;span style="font-style:italic;"&gt;describes&lt;/span&gt; markup, and some YAMLish code which &lt;span style="font-style:italic;"&gt;is&lt;/span&gt; markup). It just reeks of those xml-based scripting languages - this is a type of recursion up with which I cannot put. Or so I thought.&lt;br /&gt;&lt;br /&gt;Enter: &lt;a href="http://wiki.github.com/chriseppstein/compass"&gt;Compass&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It was for frameworks like this that frameworks like &lt;a href="http://www.blueprintcss.org/"&gt;Blueprint CSS&lt;/a&gt; were created. It's symbiotic - without both, each are only marginally interesting. But together they become something more - like the &lt;a href="http://en.wikipedia.org/wiki/Wonder_Twins"&gt;Wonder Twins&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Problem With CSS Frameworks&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I'm going to pick on Blueprint, though the problem exists universally. The benefits of a pre-defined CSS framework are severalfold: attractive defaults across several browsers, nice typography for printing, and a common reference-point for merging other toolkits into your application (plugins, eg, jquery). Blueprint is great for HTML element defaults, and even for defining simple CSS class names like "highlight" or "hide". But an entire framework? Blueprint (and others) also have a rich set of definitions for layouts (be it "columns", "grids", "table", etc.). The nightmare is using them.&lt;br /&gt;&lt;br /&gt;Here is an example of a value "23" set in the last column, with a specific width, prepended by 20 columns, and appended by 1, from Blueprint's own documentation: &lt;pre&gt;&amp;lt;div class="prepend-20 span-1 append-1 last"&amp;gt;23&amp;lt;/div&amp;gt;&lt;/pre&gt;This harkens back to the dark-ages of the web: mixing content and layout. Though the mixing is done via css, the problem is that the CSS (more flexible than, say, a table) is still describing how the HTML should be &lt;span style="font-style:italic;"&gt;displayed&lt;/span&gt; (however vaguely), not what it &lt;span style="font-style:italic;"&gt;is&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Keeping Semantic&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Up until now, we are stuck. With only HTML and CSS available, it is difficult to utilize Blueprint grids without giving something up. We can either do the above (describe layout in HTML's class attributes), or attempt to define a friendlier CSS. Let's pretend (with a stretch of the imagination) that the div declared above contains my age. A descriptive, layout neutral HTML would appear thusly.&lt;pre&gt;&amp;lt;div class="my-age"&amp;gt;23&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;span style="font-style:italic;"&gt;(Or better yet, in &lt;a href="http://haml-lang.com/"&gt;HAML&lt;/a&gt;:)&lt;/span&gt;&lt;pre&gt;.my-age 23&lt;/pre&gt;Now that's separation! Nice, semantic HTML. No layout. Of course, now we have a problem: Blueprint knows nothing about the new class "my-age". How can I explain to Blueprint that the CSS class I just created should act like "prepend-20 span-1 append-1 last"? In short: you cannot. Not without hacking up your Blueprint CSS file (non-portable - you'll lose a lot of the benefit of using a CSS framework), or simply copying the Blueprint code into your own custom CSS class (better, but you've now completely missed the benefit of using Blueprint).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How Compass Aids Separation&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Compass is a CSS generation framework. Actually, let me back up. SASS is a CSS generation framework, while Compass is the glue between Blueprint (and &lt;a href="http://wiki.github.com/chriseppstein/compass/supported-frameworks"&gt;other CSS frameworks&lt;/a&gt;) and SASS. Remember me saying I hated SASS? It's true. But Compass pre-packages these CSS frameworks and makes them available as mixin modules... and that I love. So let's get on with it.&lt;br /&gt;&lt;br /&gt;Assuming I have Compass/SASS installed and operational, fixing the above problem is trivial.&lt;pre&gt;@import blueprint&lt;br /&gt;body&lt;br /&gt;  div.my-age:&lt;br /&gt;    +prepend(20)&lt;br /&gt;    +span(1)&lt;br /&gt;    +append(1)&lt;br /&gt;    +last&lt;br /&gt;&lt;/pre&gt;What Compass does is provide those Blueprint mixins (+prepend, +span, +append, +last - complements of @import blueprint), while SASS provides much of the rest, compiles the given markup to CSS (yuck). What you get is the kind of inheritance lacking in CSS proper.&lt;br /&gt;&lt;br /&gt;Opening the Blueprint Grid CSS file we see the classes we used are defined as this:&lt;pre&gt;.prepend-20 { padding-left: 800px;}&lt;br /&gt;.span-1 {width: 30px;}&lt;br /&gt;.append-1 { padding-right: 40px;}&lt;br /&gt;.last { margin-right: 0;}&lt;/pre&gt;But after Compass/SASS we get a new CSS file generated, which contains the following:&lt;pre&gt;body div.my-age {&lt;br /&gt;  padding-left: 800px;&lt;br /&gt;  width: 30px;&lt;br /&gt;  padding-right: 40px;&lt;br /&gt;  margin-right: 0;&lt;br /&gt;}&lt;/pre&gt;We get to keep our Blueprint pristine, while able to keep markup semantic and layout separate. What's more, is that beyond the brute-force method of copying Blueprint class-for-class, Compass provides a host of other useful mixins. In fact, the above SASS can be simplified as something more succinct:&lt;pre&gt;@import blueprint&lt;br /&gt;body&lt;br /&gt;  div.my-age:&lt;br /&gt;    +column(20, true)&lt;br /&gt;    +append(1)&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;What I stated in the intro is still true. Markup that generates markup often lacks any sort of real tooling, and this is no exception. What I find myself doing is writing CSS using &lt;a href="http://macrabbit.com/cssedit/"&gt;CSSEdit&lt;/a&gt; against the SASS-generated CSS. Once I'm happy with the changes visually, I make changes in the SASS file. Is it extra effort? Yes - but not much. And the payoff to project bootstrapping speed, along with the overall maintainability, makes it worth it. Try it on your next small Rails project (along with HAML) - you may find it hard to go back.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=mGW6Iu6Wr08:6f4XOuG_JLM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=mGW6Iu6Wr08:6f4XOuG_JLM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=mGW6Iu6Wr08:6f4XOuG_JLM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=mGW6Iu6Wr08:6f4XOuG_JLM:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=mGW6Iu6Wr08:6f4XOuG_JLM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=mGW6Iu6Wr08:6f4XOuG_JLM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=8768301954155504498" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8768301954155504498?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8768301954155504498?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/mGW6Iu6Wr08/i-hate-sass-but-i-love-compass.html" title="I Hate Sass, but I Love Compass" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/09/i-hate-sass-but-i-love-compass.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEGQXYzfip7ImA9WxNSGEg.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-8045889115112388266</id><published>2009-09-01T19:48:00.003-05:00</published><updated>2009-09-01T19:50:20.886-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-01T19:50:20.886-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>Codeoshi on Github</title><content type="html">Here's the link: &lt;a href="http://github.com/coderoshi"&gt;http://github.com/coderoshi&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sure, it's been there for a while - it just recently occurred to me that I never linked to it.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=wnYn0ph3lPA:nU-GLS4c7bE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=wnYn0ph3lPA:nU-GLS4c7bE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=wnYn0ph3lPA:nU-GLS4c7bE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=wnYn0ph3lPA:nU-GLS4c7bE:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=wnYn0ph3lPA:nU-GLS4c7bE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=wnYn0ph3lPA:nU-GLS4c7bE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="related" href="http://github.com/coderoshi" title="Codeoshi on Github" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=8045889115112388266" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8045889115112388266?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8045889115112388266?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/wnYn0ph3lPA/codeoshi-on-github.html" title="Codeoshi on Github" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/09/codeoshi-on-github.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcEQH0zfip7ImA9WxNTFkg.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-2542560923353499342</id><published>2009-08-19T00:00:00.000-05:00</published><updated>2009-08-19T00:00:01.386-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-19T00:00:01.386-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 52</title><content type="html">Like one cast away on a desert island,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;the rolling tide keeps his head.&lt;br /&gt;Like one working on the dark prairie plains,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;the chirping insects keep him company.&lt;br /&gt;Listen to the hum of the machine, for that is the coder’s solitude,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;that keeps his company ahead.&lt;br /&gt;&lt;br /&gt;The elite understands his value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;does not lord it over his subordinates,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;does not embellish it to his superiors.&lt;br /&gt;&lt;br /&gt;His opportunity flies like a gentle bee’s.&lt;br /&gt;Alights on the first flower it sees,&lt;br /&gt;And leaves just as suddenly, without a trace&lt;br /&gt;But benefits the flower in endless ways.&lt;br /&gt;&lt;br /&gt;The elite has no home but Code,&lt;br /&gt;And because of this, is never homeless.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GqL3WzaGmIk:ywKSZNbX5uE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GqL3WzaGmIk:ywKSZNbX5uE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GqL3WzaGmIk:ywKSZNbX5uE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GqL3WzaGmIk:ywKSZNbX5uE:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GqL3WzaGmIk:ywKSZNbX5uE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GqL3WzaGmIk:ywKSZNbX5uE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=2542560923353499342" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2542560923353499342?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2542560923353499342?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/GqL3WzaGmIk/code-te-ching-verse-52.html" title="Code Te Ching - Verse 52" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/08/code-te-ching-verse-52.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08NQXo_cSp7ImA9WxNTFU4.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-8785787745101543305</id><published>2009-08-17T10:29:00.012-05:00</published><updated>2009-08-17T12:58:10.449-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-17T12:58:10.449-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Ruby is Java and Java is C</title><content type="html">Remember 10 years ago? As "Java 2" (jdk 1.2) exploded in popularity throughout 1999, scores of developers dropped their perl/c CGI web server-side methods in favor of the new hotness Java. And why not? The language was maturing, the simplicity of ASP was ported to Java as JSPs in June, and the servlet spec was hammered out with the advent of WARs in August. Those of us lucky enough to get paid to be on this forefront found plenty of work still needed to be done - by way of tooling and optimization.&lt;br /&gt;&lt;br /&gt;But with this new fervor of excitement rose an equal amount of riffing from the "real" server-side language: C/C++. "It may seem like you can write apps faster", they'd say, "but there's no way you can beat our tools - look at our libraries! Look at the power of our pre-processor, compile optimizations, and emacs! And - you'll be sorry when you have to spend all that time optimizing, and eventually re-write your code in C anyway." It was a fair argument, and there were certainly anecdotes over the years of companies pulling the plugin on their Java projects to revert back to C (hell, I worked on one at Cerner as late as 2004). Some Javanistas attempted to argue back - but most of us quietly hammered on, bending Java to our will - content in the knowledge that hardware would close the performance gap, and our tools would do nothing but grow. Yet still they scorned - for a while. Ten short years later, you rarely hear from that camp anymore concerning web server-side productivity or reliability. We clearly - emphatically - won. (It's a shame, really, since I kind of miss hacking C.)&lt;br /&gt;&lt;br /&gt;But times have changed. Despite incessant claims that Moore's law is dead - it has held strong, driving forward. Hardware is cheap. Disks are cheap. Memory is cheap. And in many systems, bandwidth is cheap. Yet now, a short 10 years later, the Ruby camp suffers the slings and arrows of a myopic community - in this case Java steps into the role of C. The old, general purpose stand-by refuses to fade away in favor of it's lighter, easier, friendlier replacement. The arguments levied against Ruby these days are similar to the old arguments against Java. It's slower. It doesn't have powerful tools. It doesn't concern the needs of the "enterprise". "Real" programmers understand the difference between interfaces and abstract classes - and the value of each being distinct (I still don't know). Yadda yadda yadda...&lt;br /&gt;&lt;br /&gt;So I'll make two predictions here. Not so bold now, but in fairness to me, I've been saying it for 4 years: Ruby will win this battle for the web over Java. Java is just too clunky of a language to survive, with too much baggage to match the agility of Ruby - or even Python for that matter.&lt;br /&gt;&lt;br /&gt;Java - desperate to remain relevant - has at least learned something from the past. Java, as a language will die, but hopefully the JVM - arguably the greatest VM ever created (not so much by design, but by sheer effort alone) won't fade into that dark night. Hopefully &lt;a href="http://www.engineyard.com/blog/2009/engine-yard-adds-jruby-support/"&gt;EngineYard's recent investment into JRuby &lt;/a&gt;is just the right medicine - lest it completely drop from the web server-side market. And that really would be a shame.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=KTbwylx6I1k:EK3BW2zTI_k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=KTbwylx6I1k:EK3BW2zTI_k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=KTbwylx6I1k:EK3BW2zTI_k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=KTbwylx6I1k:EK3BW2zTI_k:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=KTbwylx6I1k:EK3BW2zTI_k:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=KTbwylx6I1k:EK3BW2zTI_k:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=8785787745101543305" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8785787745101543305?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8785787745101543305?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/KTbwylx6I1k/ruby-is-java-and-java-is-c.html" title="Ruby is Java and Java is C" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/08/ruby-is-java-and-java-is-c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUABRnc6eSp7ImA9WxNTF0o.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-5787629701016715040</id><published>2009-07-29T08:55:00.040-05:00</published><updated>2009-08-20T09:15:57.911-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-20T09:15:57.911-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="startup" /><category scheme="http://www.blogger.com/atom/ns#" term="google app engine" /><title>Build a Business with Google</title><content type="html">Hi, I'm Eric. A C++ coder turned Java zealot turned Ruby on Rails adopter turned Django turned... whatever. They're all fine. I'm not here to talk about superior architecture, or the best language, or design or whatever. I'm here to talk about getting your web app idea out the fucking door. This is exactly what we did with &lt;a href="http://www.microtasking.net"&gt;MicroTasking.net&lt;/a&gt;. A year ago this was hard, but could be done for free. Two years ago it could be done cheaply. Five years ago you needed some funding and a lot more time. This is today - so I'll talk about the lowest barrier to entry technical stack on the market: Google.&lt;br /&gt;&lt;br /&gt;Note - I don't work for Google, I don't get kickbacks, I don't even own any stock. But I have &lt;a href="http://www.sonatype.com"&gt;bootstrapped&lt;/a&gt; &lt;a href="http://www.vontoo.com"&gt;several&lt;/a&gt; &lt;a href="http://www.thefutureis.mobi"&gt;companies&lt;/a&gt;, &lt;a href="http://www.microtasking.net"&gt;products&lt;/a&gt;, &lt;a href="http://www.cerner.com"&gt;enterprises&lt;/a&gt;, &lt;a href="http://www.snipsnipe.com"&gt;forgettable&lt;/a&gt; &lt;a href="http://gigaring.heroku.com"&gt;services&lt;/a&gt;, &lt;a href="http://www.vocmsg.com/"&gt;and&lt;/a&gt; &lt;a href="http://apache.maven.org"&gt;open&lt;/a&gt; &lt;a href="http://mojo.codehaus.org/"&gt;source&lt;/a&gt; &lt;a href="http://plexus.codehaus.org/"&gt;products&lt;/a&gt;. I also make &lt;a href="http://www.ziggypod.com/"&gt;iPhone apps&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Are you afraid of "putting all of your eggs in one Google basket"? Don't. When speaking of risk assessment, the largest risk of a startup is failing to launch. Google going away isn't your biggest concern. Scaling isn't either. Just push it out the door - then worry about those things. Once you have customers, you'd be amazed all of the problems you can pay to have solved. Like migrating to dedicated machines, if it makes you feel better.&lt;br /&gt;&lt;br /&gt;So what do you need, from the technical side, to start a web application company? A domain name. You need a server that doesn't suck. Email/office software is nice. A blog is good. A phone number to call. What else? You also need &lt;span style="font-style:italic;"&gt;customers&lt;/span&gt;. You get them through advertising and campaign optimization (which you achieve via tracking). They also need to be able to make purchases. But first thing's first:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Domain Registration/Host/Email/Office Apps&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Let's start with the basics. Register a domain and get a host through &lt;a href="http://www.google.com/a/cpanel/domain/new"&gt;Google Apps signup&lt;/a&gt;. Click "I want to buy a domain name" and search for one. It costs $10/year, which is more than Go Daddy. What they give is worth the extra price. You'll automatically be set up with a standard version of GA - which  provides you with 50 domain-specific email accounts integrated with the Calendar, a sandboxed office suite with IM/Video Chat, Documents, Slideshows, Spreadsheets - also integrated Forms, which you can put on your Site or email, and collect results as a spreadsheet. Oh, also, they provide a website CMS.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Money down: $10&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Phone Management&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Sign up for &lt;a href="http://www.google.com/voice"&gt;Google Voice&lt;/a&gt;. It's not public yet - but it will be soon enough. I use it daily... it has damn near everything you need for a small company PBX. I live in Indianapolis, but my business number is San Francisco - which forwards to my cellphone. Twofold benefit. 1) you don't want to give out your private number, and 2) you don't want to give out your private number. It's free for now. You can even pay extra for a toll-free (800, 888, 866) number.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;More on Email&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This is a nice trick mentioned by Tim Ferriss in the &lt;a href="http://www.fourhourworkweek.com/"&gt;4-Hour Work Week&lt;/a&gt;. Since you're eventually going to grow and outsource all of your work (right?) it's not a bad idea to segment your communications in advance. Your company may just be you and a buddy for now, but you want the illusion of a larger team. Sales. Info. Webmaster. Whatever. You can do this on the Google Apps dashboard by clicking "Users and Groups" on the top, then choosing "Groups". Create as many groups as you need and just have them forward to the appropriate people. As you grow, it's easy to reroute the traffic - much easier than changing a well-known email address. Our list for MicroTasking.net is:&lt;br /&gt;&lt;br /&gt;contact@microtasking.net, help@microtasking.net, info@microtasking.net, refund@microtasking.net, sales@microtasking.net&lt;br /&gt;&lt;br /&gt;They all forward to me and Jim.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Blog&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Get a blog via &lt;a href="http://www.blogger.com"&gt;Blogger&lt;/a&gt;. Just sign-up with the Google Account you made above. Follow the steps to create a blog. That's easy enough, eh? What you probably want here though, is not a blog URL http://mynewblog.blogspot.com , but rather http://blog.mynewcompany.com. This is a two-step process.&lt;br /&gt;&lt;br /&gt;First, create the blog subdomain. In the Google Apps dashboard, click "Domain Settings" above. Then click "Domain Names", then "Advanced DNS settings". Sign into enom. "Edit Host Records" and "Add New" CNAME named "blog" (or whatever). Set the address to "ghs.google.com." (don't forget the period at the end). That's it for the DNS routing table.&lt;br /&gt;&lt;br /&gt;Next log back into Blogger. Click "Settings" and then "Publishing". Fill out Your Domain with the new subdomain (eg. http://blog.mynewcompany.com). That's it! No more lame blogspot domain.&lt;br /&gt;&lt;br /&gt;This should cover you on the business/IT end. Let's make the app!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Application&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;For years Google skirted around the edges - instead focusing on toolkits, APIs, and company tools like email. With the launch of &lt;a href="http://appengine.google.com/"&gt;Google App Engine&lt;/a&gt; (GAE) last year, they've taken a huge leap toward Amazon. What is App Engine? Think EC2+SimpleDB+S3+deployment tools+data management. It's to Python (and Java) what &lt;a href="http://www.heroku.com"&gt;Heroku&lt;/a&gt; is for Ruby on Rails. In other words - a dream.&lt;br /&gt;&lt;br /&gt;Sign up for a &lt;a href="http://appengine.google.com/"&gt;Google App Engine&lt;/a&gt; account. Again, just use your new gmail account. There are a lot of posts about App Engine, so I won't cover it here. But what I will tell you is, if you choose to write in Python, use Django. There a great &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;patch project  here&lt;/a&gt;. Follow the instructions. Use it. I've written 3 GAE projects so far - two of them without it. One with. If your application will be non-trivial, just make the investment to learn Django and use it - you'll thank me later.&lt;br /&gt;&lt;br /&gt;Note that your application lives at http://mynewapp.appspot.com/. Again, we want to put the application under our single domain - which is painfully easy. This is where I diverge from the Google party-line. I don't use the Google Site stuff - but by default, your domain will forward to use Google Site. So I instead hijack the "www" subdomain to point to my app-engine app.&lt;br /&gt;&lt;br /&gt;First, we need to tell Google about our application. Go back to the Dashboard, and click on "Add More Services". Under "Other services", you will see "Google App Engine" - "Enter App ID:". Do what it says (this is the unique name you gave your app - the *.appspot.com subdomain). It will then forward you to another settings page - but ignore this for now and return to the main Dashboard page. Click on the "Sites" link, then "Web address mapping". Delete the "www" mapping. Then return to your Dashboard.&lt;br /&gt;&lt;br /&gt;Select the new "app engine" link - the one you just added. Choose "Add new URL", and enter in  the subdomain "www". Viola! Now your application will be the main page. I recommend doing this because Google Sites is pretty limited, both in style and customizability. Your applications index page doesn't have to be anything more than a static template page - which you can 100% customize like any other website. Some people are taking advantage of this, and using App Engine as a pure content delivery network (CDN) to host static pages, images, etc for free. Actually, I host &lt;a href="http://www.ziggypod.com"&gt;ZiggyPod&lt;/a&gt; this way. It' fast, scales, and the price is right :). It's "freemium", so you can pay for more later.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Payments&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are many services Google provides, which you can easily hook into via app-engine. Maps, Email, etc. But there's nothing special there. The real cool piece is hooking into &lt;a href="https://checkout.google.com"&gt;Google Checkout&lt;/a&gt;. Sign up for an account. There are many ways you can hook into GC, but my favorite way is to set up your account to automatically update the application when a sale is made - such as making more services available. It's nearly immediate.&lt;br /&gt;&lt;br /&gt;Head to "Settings", "Integration" in the GC page. Under "API callback URL" enter in the URL that will accept the callback. Note that this URL must be https, and that app engine only supports certificates from appspot.com. Meaning, here is one place where you will have to enter in your appspot URL. For example:&lt;br /&gt;&lt;br /&gt;https://mynewapp.appspot.com/googlepaynotify&lt;br /&gt;&lt;br /&gt;This assumes your app has a path "/googlepaynotify" which handles the callback. Google Checkout will send the URL XML or name=value pairs. I prefer XML - just parse it and handle it. There's plenty of &lt;a href="http://code.google.com/apis/checkout/"&gt;documentation on the API&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This handles the callback, but how do you make the sale begin? The easiest way is to create a "Buy Now Button" - you'll see it if you click "Tools" on the top. It will generate the client-side code where you can put the button on your site. Congratulations! You can now accept sales. You can make it as complex as you want, of course, which requires more integration with the API. But that's beyond the scope here.&lt;br /&gt;&lt;br /&gt;So far we have a homepage, full office stack, a blog, application hosting, and the ability to accept payments. What more do we need... oh yeah, customers! Let's integrate with AdWords.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;AdWords&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://adwords.google.com/"&gt;AdWords&lt;/a&gt; is older than dirt. It's Google's first and most profitable business unit - and with good reason. I worked for over a year as a keyword marketer, and I have one piece of advise: Don't try and game the system. All of the obvious ideas have been tried, and the cleverer ones are dominated by a few players who do that, and only that, for a living.&lt;br /&gt;&lt;br /&gt;However - there is something you should know: Turn off keywords. OK, perhaps not completely, but your focus should be on optimizing Content Network. Two reasons for this 1) since the keyword space is basically dominated, you'll pay out the nose for decent keywords. Sure, grab a few - your company name, for example, but for the most part, take a cue from Paul McCartney. Let it be. 2) You'll have far more impression on the content network than keywords. You only pay per click, so if someone sees your website name and don't click, you just got a free impression. I get 100,000 impressions a day. Sure - most don't click, or see it. But some do - and it didn't cost all that much.&lt;br /&gt;&lt;br /&gt;I could go on. Forever. The point being, sign up for adwords - it's a decent driver of traffic and a way to bootstrap your advertising for cheap. Just be wary of the expensive words. I never pay more than 0.50 per click. This is a secret of the pros. If the keywords you've chosen are expensive, they have high traffic, sure, but you can rather visit &lt;a href="https://adwords.google.com/select/KeywordToolExternal"&gt;https://adwords.google.com/select/KeywordToolExternal&lt;/a&gt;, type in the good keyword, and take all of the lesser quality words instead. Let's do the math.&lt;br /&gt;&lt;br /&gt;1 keyword @ $5.00/click * 1,000 click each = $5,000&lt;br /&gt;500 (related) keywords @ $0.10/click * 2 clicks each = $10&lt;br /&gt;&lt;br /&gt;For a savings of $4,990, you still got 1000 clicks. Of course, this takes more management. But there are several of these kinds of tricks available.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Analytics&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://www.google.com/analytics"&gt;Google Analytics&lt;/a&gt; is great. Before this gem, most people either rolled their own traffic trackers, or payed huge sums of money for less-awesome analytics tools. I don't have much to say about it other than sign up, put it on your home page (landing page). If you use the same account for AdWords - Analytics will track your traffic which comes from clicking on ads. A handy feature to track conversions.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Integration/Optimization&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are so many advanced tools available, it's hard to list them all here. But here are some&lt;br /&gt;&lt;br /&gt;&lt;a href="https://adwords.google.com/support/bin/answer.py?answer=115794&amp;hl=en_US"&gt;Conversion Tracking&lt;/a&gt;: From ad to successful "conversion" (visiting whatever page you consider to be a success), AdWords can self-optimize where/when/who to place your ads.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://adwords.google.com/support/bin/answer.py?answer=60150&amp;hl=en_US"&gt;Conversion Optimizer&lt;/a&gt;: After a month of tracking conversions, you can start paying per action - this means rather than paying Google for keywords/content which may not succeed at sales - you can pay them only when a sale happens.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://checkout.google.com/support/sell/bin/answer.py?answer=42896&amp;topic=8667"&gt;Checkout Badge&lt;/a&gt;: Increase AdWord conversions by letting Google notify and target people with Checkout accounts.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Many people use some aspect of Google services: gmail, applications, analytics. No need to complicate the matter - just wire these services together to create a full-stack for your new web-service company. Most anything you need (short of legal or tax advice) can be done for free or cheap.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=cWHsBOq95m8:h7V15j1ChZc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=cWHsBOq95m8:h7V15j1ChZc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=cWHsBOq95m8:h7V15j1ChZc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=cWHsBOq95m8:h7V15j1ChZc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=cWHsBOq95m8:h7V15j1ChZc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=cWHsBOq95m8:h7V15j1ChZc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=5787629701016715040" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/5787629701016715040?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/5787629701016715040?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/cWHsBOq95m8/build-business-with-google.html" title="Build a Business with Google" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>10</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/07/build-business-with-google.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAMSHwzfyp7ImA9WxJSF00.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-8317958737761842503</id><published>2009-05-06T19:01:00.019-05:00</published><updated>2009-05-07T09:33:09.287-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-07T09:33:09.287-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="textbarf" /><category scheme="http://www.blogger.com/atom/ns#" term="google app engine" /><category scheme="http://www.blogger.com/atom/ns#" term="gae" /><title>Google App Engine Scales and Develops Fast</title><content type="html">Really. It's amazing. After a quick chat about the concept with &lt;a href="http://jimbojw.com"&gt;Jim&lt;/a&gt;, I bet my wife I could get a web app knocked out which accepted text messages, stored and printed them in an hour (&lt;a href="http://www.textbarf.com"&gt;www.textbarf.com&lt;/a&gt;). It took 35 minutes. In fact, I have a feeling this write-up will take longer. Now THAT's progress.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;(FYI - sauce: &lt;a href="http://github.com/vocmsg/textbarf/tree/master"&gt;http://github.com/vocmsg/textbarf/tree/master&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Getting started&lt;/span&gt;&lt;br /&gt;First, create a &lt;a href="http://appengine.google.com/"&gt;Google App Engine account&lt;/a&gt;. If you already have gmail, just use that. You can have up to 10 apps.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_E3_4LXYT1LI/SgIoDmMuWhI/AAAAAAAAASo/c6HFOyhqd20/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://1.bp.blogspot.com/_E3_4LXYT1LI/SgIoDmMuWhI/AAAAAAAAASo/c6HFOyhqd20/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5332868951018723858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you download the SDK and install it for your OS, you'll get a nice little launcher with it. Right-click new, and you're on your way. Launching is just as simple... just click "Deploy", enter your account login, and your app is launched. In my case, &lt;a href="http://textbarf.appspot.com"&gt;http://textbarf.appspot.com&lt;/a&gt; (all GAE apps are subdomains of appspot).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code&lt;/b&gt;&lt;br /&gt;The source code couldn't be simpler. First, appengine db models are mapped to Google's BigTable - a columnar (not relational) database. The nice thing about this kind of dataset is that OO models map fairly directly to the data on the backend (no ORM). The downside is that you'll have lots of duplicate data - since joins are really expensive. But I digress. All we need to do is store a text message, the phone number it came from, and the datetime the txt was made. Ready? Java people cover your eyes - you may cry from jealousy:&lt;pre name="code" class="java:nocontrols"&gt;class Barf(db.Model):&lt;br /&gt;  text = db.StringProperty(required=True)&lt;br /&gt;  phone = db.PhoneNumberProperty()&lt;br /&gt;  date = db.DateTimeProperty(auto_now_add=True)&lt;/pre&gt;That's it. GAE creates a BigTable type which maps to this design (as well as automatically create any necessary indexes based on given queries, which then populates the &lt;a href="http://github.com/vocmsg/textbarf/tree/master"&gt;index.yaml&lt;/a&gt; file. I could have put this in an external module (normally I'd put it in a file called models.py and import it), but for the sake of speed and simplicity, I just put it in the main.py file generated by the GAE SDK tools.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_E3_4LXYT1LI/SgIvSndk80I/AAAAAAAAASw/_jeji5B1i7U/s1600-h/Picture+2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_E3_4LXYT1LI/SgIvSndk80I/AAAAAAAAASw/_jeji5B1i7U/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5332876905637278530" /&gt;&lt;/a&gt;&lt;br /&gt;Next, we need to deal with request. GAE webapp maps URLs to files (in app.yaml - which already points root to main.py by default), and uses 'WSGIApplication' to map internally URLs to RequestHandler classes. In this case, there are two urls: '/' and '/txtback' - one is the website URL, the other is so the SMS service can ping back data to the server. They are mapped in the main module&lt;pre name="code" class="java:nocontrols"&gt;def main():&lt;br /&gt;  app = webapp.WSGIApplication([('/', MainHandler),&lt;br /&gt;                                ('/txtback', TxtBackHandler)])&lt;br /&gt;  wsgiref.handlers.CGIHandler().run(app)&lt;/pre&gt;Let's look at the root URL.&lt;pre name="code" class="java:nocontrols"&gt;class MainHandler(webapp.RequestHandler):&lt;br /&gt;  def get(self):&lt;br /&gt;    barfs = Barf.all().order('-date').fetch(250)&lt;br /&gt;    &lt;br /&gt;    path = os.path.join(os.path.dirname(__file__), 'templates/index.html')&lt;br /&gt;    self.response.out.write(template.render(path, {'barfs': barfs}))&lt;/pre&gt;Again - hopefully straightforward (isn't python so readable?). If a GET request happens, first fetch 250 Barf objects reverse ordered by date. Next, get the path to an external template file and write the rendered template (passing in the barfs objects) to the response output. Most of the magic is in the template.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Template&lt;/b&gt;&lt;br /&gt;The template is mostly a standard HTML file, with a little bit of server-side markup.&lt;pre name="code" class="xml:nocontrols"&gt;{% for barf in barfs %}&lt;br /&gt;  {% ifchanged barf.date.date %}&lt;br /&gt;    &amp;lt;li&gt;&amp;lt;div class="date"&gt;{{ barf.date.date }}&amp;lt;/div&gt;&amp;lt;/li&gt;&lt;br /&gt;  {% endifchanged %}&lt;br /&gt;  &amp;lt;li&gt;&lt;br /&gt;    &amp;lt;div class="time"&gt;{{ barf.date|date:"P" }}&amp;lt;/div&gt;&lt;br /&gt;    &amp;lt;div class="quote"&gt;{{ barf.text|escape }}&amp;lt;/div&gt;&lt;br /&gt;  &amp;lt;/li&gt;&lt;br /&gt;{% endfor %}&lt;/pre&gt;Again - it should be self explanatory. Iterate through each "barf" object. If the date has changed since the previous loop, output it. Then, output the barf.date formatted by the date formatter with type "P" (simple time) and the given text. That's all you need to output stored data. Google manages the rest for you - all with a scalable base.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Accepting Text Messages&lt;/b&gt;&lt;br /&gt;Next, we want to accept text messages to populate the text Barf objects. There's no need to create a template here, a simple text response it sufficient. Our main goal is to store the input.&lt;pre name="code" class="java:nocontrols"&gt;class TxtBackHandler(webapp.RequestHandler):&lt;br /&gt;  def get(self):&lt;br /&gt;    text = self.request.get('message')&lt;br /&gt;    if text: text = text.strip().lower()&lt;br /&gt;    phone = self.request.get('min')&lt;br /&gt;    if phone: phone = phone[-10:]&lt;br /&gt;    &lt;br /&gt;    b = Barf(text=text, phone=phone)&lt;br /&gt;    b.put()&lt;br /&gt;    &lt;br /&gt;    self.response.out.write('http://textbarf.com')&lt;/pre&gt;We expect two request attributes, create a Barf object, save it and write back the URL. Simple as that.&lt;br /&gt;&lt;br /&gt;But that was only the callback. To accept text messages, I signed up for a 41411 shortcode account (named "tbarf") through &lt;a href="http://www.textmarks.com/"&gt;TextMarks.com&lt;/a&gt;. Once you sign up and verify the account, you need to provide the callback URL. Before you can do that, there must be a URL to hit. So, I click the deploy button. 5 seconds later, the app is up an running. All that's left is to give the URL to TextMarks - in my case: http://textbarf.appspot.com/txtback?min=\p&amp;message=\0 (where \p and \0 are interpolated with the calling phone and message data). 41411 is great, free, and they make money by ads.&lt;br /&gt;&lt;br /&gt;Seriously - that's it. That took a grand total of 30 minutes. So, I registered a URL and pointed it at the app (http://www.textbarf.com), then just for good measure, slapped in Google Analytics. This whole app cost a total of $10, for the sweet, sweet domain.&lt;br /&gt;&lt;br /&gt;Voilà! Eat it, EC2! Just for the record - this post took about an hour.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m4tStmtlWvE:1Exun9A5sR4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m4tStmtlWvE:1Exun9A5sR4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=m4tStmtlWvE:1Exun9A5sR4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m4tStmtlWvE:1Exun9A5sR4:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=m4tStmtlWvE:1Exun9A5sR4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=m4tStmtlWvE:1Exun9A5sR4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=8317958737761842503" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8317958737761842503?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/8317958737761842503?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/m4tStmtlWvE/google-app-engine-scales-and-develops.html" title="Google App Engine Scales and Develops Fast" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_E3_4LXYT1LI/SgIoDmMuWhI/AAAAAAAAASo/c6HFOyhqd20/s72-c/Picture+1.png" height="72" width="72" /><thr:total>6</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/05/google-app-engine-scales-and-develops.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMNQH85eCp7ImA9WxJSEEs.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-7157671082245644987</id><published>2009-04-28T23:07:00.000-05:00</published><updated>2009-04-29T22:34:51.120-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-29T22:34:51.120-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 51</title><content type="html">The ancients followed the way of the machine.&lt;br /&gt;Dark, wondrous, complex.&lt;br /&gt;&lt;br /&gt;Difficult beyond knowing.&lt;br /&gt;&lt;br /&gt;Yet for all their knowing, they could not control it.&lt;br /&gt;Commanding:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Machine do this!&lt;br /&gt;Storing:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Machine hold this!&lt;br /&gt;Jumping:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Machine go there!&lt;br /&gt;Linking:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Machine go here!&lt;br /&gt;Finally, Yielding:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Machine, please help!&lt;br /&gt;&lt;br /&gt;And they taught the machine to help.&lt;br /&gt;&lt;br /&gt;Long did they suffer for the sake of their children.&lt;br /&gt;Those who return to such thought do the ancients a disservice.&lt;br /&gt;&lt;br /&gt;So embrace what has been done.&lt;br /&gt;Though the path may wind, it should never go back.&lt;br /&gt;&lt;br /&gt;Honor their memory, and their command of memory.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Then forget.&lt;br /&gt;&lt;br /&gt;There is no instruction for honor.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=x-TNg1QvEZ0:Yg5NlCYp4Uw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=x-TNg1QvEZ0:Yg5NlCYp4Uw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=x-TNg1QvEZ0:Yg5NlCYp4Uw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=x-TNg1QvEZ0:Yg5NlCYp4Uw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=x-TNg1QvEZ0:Yg5NlCYp4Uw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=x-TNg1QvEZ0:Yg5NlCYp4Uw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=7157671082245644987" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7157671082245644987?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/7157671082245644987?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/x-TNg1QvEZ0/code-te-ching-verse-51.html" title="Code Te Ching - Verse 51" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/04/code-te-ching-verse-51.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkINSHYyfCp7ImA9WxJTFUQ.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-6930744961783328753</id><published>2009-04-24T12:06:00.000-05:00</published><updated>2009-04-24T13:43:19.894-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-24T13:43:19.894-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 50</title><content type="html">Learners!&lt;br /&gt;Great men of learning toil lifetimes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for a glimpse of what the elite know.&lt;br /&gt;&lt;br /&gt;Great, unconditional love flows from the master.&lt;br /&gt;Great, conditional knowledge flows from the learned.&lt;br /&gt;&lt;br /&gt;When a labor of the mind toils a lifetime to fall short of perfection,&lt;br /&gt;the inaction of love sits silently, content in its experienced and subtle understanding of Code.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GWpjYianzI4:EbuG1dyiVBQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GWpjYianzI4:EbuG1dyiVBQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GWpjYianzI4:EbuG1dyiVBQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GWpjYianzI4:EbuG1dyiVBQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GWpjYianzI4:EbuG1dyiVBQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GWpjYianzI4:EbuG1dyiVBQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=6930744961783328753" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6930744961783328753?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6930744961783328753?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/GWpjYianzI4/code-te-ching-verse-50.html" title="Code Te Ching - Verse 50" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2008/02/code-te-ching-verse-50.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMCQHw9fSp7ImA9WxVaE08.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-2526511421472894867</id><published>2009-04-09T19:16:00.003-05:00</published><updated>2009-04-09T19:31:01.265-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-09T19:31:01.265-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="google app engine" /><category scheme="http://www.blogger.com/atom/ns#" term="gae" /><title>Google App Engine Java Support</title><content type="html">I know, I know. Envy me. Not only have I gotten to beta test the iPhone 3.0 notification and payment frameworks (incidentally, OS3.0 is piiiimmmppp), I now get to beta test the GAE J6 support. Although I'm still shocked, and slightly dismayed that the first language supported beyond Python is Java, it's clear they did it based on the very vocal rantings of the Javanistas (http://code.google.com/p/googleappengine/issues/detail?id=1) with gems such as "Java/Groovy would make this service much more serious for the individuals and development companies to work with it". Ah, the egocentric hubris of the Java-first crowd.&lt;br /&gt;&lt;br /&gt;Well, enough about the that. The great news isn't Java support - it's JVM support. Since now I can finally run Rails (well, JRails), it may be worth a go. But I still don't know how they're going to handle the lack of opening ports.&lt;br /&gt;&lt;br /&gt;Sadly, I've been so busy knocking the hell out of &lt;a href="http://app.vocmsg.com"&gt;vocmsg&lt;/a&gt;, everything must relate to that. So, I think I'll write my iPhone notifier on GAE using J6, and dump the overview here. &lt;span style="font-style:italic;"&gt;¡Me parece bien!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=o9iItzTta8Y:jKcnSPU9wmA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=o9iItzTta8Y:jKcnSPU9wmA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=o9iItzTta8Y:jKcnSPU9wmA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=o9iItzTta8Y:jKcnSPU9wmA:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=o9iItzTta8Y:jKcnSPU9wmA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=o9iItzTta8Y:jKcnSPU9wmA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=2526511421472894867" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2526511421472894867?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2526511421472894867?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/o9iItzTta8Y/google-app-engine-java-support.html" title="Google App Engine Java Support" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/04/google-app-engine-java-support.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YESHs5fip7ImA9WxVUGEk.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-2843887517871629715</id><published>2009-03-23T15:27:00.005-05:00</published><updated>2009-03-23T15:45:09.526-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-23T15:45:09.526-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="maven" /><title>Finally! Practical Maven Skinny Wars</title><content type="html">So, Maven 2.1 was finally released. I can't say I'm overly impressed with the pace, but considering it was driven almost exclusively by John Casey, it's a great achievement, nonetheless. Deterministic Build Lifecycle Planning (or DeBLiP, as we [well, just me] in the industry call it) is such a huge leap forward in build repeatability, it's hard to comment on at this stage. It's something best held to the clearer lens of retrospect.&lt;br /&gt;&lt;br /&gt;But enough about that. Something of immediate practical value: real skinny WARs. Until now the maven-war-plugin left you with two choices: no jars, or most jars. Sure, you could manually exclude all but a set, but it was a PITA and unpractical. Behold my surprise to find the newest WAR config addition to 2.1-beta-1: &lt;code&gt;packagingIncludes&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Use case:&lt;/span&gt;&lt;br /&gt;I want a &lt;span style="font-style:italic;"&gt;mostly&lt;/span&gt; skinny WAR that filters out all JARs except for struts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Solution:&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;project&gt;&lt;br /&gt;  ...&lt;br /&gt;  &amp;lt;build&gt;&lt;br /&gt;    &amp;lt;plugins&gt;&lt;br /&gt;      &amp;lt;plugin&gt;&lt;br /&gt;        &amp;lt;artifactId&gt;maven-war-plugin&amp;lt;/artifactId&gt;&lt;br /&gt;        &amp;lt;version&gt;2.1-beta-1&amp;lt;/version&gt;&lt;br /&gt;        &amp;lt;configuration&gt;&lt;br /&gt;          &amp;lt;packagingIncludes&gt;WEB-INF/lib/struts*.jar&amp;lt;/packagingIncludes&gt;&lt;br /&gt;          &amp;lt;archive&gt;&lt;br /&gt;            &amp;lt;manifest&gt;&lt;br /&gt;              &amp;lt;addClasspath&gt;true&amp;lt;/addClasspath&gt;&lt;br /&gt;              &amp;lt;classpathPrefix&gt;lib/&amp;lt;/classpathPrefix&gt;&lt;br /&gt;            &amp;lt;/manifest&gt;&lt;br /&gt;          &amp;lt;/archive&gt;&lt;br /&gt;        &amp;lt;/configuration&gt;&lt;br /&gt;      &amp;lt;/plugin&gt;&lt;br /&gt;    &amp;lt;/plugins&gt;&lt;br /&gt;  &amp;lt;/build&gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/project&gt;&lt;/pre&gt;Thanks WAR plugin guys! Now just fix the &lt;a href="http://www.coderoshi.com/2009/03/maven-hack-simple-skinny-wars.html"&gt;EAR problem&lt;/a&gt; and I'll be set.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=XbLGPTTDffA:UvZqFqF-M5w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=XbLGPTTDffA:UvZqFqF-M5w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=XbLGPTTDffA:UvZqFqF-M5w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=XbLGPTTDffA:UvZqFqF-M5w:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=XbLGPTTDffA:UvZqFqF-M5w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=XbLGPTTDffA:UvZqFqF-M5w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=2843887517871629715" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2843887517871629715?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/2843887517871629715?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/XbLGPTTDffA/finally-practical-maven-skinny-wars.html" title="Finally! Practical Maven Skinny Wars" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/03/finally-practical-maven-skinny-wars.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcCRnsyfyp7ImA9WxVVGUU.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-3947906062209358342</id><published>2009-03-13T12:05:00.000-05:00</published><updated>2009-03-13T18:14:27.597-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-13T18:14:27.597-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code te ching" /><title>Code Te Ching - Verse 49</title><content type="html">The elite rests entirely, his mind is balanced and at ease.&lt;br /&gt;He is not attached to methods or language, but he knows them well anyway.&lt;br /&gt;&lt;br /&gt;A pebble cannot halt a stream, but can block a dam ten thousand times larger.&lt;br /&gt;So too does the elite know, that though a language may have no use to the masses,&lt;br /&gt;There are times where it simply outshines the most elaborate of methods.&lt;br /&gt;&lt;br /&gt;The wise respect the direction of the elite,&lt;br /&gt;The wise knows he is not blind to the world.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=LfXeNpZAIK0:44nyS1fDDWU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=LfXeNpZAIK0:44nyS1fDDWU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=LfXeNpZAIK0:44nyS1fDDWU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=LfXeNpZAIK0:44nyS1fDDWU:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=LfXeNpZAIK0:44nyS1fDDWU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=LfXeNpZAIK0:44nyS1fDDWU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=3947906062209358342" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3947906062209358342?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/3947906062209358342?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/LfXeNpZAIK0/code-te-ching-verse-49.html" title="Code Te Ching - Verse 49" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/03/code-te-ching-verse-49.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMMRXo-eCp7ImA9WxVWGUs.&quot;"><id>tag:blogger.com,1999:blog-1906868083678732010.post-6330853116318078588</id><published>2009-03-01T22:04:00.005-06:00</published><updated>2009-03-01T22:18:04.450-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-01T22:18:04.450-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="maven" /><title>Maven Hack: Simple Skinny WARs</title><content type="html">Reading Maven's skinny-war documentation, it might turn you off to the idea. A skinny war is where your WAR does not contain any jar files, but instead get's packaged within an EAR than instead contains the jars. So rather than a zipped up EAR that looks like this:&lt;pre&gt;myear-1.0.ear&lt;br /&gt;\__mywar-1.0.war&lt;br /&gt;     \__WEB-INF/lib/&lt;br /&gt;          |__ log4j-1.2.8.jar&lt;br /&gt;          \__ commons-logging-1.1.jar&lt;/pre&gt;It will instead look like this:&lt;pre&gt;myear-1.0.ear&lt;br /&gt;|__mywar-1.0.war&lt;br /&gt;\__lib/&lt;br /&gt;     |__ log4j-1.2.8.jar&lt;br /&gt;     \__ commons-logging-1.1.jar&lt;/pre&gt;By default, the maven-ear-plugin assumes that any WAR dependencies already have the required jars packaged into it (in other words, it assumes a "fat" war). Because of this assumption, the EAR plugin will not package the WAR's transitive dependencies (why should it? If it did, you'd have duplicate dependencies, and the EAR would be twice the size).&lt;br /&gt;&lt;br /&gt;The problem is, because of this assumption, when you instead provide it with a "skinny" war (one without JARs), the EAR plugin cannot know that the WAR it is given doesn't have those dependencies already. If you give the EAR as skinny WAR, the package will look like this:&lt;pre&gt;myear-1.0.ear&lt;br /&gt;\__mywar-1.0.war&lt;/pre&gt;Hardly what we wanted! The fix according to the documentation is to duplicate the WAR's dependencies in the EAR, so the EAR can download and install them. Note that the maven-ear-plugin only ignores WAR transitive dependencies, not JARs or EJBs. But duplicating all WAR dependencies isn't only a lot of typing, it breaks encapsulation of the WAR projects. What to do!? (NOTE: "breaks encapsulation" means, if your skinny WAR project depends on log4j:1.2.8 and commons-logging:1.1, then your EAR project will need to also add the dependencies log4j:1.2.8 and commons-logging:1.1. If you upgrade your WAR to use log4j:1.2.12, then you must make the change in your EAR too. Fail.)&lt;br /&gt;&lt;br /&gt;Luckily, we can fix this egregious conundrum.&lt;br /&gt;&lt;br /&gt;The maven-ear-plugin will package up transitive dependencies of all projects except for WARs (and possibly EAR - I've never really tried it). This means, we can add the WAR project's POM as it's own dependency.&lt;br /&gt;&lt;br /&gt;So, your EAR dependency list will now contain two dependencies for each WAR &lt;span style="font-style:italic;"&gt;only&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;mywar:1.0:war and mywar:1.0:pom. Although the EAR won't package up your skinny WAR's dependencies, it _will_ package the POM's dependencies - which just so happen to be exactly the same as the WAR's! Now your EAR POM will look something like this.&lt;pre&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.myorg&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;mywar&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.myorg&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;mywar&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;/pre&gt;Yatta!&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&amp;copy; 2007 Eric Redmond&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GdVIMWF17MU:A51H3qJOvrM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GdVIMWF17MU:A51H3qJOvrM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GdVIMWF17MU:A51H3qJOvrM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GdVIMWF17MU:A51H3qJOvrM:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/coderoshi?a=GdVIMWF17MU:A51H3qJOvrM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/coderoshi?i=GdVIMWF17MU:A51H3qJOvrM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1906868083678732010&amp;postID=6330853116318078588" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6330853116318078588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1906868083678732010/posts/default/6330853116318078588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/coderoshi/~3/GdVIMWF17MU/maven-hack-simple-skinny-wars.html" title="Maven Hack: Simple Skinny WARs" /><author><name>Eric Redmond</name><uri>http://www.blogger.com/profile/06061345369534079723</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://www.coderoshi.com/2009/03/maven-hack-simple-skinny-wars.html</feedburner:origLink></entry></feed>
