<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>:jasonrudolph =&gt; :blog</title>
	
	<link>http://jasonrudolph.com/blog</link>
	<description>puts Blog.new("nonsense")</description>
	<pubDate>Wed, 03 Dec 2008 03:11:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<creativeCommons:license>http://creativecommons.org/licenses/by-sa/3.0/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by-sa/3.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/jasonrudolph" type="application/rss+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.rojo.com/add-subscription?resource=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://blog.rojo.com/RojoWideRed.gif">Subscribe with Rojo</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/jasonrudolph" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.addtoany.com/?linkname=%3Ajasonrudolph%20%3D%3E%20%3Ablog&amp;linkurl=http%3A%2F%2Ffeeds.feedburner.com%2Fjasonrudolph&amp;type=feed" src="http://www.addtoany.com/addfr-b.gif">Add to Any Feed Reader</feedburner:feedFlare><item>
		<title>TextMate Oldie But Goodie Wrap-up</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/473155098/</link>
		<comments>http://jasonrudolph.com/blog/2008/12/02/textmate-oldie-but-goodie-wrap-up/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 02:49:30 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Productivity]]></category>

		<category><![CDATA[TextMate]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=241</guid>
		<description><![CDATA[With November behind us, there&#8217;s now a month of TextMate productivity tips scattered across the twitterverse.  In case you missed any of them, here&#8217;s a recap:


November 1 - Use Control+Option+Command+V to view your clipboard history. Then hit Enter to paste the selected item into the current document.
November 2 - Use Control+Shift+C to access the [...]]]></description>
			<content:encoded><![CDATA[<p>With November behind us, there&#8217;s now a <a href="http://jasonrudolph.com/blog/2008/11/04/a-month-of-textmate-productivity-tips/" title="jasonrudolph/blog &raquo; A Month of TextMate Productivity Tips">month of TextMate productivity tips</a> scattered across the twitterverse.  In case you missed any of them, here&#8217;s a recap:</p>

<ul>
<li><a href="http://twitter.com/jasonrudolph/status/985128152" title="Twitter / jasonrudolph: TMOBGOTD #1: TextMate Oldie But Goodie Of The Day">November 1</a> - Use <strong>Control+Option+Command+V</strong> to view your clipboard history. Then hit <strong>Enter</strong> to paste the selected item into the current document.</li>
<li><a href="http://twitter.com/jasonrudolph/status/986324036" title="Twitter / jasonrudolph: TMOBGOTD #2: TextMate Oldie But Goodie Of The Day">November 2</a> - Use <strong>Control+Shift+C</strong> to access the Math bundle from any file. Instantly perform calculations, add/subtract selected numbers, and more.</li>
<li><a href="http://twitter.com/jasonrudolph/status/987583480" title="Twitter / jasonrudolph: TMOBGOTD #3: TextMate Oldie But Goodie Of The Day">November 3</a> - With your cursor on any Ruby string, use <strong>Control+Shift+<code>'</code></strong> to toggle between single quotes, double quotes, and <code>%Q{}</code>. Also works with Groovy, JavaScript, Perl, SQL, Bash, etc.</li>
<li><a href="http://twitter.com/jasonrudolph/status/989258974" title="Twitter / jasonrudolph: TMOBGOTD #4: TextMate Oldie But Goodie Of The Day">November 4</a> - In HTML (or HTML-friendly) files, select several lines and use <strong>Control+Command+Shift+W</strong> to wrap each line in a pair of HTML tags.</li>
<li><a href="http://twitter.com/jasonrudolph/status/991596639" title="Twitter / jasonrudolph: TMOBGOTD #5: TextMate Oldie But Goodie Of The Day">November 5</a>    - <strong>Control+Escape</strong> brings up the automation menu. Use it for quick access to the current bundle and to navigate through other bundles.</li>
<li><a href="http://twitter.com/jasonrudolph/status/993248827" title="Twitter / jasonrudolph: TMOBGOTD #6: TextMate Oldie But Goodie Of The Day">November 6</a>    - With your cursor on any Ruby symbol, use <strong>Control+:</strong> to change it to a string. Use <strong>Control+:</strong> again to toggle back to a symbol.</li>
<li><a href="http://twitter.com/jasonrudolph/status/994869385" title="Twitter / jasonrudolph: TMOBGOTD #7: TextMate Oldie But Goodie Of The Day">November 7</a>    - Folding is (almost always) evil and is triggered by accident more often than not. Turn it off in <strong>View -> Gutter -> Foldings</strong>.</li>
<li><a href="http://twitter.com/jasonrudolph/status/996269641" title="Twitter / jasonrudolph: TMOBGOTD #8: TextMate Oldie But Goodie Of The Day">November 8</a>    - For the rare occasion when you <em>want</em> folding, use <strong>F1</strong> to fold the current block. Use <strong>Command+Option+n</strong> (where n is a digit) to toggle foldings at the nth level.</li>
<li><a href="http://twitter.com/jasonrudolph/status/997515553" title="Twitter / jasonrudolph: TMOBGOTD #9: TextMate Oldie But Goodie Of The Day">November 9</a>    - With your cursor on a misspelled word, use <strong>Option+F2</strong> to bring up suggested spelling corrections. Hit <strong>Enter</strong> to choose a correction.</li>
<li><a href="http://twitter.com/jasonrudolph/status/998734765" title="Twitter / jasonrudolph: TMOBGOTD #10: TextMate Oldie But Goodie Of The Day">November 10</a>  - With your cursor on any ActiveRecord model, use <strong>Control+Command+Shift+S</strong> to instantly view the schema for that model.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1000366213" title="Twitter / jasonrudolph: TMOBGOTD #11: TextMate Oldie But Goodie Of The Day">November 11</a> - When working w/ CSS, use <strong>Command+Shift+C</strong> to bring up the OS X color palette. Choose a color to insert the corresponding hex code. </li>
<li><a href="http://twitter.com/jasonrudolph/status/1002089182" title="Twitter / jasonrudolph: TMOBGOTD #12: TextMate Oldie But Goodie Of The Day">November 12</a> - Selection-fu => Use <strong>Control+W</strong> to select the current word. Use <strong>Command+Shift+L</strong> to select the current line.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1003798845" title="Twitter / jasonrudolph: TMOBGOTD #13: TextMate Oldie But Goodie Of The Day">November 13</a> - Use <strong>Control+H</strong> to pull up the documentation for the selected word. Works for CSS attributes, Ruby methods, HTML tags, Javadoc, etc.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1005452019" title="Twitter / jasonrudolph: TMOBGOTD #14: TextMate Oldie But Goodie Of The Day">November 14</a> - Anywhere that ERb is supported, use <strong>Control+></strong> to produce a <%= %> sequence. Hit it again to cycle through the various flavors.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1007068201" title="Twitter / jasonrudolph: TMOBGOTD #15: TextMate Oldie But Goodie Of The Day">November 15</a> - Need fast access to placeholder text? Type &#8220;lorem&#8221; and hit <strong>Tab</strong>.           </li>
<li><a href="http://twitter.com/jasonrudolph/status/1008426064" title="Twitter / jasonrudolph: TMOBGOTD #16: TextMate Oldie But Goodie Of The Day">November 16</a> - Sometimes TextMate is too smart for its own good. Use <strong>Control+Command+V</strong> to paste <em>without</em> reindent. Especially useful for YAML.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1009988210" title="Twitter / jasonrudolph: TMOBGOTD #17: TextMate Oldie But Goodie Of The Day">November 17</a> - Fun with case conversions - <strong>Control+U</strong> => TO UPPERCASE. <strong>Control+Shift+U</strong> => to lowercase. <strong>Control+Option+U</strong> => Convert to Titlecase.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1011447822" title="Twitter / jasonrudolph: TMOBGOTD #18: TextMate Oldie But Goodie Of The Day">November 18</a> - Use <strong>Control+Tab</strong> to toggle focus between the editor window and the folder/file tree in the project drawer.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1013044747" title="Twitter / jasonrudolph: TMOBGOTD #19: TextMate Oldie But Goodie Of The Day">November 19</a> - Don&#8217;t lose time waiting for &#8220;Find in Project&#8221; to slog through a large project. Search fast w/ <a href="http://bit.ly/ack" title="protocool's ack-tmbundle at GitHub">Ack in Project</a>.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1014602882" title="Twitter / jasonrudolph: TMOBGOTD #20: TextMate Oldie But Goodie Of The Day">November 20</a> - Use <strong>Control+Option+Command+P</strong> to preview the current file as rendered HTML. Good for HTML (duh), Markdown, and Textile.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1017290604" title="Twitter / jasonrudolph: TMOBGOTD #21: TextMate Oldie But Goodie Of The Day">November 21</a> - <strong>Command+Option+[</strong> => Format current selection (or current line if nothing is selected) according to rules for the current grammar.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1018311743" title="Twitter / jasonrudolph: TMOBGOTD #22: TextMate Oldie But Goodie Of The Day">November 22</a> - Use <strong>Option+PageUp</strong> and <strong>Option+PageDown</strong> to page up/down while keeping your cursor in the middle of the screen. (On a laptop, <strong>PageUp</strong> is <strong>Function+Up</strong>. So, for this tip, you&#8217;d use <strong>Function+Option+Up</strong> and <strong>Function+Option+Down</strong>.)</li>
<li><a href="http://twitter.com/jasonrudolph/status/1019577832" title="Twitter / jasonrudolph: TMOBGOTD #23: TextMate Oldie But Goodie Of The Day">November 23</a> - Use <strong>Command+Option+W</strong> to toggle soft line wrapping.            </li>
<li><a href="http://twitter.com/jasonrudolph/status/1021193988" title="Twitter / jasonrudolph: TMOBGOTD #24: TextMate Oldie But Goodie Of The Day">November 24</a> - Hit <strong>Escape</strong> to auto-complete the current word using similar words in the current file (in order of their proximity to the cursor).</li>
<li><a href="http://twitter.com/jasonrudolph/status/1022973346" title="Twitter / jasonrudolph: TMOBGOTD #25: TextMate Oldie But Goodie Of The Day">November 25</a> - Enable <a href="http://bit.ly/tm" title="TextMate Manual » Calling TextMate from Other Applications">&#8220;Edit in TextMate&#8221;</a> to use TextMate from any Cocoa app - email in Mail.app, blog comments &amp; wikis in Safari, etc. </li>
<li><a href="http://twitter.com/jasonrudolph/status/1025110446" title="Twitter / jasonrudolph: TMOBGOTD #26: TextMate Oldie But Goodie Of The Day">November 26</a> - Use <strong>Option+Command+R</strong> to feed the current file (or selection) to any shell command and capture the output in any number of ways.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1026835629" title="Twitter / jasonrudolph: TMOBGOTD #27: TextMate Oldie But Goodie Of The Day">November 27</a> - Use <strong>Control+Option+Shift+H</strong> to change the language of the current file to HTML. Use &#8216;X&#8217; for XML or XSL. &#8216;R&#8217; for Ruby, Rails, etc. </li>
<li><a href="http://twitter.com/jasonrudolph/status/1028073252" title="Twitter / jasonrudolph: TMOBGOTD #28: TextMate Oldie But Goodie Of The Day">November 28</a> - <strong>Command+Shift+T</strong> => Go to symbol. This grammar-sensitive fuzzy finder locates classes &amp; methods in Ruby, IDs in HTML, etc.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1029697485" title="Twitter / jasonrudolph: TMOBGOTD #29: TextMate Oldie But Goodie Of The Day">November 29</a> - Hold down the <strong>Option</strong> key while selecting an area of text to make a columnar selection. More info here http://bit.ly/tmcol.</li>
<li><a href="http://twitter.com/jasonrudolph/status/1030966782" title="Twitter / jasonrudolph: TMOBGOTD #30: TextMate Oldie But Goodie Of The Day">November 30</a> - Forgot how to access a certain feature of TextMate. Quickly find any and all of the TMOBGOTD tips (and more) with <strong>Command+Shift+?</strong></li>
</ul>

<p>And if you&#8217;re still following along, you&#8217;re hardcore enough that you&#8217;ll want to make sure that the bonus inaugural entry is firmly tucked into your TextMate black belt as well:</p>

<ul>
<li><a href="http://twitter.com/jasonrudolph/statuses/983796383" title="Twitter / jasonrudolph: TMOBGOTD #0: TextMate Oldie But Goodie Of The Day">October 31</a> - <strong>Control+Command+T</strong> => Fuzzy find for bundle items.</li>
</ul>

<p>Got a favorite TextMate tip of your own to share? Tag it with the worst acronym ever (<a href="http://search.twitter.com/search?q=TMOBGOTD" title="TMOBGOTD - Twitter Search">TMOBGOTD</a> - TextMate Oldie But Goodie Of The Day) for all the TextMate-lovin&#8217; world to see.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=vxcMo"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=vxcMo" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=8YduO"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=8YduO" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=7nDLo"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=7nDLo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/473155098" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/12/02/textmate-oldie-but-goodie-wrap-up/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F12%2F02%2Ftextmate-oldie-but-goodie-wrap-up%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/12/02/textmate-oldie-but-goodie-wrap-up/</feedburner:origLink></item>
		<item>
		<title>Grails vs. Rails: Are we seriously still talking about this?!</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/457835505/</link>
		<comments>http://jasonrudolph.com/blog/2008/11/18/grails-vs-rails-are-we-seriously-still-talking-about-this/#comments</comments>
		<pubDate>Tue, 18 Nov 2008 20:27:40 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=236</guid>
		<description><![CDATA[I had the pleasure of meeting a local Grails enthusiast last night who was new to the Triangle, but I was disappointed to see the same old argument spoil the show.  The Rails vs. Grails debate is tired, and it&#8217;s curiously - perhaps even embarrassingly - unidirectional. I hereby call on the great philosophers [...]]]></description>
			<content:encoded><![CDATA[<p>I had the <a href="http://twitter.com/jasonrudolph/status/1010492093" title="Twitter / Jason Rudolph: Checking out @robertfischer's Grails presentation at TriJUG">pleasure of meeting a local Grails enthusiast last night</a> who was new to the Triangle, but I was disappointed to see the same old argument spoil the show.  The <a href="http://jasonrudolph.com/blog/tag/rails/" title="jasonrudolph.com/blog &raquo; Rails">Rails</a> vs. <a href="http://jasonrudolph.com/blog/tag/grails/" title="jasonrudolph.com/blog &raquo; Grails">Grails</a> debate is tired, and it&#8217;s curiously - perhaps even <a href="http://enfranchisedmind.com/blog/2008/11/18/intro-to-grails-presentation-slides/#comment-33865" title="Enfranchised Mind &raquo; &#8220;Intro to Grails&#8221; Presentation Slides">embarrassingly</a> - unidirectional. I hereby call on the great philosophers to weigh in:</p>

<p><a href="http://www.youtube.com/watch?v=aMfr2CgIPhg" title="YouTube: Rodney King - Can We All Get Along...">Philosopher, The First</a> </p>

<p><a href="http://www.vanderburg.org/Blog/Software/Development/koan.blog" title="Glenn Vanderburg: Six of One, a Half Dozen of the Other">Philosopher, The Second</a></p>

<p>Now, go in peace.</p>

<p>&#8211;</p>

<p><strong>Update 2008-11-19</strong> - Robert has deleted his comment (originally linked to above and <a href="http://jasonrudolph.com/blog/2008/11/18/grails-vs-rails-are-we-seriously-still-talking-about-this/#comment-14775" title="jasonrudolph.com/blog - Comment by Robert Fischer">referenced by Robert below</a>) from his blog.  His original blog post remains intact, sans incendiary comment.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=Upufn"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=Upufn" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=RlUvN"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=RlUvN" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=ns1On"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=ns1On" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/457835505" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/11/18/grails-vs-rails-are-we-seriously-still-talking-about-this/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F11%2F18%2Fgrails-vs-rails-are-we-seriously-still-talking-about-this%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/11/18/grails-vs-rails-are-we-seriously-still-talking-about-this/</feedburner:origLink></item>
		<item>
		<title>A Month of TextMate Productivity Tips</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/442115417/</link>
		<comments>http://jasonrudolph.com/blog/2008/11/04/a-month-of-textmate-productivity-tips/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 14:00:01 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Productivity]]></category>

		<category><![CDATA[TextMate]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=230</guid>
		<description><![CDATA[I&#8217;ve had the joy of calling TextMate my editor of choice for almost three years now, and as the The Pragmatic Programmer wisely recommends, my editor has definitely grown to become &#8220;an extension of [my] hand.&#8221;  Often when giving a presentation or pair programming, someone will stop me to ask, &#8220;Wait a minute. How&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had the joy of calling <a href="http://macromates.com/" title="TextMate — The Missing Editor for Mac OS X">TextMate</a> my editor of choice for almost three years now, and as the <a href="http://pragmaticprogrammer.com/the-pragmatic-programmer/extracts/tips" title="Pragmatic Software Development Tips from the &quot;Pragmatic Programmer&quot;">The Pragmatic Programmer</a> wisely recommends, my editor has definitely grown to become &#8220;an extension of [my] hand.&#8221;  Often when giving a presentation or pair programming, someone will stop me to ask, &#8220;Wait a minute. How&#8217;d you do that?&#8221; &#8220;<em>That</em>&#8221; is inevitably in reference to some bit of hyper-productive TextMate keyboard wizardry that eliminated several steps the person was otherwise expecting to see. Of course, a few years ago you were more likely to hear <em>me</em> asking that question. (And I still love it when I get to ask that question nowadays.)</p>

<p>For the month of November, I&#8217;ll share one of these <em>&#8220;How&#8217;d you do that?&#8221;</em> tips each day. They&#8217;re by no means revolutionary; they&#8217;re much more in the <em>oldie but goodie</em> camp.  Hence the name: <strong>TextMate Oldie But Goodie Of The Day (TMOBGOTD)</strong>. Each one can shave time - sometimes several seconds - off of common tasks.  And if they&#8217;re common tasks in your workflow, then that time surely adds up.  </p>

<p>You can follow along at <a href="http://twitter.com/jasonrudolph" title="Twitter / Jason Rudolph">twitter.com/jasonrudolph</a>, where the first four tips are already in place.</p>

<ol>
<li><a href="http://twitter.com/jasonrudolph/status/985128152" title="Twitter / jasonrudolph: TMOBGOTD #1: TextMate Oldie But Goodie Of The Day">November 1</a> - Use <strong>Control+Option+Command+V</strong> to view your clipboard history. Then hit <strong>Enter</strong> to paste the selected item into the current document.</li>
<li><a href="http://twitter.com/jasonrudolph/status/986324036" title="Twitter / jasonrudolph: TMOBGOTD #2: TextMate Oldie But Goodie Of The Day">November 2</a> - Use <strong>Control+Shift+C</strong> to access the Math bundle from any file. Instantly perform calculations, add/subtract selected numbers, and more.</li>
<li><a href="http://twitter.com/jasonrudolph/status/987583480" title="Twitter / jasonrudolph: TMOBGOTD #3: TextMate Oldie But Goodie Of The Day">November 3</a> - With your cursor on any Ruby string, use <strong>Control+Shift+<code>'</code></strong> to toggle between single quotes, double quotes, and <code>%Q{}</code>. Also works with Groovy, JavaScript, Perl, SQL, Bash, etc.</li>
<li><a href="http://twitter.com/jasonrudolph/status/989258974" title="Twitter / jasonrudolph: TMOBGOTD #4: TextMate Oldie But Goodie Of The Day">November 4</a> - In HTML (or HTML-friendly) files, select several lines and use <strong>Control+Command+Shift+W</strong> to wrap each line in a pair of HTML tags.</li>
</ol>

<p>Whether you&#8217;re seeing these techniques for the first time or rediscovering a command that you&#8217;d forgotten about, take a moment to try it out.  Perform each technique three times, and you&#8217;ll be well on your way to committing it to memory. In just 60 seconds a day, you too can train to become a TextMate black belt.  Or double your money back.  Guaranteed.</p>

<p>&#8211;</p>

<p><strong>Update 2008-12-02</strong> - Check out the <a href="http://jasonrudolph.com/blog/2008/12/02/textmate-oldie-but-goodie-wrap-up/" title="jasonrudolph/blog &raquo; TextMate Oldie But Goodie Wrap-up">full list of tips in the wrap-up post</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=8Fxwn"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=8Fxwn" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=dRnQN"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=dRnQN" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=juEUn"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=juEUn" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/442115417" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/11/04/a-month-of-textmate-productivity-tips/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F11%2F04%2Fa-month-of-textmate-productivity-tips%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/11/04/a-month-of-textmate-productivity-tips/</feedburner:origLink></item>
		<item>
		<title>Testing Anti-Patterns Potpourri - Quotes, Resources, and Collective Wisdom</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/413685525/</link>
		<comments>http://jasonrudolph.com/blog/2008/10/07/testing-anti-patterns-potpourri-quotes-resources-and-collective-wisdom/#comments</comments>
		<pubDate>Tue, 07 Oct 2008 10:30:02 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Testing]]></category>

		<category><![CDATA[Testing Anti-Patterns]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=204</guid>
		<description><![CDATA[While working on the Testing Anti-Patterns series over the past few months, I&#8217;ve had the pleasure of reading some great writing on testing, test-driven development, code coverage analysis, and the bigger picture of software quality in general.  What follows is a collection of some of my favorite findings: quotes and resources spanning the last [...]]]></description>
			<content:encoded><![CDATA[<p>While working on the <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns">Testing Anti-Patterns series</a> over the past few months, I&#8217;ve had the pleasure of reading some great writing on testing, test-driven development, code coverage analysis, and the bigger picture of software quality in general.  What follows is a collection of some of my favorite findings: quotes and resources spanning the last ten years and then some.</p>

<h2>How Not to Test</h2>

<p>Let&#8217;s start off with something light.  James Carr&#8217;s <a href="http://blog.james-carr.org/?p=44" title="James Carr &raquo; Blog Archive &raquo; TDD Anti-Patterns">TDD Anti-Pattern Catalogue</a> is a good, fun read that&#8217;s downright hilarious at times (but only because we remember <del>writing</del> seeing these tests once or twice).  And not only are the anti-patterns that James proposes worth reading, you owe it to yourself to check out the extensive discussion in the comments as well. There you&#8217;ll find folks chiming in with many additional gems, including:</p>

<ul>
<li><a href="http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/#comment-47093" title="James Carr &raquo; Blog Archive &raquo; TDD Anti-Patterns">The Blue Moon</a> - Matt Simner&#8217;s aptly-named anti-pattern is one we&#8217;ve all hit at least once: &#8220;A test that’s specifically dependent on the current date, and fails as a result of things like public holidays, leap years, weekends, 5-week months, etc.&#8221;  Ouch.  </li>
<li><a href="http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/#comment-77729" title="James Carr &raquo; Blog Archive &raquo; TDD Anti-Patterns">Honest Guv</a> - Graham Lenton&#8217;s contribution to the list brings back some memories I&#8217;d rather forget: &#8220;Where the expected outcome is so entropic that the developer simply asserts true with a comment &#8216;this works, honestly.&#8217;&#8221;  Um.  Sure it does.</li>
</ul>

<h2>We&#8217;re Still Figuring This Stuff Out</h2>

<p>Some tests are just so incredibly rotten that it&#8217;s easy to definitively declare a better approach, but it&#8217;s not always that black and white.  Just as we have to make <a href="http://www.vanderburg.org/Blog/Software/Development/koan.blog" title="Glenn Vanderburg: Blog - Six of One, a Half Dozen of the Other">trade-offs</a> when designing and developing production code, so too do we have to weigh the advantages and disadvantages of the available approaches for testing that code.  </p>

<p>In his post on <a href="http://blog.jayfields.com/2008/06/developer-testing-and-importance-of.html" title="Jay Fields' Thoughts: Developer Testing and the Importance of Context">Developer Testing and the Importance of Context</a>, Jay Fields reflects on the catalog of testing patterns he&#8217;s documented over the past few years, and he reminds us that &#8220;context is still king:&#8221;</p>

<blockquote>
  <p>You&#8217;ll find that some of [the] approaches are in direct conflict. This isn&#8217;t because one pattern is superior to another in isolation, it&#8217;s because one pattern is superior to another in context.</p>
</blockquote>

<p>Software development certainly isn&#8217;t the only engineering discipline that requires its practitioners to manage trade-offs, so how do we compare with other industries?  The often controversial (but always entertaining) Neal Ford argues that &#8220;testing is the engineering rigor of software development,&#8221; but that <a href="http://memeagora.blogspot.com/2007/11/building-bridges-without-engineering.html" title="Meme Agora: Building Bridges without Engineering">we&#8217;ve still got a long way to go</a> if software development will ever truly be an engineering discipline:</p>

<blockquote>
  <p>It may just be that software will always resist traditional engineering kinds of analysis. We&#8217;ll know in a few thousand years, when we&#8217;ve been building software as long as we&#8217;ve been building bridges. We&#8217;re currently at the level in software where bridge builders were when they built a bridge, ran a heavy cart across it, and it collapsed. &#8220;Well, that wasn&#8217;t a very good bridge. Let&#8217;s try again.&#8221;</p>
</blockquote>

<h2>Pragmatic Use of Code Coverage Analysis</h2>

<p>We&#8217;ve talked quite a bit about <a href="http://jasonrudolph.com/blog/2008/06/10/a-brief-discussion-of-code-coverage-types/" title="jasonrudolph.com/blog -- A Brief Discussion of Code Coverage Types">code coverage</a> in our discussion of <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog -- Testing Anti-Patterns: How to Fail With 100% Test Coverage">testing anti-patterns</a>.  Brian Marick&#8217;s 1997 paper titled <a href="http://www.exampler.com/testing-com/writings/coverage.pdf" title="PDF - 'How to Misuse Code Coverage' by Brian Marick">How to Misuse Code Coverage</a> is a must-read, full of pragmatic advice from a veteran tester:</p>

<blockquote>
  <p>I&#8217;ve written four coverage tools &#8230; I still find myself looking at a coverage condition, saying &#8220;I know how to satisfy that,&#8221; and getting an almost physical urge to write a quick-and-dirty test that would make the coverage tool happy. It&#8217;s only the certain knowledge that customers don&#8217;t care if the coverage tool is happy that restrains me.</p>
  
  <p>The most common coverage mistake is giving into that urge. I warn against it by saying that coverage tools don&#8217;t give commands (&#8221;make that evaluate true&#8221;), they give clues (&#8221;you made some mistakes somewhere around there&#8221;). If you treat their clues as commands, you&#8217;ll end up in the fable of the Sorcerer&#8217;s Apprentice: causing a disaster because your tools do something very precisely, very enthusiastically, and with inhuman efficiency - but that something is only what you thought you wanted.</p>
  
  <p>Designing your initial test suite to achieve 100% coverage is an even worse idea. It’s a sure way to create a test suite weak at finding those all-important faults of omission. Further, the coverage tool can no longer tell you where your test suite is weak - because it&#8217;s uniformly weak in precisely the way that coverage can&#8217;t directly detect. Don&#8217;t use code coverage in test design. The return on your testing dollar (in terms of bugs found) is too low.</p>
</blockquote>

<p>Now that we know how to misuse code coverage, the Google Testing Blog weighs in on the <a href="http://googletesting.blogspot.com/2008/03/tott-understanding-your-coverage-data.html" title="Google Testing Blog: TotT: Understanding Your Coverage Data">proper application of coverage analysis</a>:</p>

<blockquote>
  <ol>
  <li><p>Make your tests as comprehensive as you can, without coverage in mind. This means writing as many test cases as are necessary, not just the minimum set of test cases to achieve maximum coverage.</p></li>
  <li><p>Check coverage results from your tests. Find code that&#8217;s missed in your testing. Also look for unexpected coverage patterns, which usually indicate bugs.</p></li>
  <li><p>Add additional test cases to address the missed cases you found in step 2.</p></li>
  <li><p>Repeat step 2-3 until it&#8217;s no longer cost effective. If it is too difficult to test some of the corner cases, you may want to consider refactoring to improve testability.</p></li>
  </ol>
</blockquote>

<p>In <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670" title="Amazon.com: Code Complete: A Practical Handbook of Software Construction: Steve McConnell">Code Complete</a>, Steve McConnell offers sage advice for knowing when you can reasonably move to Step 2.  (Hint: Just testing the happy path ain&#8217;t gonna get you there.):</p>

<blockquote>
  <p>Immature testing organizations tend to have about five clean tests for every dirty test.  Mature testing organizations tend to have five dirty tests for every clean test. This ratio is not reversed by reducing the clean tests; it’s done by creating 25 times as many dirty tests.</p>
</blockquote>

<p>And we should always keep the value of code coverage (or any isolated metric for that matter) in perspective, as Andy Glover reminds us in his post on <a href="http://thediscoblog.com/2008/03/20/unambiguously-analyzing-metrics" title="The Disco Blog  &raquo; Blog Archive   &raquo; Unambiguously analyzing metrics">unambiguously analyzing metrics</a>:</p>

<blockquote>
  <p>Metrics are more copasetic when combined with other metrics and trended – for instance, complexity alone is somewhat interesting, but pairing complexity with code coverage paints a much more detailed metric that bears understanding. High complexity with low coverage is clearly more risky than the same complexity with high code coverage &#8230;</p>
</blockquote>

<h2>Beyond Developer Testing</h2>

<p>Not only should we avoid relying on a single metric, we should also be wary of relying too much on a single form (or a single &#8220;layer&#8221;) of testing.  As Luke Francl argues in his <a href="http://railspikes.com/2008/7/11/testing-is-overrated" title="Rail Spikes: Testing is Overrated">call for more diverse testing</a>, even the most exhaustive set of unit tests is limited in the scope of defects it can find [1]: </p>

<blockquote>
  <p><img src="http://jasonrudolph.com/blog/wp-content/uploads/200810_testing_layers_venn_diagram.png" alt="200810 Testing Layers Venn Diagram" />     </p>
  
  <p>Don’t put all your eggs in one basket. The most interesting thing about these defect detection techniques is that they tend to find different errors. Unit testing finds certain errors; manual testing others; usability testing and code reviews still others.</p>
</blockquote>

<p>In his post on <a href="http://www.codinghorror.com/blog/archives/001059.html" title="Coding Horror: The Ultimate Unit Test Failure">The Ultimate Unit Test Failure</a>, Jeff Atwood comes out swingin&#8217; and begs development teams to invest in interaction design with the same enthusiasm (or perhaps more) that we give to developer testing:</p>

<blockquote>
  <p>Perfectly executed code coverage doesn&#8217;t mean users will use your program. Or that it&#8217;s even <em>worth</em> using in the first place.</p>
</blockquote>

<h2>No Silver Bullet</h2>

<p>If there&#8217;s any one theme that we can observe across this collection of ideas, it&#8217;s the recognition that no recipe, or tool, or one-size-fits-all process offers the One True Way (TM) to develop quality software.  As Michael Feathers <a href="http://michaelfeathers.typepad.com/michael_feathers_blog/2008/06/the-flawed-theo.html" title="Michael Feathers' Blog: The Flawed Theory Behind Unit Testing">points out</a>, quality doesn&#8217;t come from a &#8220;mechanistic&#8221; approach to testing:</p>

<blockquote>
  <p>Quality is a function of thought and reflection - precise thought and reflection. That’s the magic. Techniques which reinforce that discipline invariably increase quality.</p>
</blockquote>

<p>It&#8217;s only that critical thought that will tell us when it would be more cost-effective to use one flavor of testing over another.  It&#8217;s only that critical thought that will uncover implied requirements in a user story or prompt us to ask about hidden assumptions that might be lingering in a given use case.  It&#8217;s only that critical thought that will recognize when the pattern that&#8217;s worked for us 95% of the time simply isn&#8217;t appropriate for the particular scenario we&#8217;ve just come across.  To forgo that critical thought in search of a silver bullet, that&#8217;s the ultimate testing anti-pattern.</p>

<h2>Notes</h2>

<p>[1] Luke notes that the specific overlaps in the diagram are admittedly arbitrary.  The specific areas of overlap are insignificant for our purposes here.  Noteworthy is that while there is some overlap between these forms of testing, each one tends to identify at least some defects that are less likely to be identified by other forms of testing.  (Diagram used with permission.)</p>

<hr />

<p>This <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns">series</a> is taken from the <a href="http://blog.thinkrelevance.com/2008/5/23/how-to-fail-with-100-test-coverage" title="Relevance Blog : How To Fail With 100% Test Coverage">How To Fail With 100% Test Coverage</a> talk. Check the <a href="http://thinkrelevance.com/events" title="Relevance: Events">schedule</a> for a talk near you.</p>

<p>&#8211;</p>

<p><strong>Thanks</strong> to <a href="http://thinkrelevance.com/about/stuart-halloway" title="Relevance: Stuart Halloway">Stuart Halloway</a>, <a href="http://robsanheim.com/" title="Panasonic Youth">Rob Sanheim</a>, and <a href="http://gigavolt.net/blog/" title="Potential Differences">Greg Vaughn</a> for reading drafts of this post.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=CaWOm"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=CaWOm" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=HZupM"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=HZupM" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=IwT3m"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=IwT3m" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/413685525" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/10/07/testing-anti-patterns-potpourri-quotes-resources-and-collective-wisdom/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F10%2F07%2Ftesting-anti-patterns-potpourri-quotes-resources-and-collective-wisdom%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/10/07/testing-anti-patterns-potpourri-quotes-resources-and-collective-wisdom/</feedburner:origLink></item>
		<item>
		<title>Audio, Video, Slides: How to Fail With 100% Test Coverage at raleigh.rb</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/387520541/</link>
		<comments>http://jasonrudolph.com/blog/2008/09/09/audio-video-slides-how-to-fail-with-100-test-coverage-at-raleighrb/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 10:00:34 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Code Coverage]]></category>

		<category><![CDATA[Rails]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Speaking]]></category>

		<category><![CDATA[Testing]]></category>

		<category><![CDATA[Testing Anti-Patterns]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=196</guid>
		<description><![CDATA[The Testing Anti-Patterns series began as a conference presentation titled How to Fail With 100% Test Coverage, and I recently had the pleasure of presenting that talk at the Raleigh-Area Ruby Brigade (raleigh.rb).  Matthew Bass was kind enough to record the audio from the event, and I&#8217;ve taken a stab at syncing that audio [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns: How to Fail With 100% Test Coverage">Testing Anti-Patterns series</a> began as a conference presentation titled <strong>How to Fail With 100% Test Coverage</strong>, and I recently had the pleasure of presenting that talk at the <a href="http://ruby.meetup.com/3/calendar/7849526/" title="Raleigh-area Ruby Brigade August Meeting - Jason Rudolph on 'How to Fail With 100% Test Coverage'">Raleigh-Area Ruby Brigade (raleigh.rb)</a>.  <a href="http://matthewbass.com" title="matthewbass.com">Matthew Bass</a> was kind enough to record the audio from the event, and I&#8217;ve taken a stab at syncing that audio with the slides for a full-on multimedia extravaganza.<sup>&sect;</sup></p>

<p><object width="400" height="302">   <param name="allowfullscreen" value="true" />   <param name="allowscriptaccess" value="always" />   <param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1683910&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=59a5d1&amp;fullscreen=1" /> <embed src="http://vimeo.com/moogaloop.swf?clip_id=1683910&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=59a5d1&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="302"></embed></object><br /></p>

<p><a href="http://vimeo.com/1683910?pg=embed&amp;sec=1683910" title="How To Fail With 100% Test Coverage on Vimeo">Download Quicktime video via Vimeo</a> (registration required)</p>

<p><a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?i=34717809&amp;id=273853776" title="raleigh.rb Podcast on iTunes - Jason Rudolph on 'How to Fail With 100% Test Coverage'">Download MP3 via iTunes</a></p>

<p><a href="http://www.raleighrb.com/podcast/2008-08-19_how_to_fail.mp3" title="raleigh.rb MP3 - Jason Rudolph on 'How to Fail With 100% Test Coverage'">Download MP3 directly</a></p>

<p><a href="http://jasonrudolph.com/downloads/presentations/How_to_Fail_With_100_Percent_Test_Coverage.pdf" title="Slides - Jason Rudolph on 'How to Fail With 100% Test Coverage'&quot;">Download slides</a></p>

<p>Wanna see this talk live?  Check the <a href="http://thinkrelevance.com/events" title="Relevance: Events">schedule</a> for an event near you.</p>

<p>&#8211;</p>

<p><sup>&sect;</sup> Keynote&#8217;s Quicktime recording/exporting has a seemingly diabolical sense of humor.  For comedic effect (or perhaps to make sure you&#8217;re paying attention), it likes to randomly shuffle the slides every once in a while.  So in the video, you&#8217;ll notice that unfortunately the slides and the audio don&#8217;t <em>always</em> line up just right.  If you find it too erratic, then it may be easier to listen to the <a href="http://www.raleighrb.com/podcast/2008-08-19_how_to_fail.mp3" title="raleigh.rb MP3 - Jason Rudolph on 'How to Fail With 100% Test Coverage'">audio</a> and advance the <a href="http://jasonrudolph.com/downloads/presentations/How_to_Fail_With_100_Percent_Test_Coverage.pdf" title="Slides - Jason Rudolph on 'How to Fail With 100% Test Coverage'&quot;">slides</a> manually.  And if you see Tyler Durden make a cameo, well, it was probably just Keynote having a laugh.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=00ZPl"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=00ZPl" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=yLXuL"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=yLXuL" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=QuAXl"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=QuAXl" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/387520541" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/09/09/audio-video-slides-how-to-fail-with-100-test-coverage-at-raleighrb/feed/</wfw:commentRss>
<enclosure url="http://www.raleighrb.com/podcast/2008-08-19_how_to_fail.mp3" length="34404226" type="audio/mpeg" />
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F09%2F09%2Faudio-video-slides-how-to-fail-with-100-test-coverage-at-raleighrb%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/09/09/audio-video-slides-how-to-fail-with-100-test-coverage-at-raleighrb/</feedburner:origLink></item>
		<item>
		<title>Grails Presentations Open Sourced on GitHub</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/382194602/</link>
		<comments>http://jasonrudolph.com/blog/2008/09/03/grails-presentations-open-sourced-on-github/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 10:00:10 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Speaking]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=193</guid>
		<description><![CDATA[Want to help convince your peers to take Grails for a spin?  Are you looking to give a presentation to your dev team, your company, or perhaps a local user group?  If you&#8217;d rather not have to assemble a presentation from scratch, I&#8217;ve got good news for you: you can now grab the [...]]]></description>
			<content:encoded><![CDATA[<p>Want to help convince your peers to take Grails for a spin?  Are you looking to give a presentation to your dev team, your company, or perhaps a local user group?  If you&#8217;d rather not have to assemble a presentation from scratch, I&#8217;ve got good news for you: you can now grab the raw Keynote files and demo code for my <a href="http://github.com/jasonrudolph/" title="jasonrudolph's Profile &mdash; GitHub">Grails presentations on GitHub</a>.  (If you don&#8217;t have Keynote, no worries: the PDFs are available as well).  And it&#8217;s GitHub, so feel free to fork, customize, and spread the good word.  Remember: As long as there&#8217;s an IDE somewhere with an open struts-config file, there&#8217;s a developer in need of help.</p>

<ul>
<li><a href="http://github.com/jasonrudolph/getting-started-with-grails" title="jasonrudolph's getting-started-with-grails presentation at master &mdash; GitHub">Getting Started with Grails</a> (<a href="http://github.com/jasonrudolph/getting-started-with-grails/tree/master/ABSTRACT" title="ABSTRACT at master from jasonrudolph's getting-started-with-grails &mdash; GitHub">Abstract</a>) (<a href="http://github.com/jasonrudolph/getting-started-with-grails/tree/master%2Fgswg.pdf?raw=true" title="gswg.pdf at master from jasonrudolph's getting-started-with-grails &mdash; GitHub">PDF</a>) </li>
<li><a href="http://github.com/jasonrudolph/going-further-with-grails" title="jasonrudolph's going-further-with-grails presentation at master &mdash; GitHub">Going Further with Grails</a> (<a href="http://github.com/jasonrudolph/going-further-with-grails/tree/master/ABSTRACT" title="ABSTRACT at master from jasonrudolph's going-further-with-grails &mdash; GitHub">Abstract</a>) (<a href="http://github.com/jasonrudolph/going-further-with-grails/tree/master%2Fgfwg.pdf?raw=true" title="gfwg.pdf at master from jasonrudolph's going-further-with-grails &mdash; GitHub">PDF</a>)</li>
<li><a href="http://github.com/jasonrudolph/bending-gorm" title="jasonrudolph's bending-gorm presentation at master &mdash; GitHub">Bending GORM: 5-minute Techniques for Enterprise Integration</a> (<a href="http://github.com/jasonrudolph/bending-gorm/tree/master/ABSTRACT" title="ABSTRACT at master from jasonrudolph's bending-gorm &mdash; GitHub">Abstract</a>) (<a href="http://github.com/jasonrudolph/bending-gorm/tree/master%2Fbending-gorm.pdf?raw=true" title="bending-gorm.pdf at master from jasonrudolph's bending-gorm &mdash; GitHub">PDF</a>)</li>
</ul>

<p>If you&#8217;re not using Git yet, well, you should be.  Seriously.  But that&#8217;s a <a href="http://jasonrudolph.com/blog/2008/04/22/git-init-say-hello-to-agility/" title="jasonrudolph/blog - git init: Say Hello to Agility">different post altogether</a>.  In the meantime though, you can download any of the presentations as a zip file or tarball.  Just look for the &#8220;download&#8221; button on the GitHub page for each presentation.</p>

<p>Enjoy!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=fyRQkl"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=fyRQkl" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=7YavFL"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=7YavFL" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=5tcDil"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=5tcDil" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/382194602" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/09/03/grails-presentations-open-sourced-on-github/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F09%2F03%2Fgrails-presentations-open-sourced-on-github%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/09/03/grails-presentations-open-sourced-on-github/</feedburner:origLink></item>
		<item>
		<title>Testing Anti-Patterns: Invisible Code</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/367967922/</link>
		<comments>http://jasonrudolph.com/blog/2008/08/18/testing-anti-patterns-invisible-code/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 10:00:59 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Code Coverage]]></category>

		<category><![CDATA[Rails]]></category>

		<category><![CDATA[Testing]]></category>

		<category><![CDATA[Testing Anti-Patterns]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=191</guid>
		<description><![CDATA[As we&#8217;ve seen over the last several weeks, it&#8217;s remarkably easy for code to earn the badge of 100% test coverage without necessarily having a strong test suite.  In each of those examples, the coverage analysis tool performed its task flawlessly: it reported exactly which portions of our code were executed as a result [...]]]></description>
			<content:encoded><![CDATA[<p>As we&#8217;ve seen over the last several weeks, it&#8217;s remarkably easy for code to earn the badge of 100% <a href="http://jasonrudolph.com/blog/2008/06/10/a-brief-discussion-of-code-coverage-types/" title="jasonrudolph.com/blog - A Brief Discussion of Code Coverage Types">test coverage</a> <em>without</em> necessarily having a strong test suite.  In <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns">each of those examples</a>, the coverage analysis tool performed its task flawlessly: it reported exactly which portions of our code were executed as a result of running the tests.  The all-green coverage report showed us that the tests indeed touched all of our code, but it was up to us to acknowledge that simply touching a line of code doesn&#8217;t mean that you&#8217;ve exercised and verified that line of code in a meaningful way.  Some folks interpret this acknowledgement to mean that coverage analysis is meaningless, but that unfortunate conclusion overlooks the real benefit of a coverage report: it&#8217;s not about getting to 100% test coverage and assuming victory, it&#8217;s about highlighting any areas of our codebase that we&#8217;ve forgotten to test entirely.</p>

<p>As with any tool, to make effective use of coverage analysis, we need to understand its purpose, its capabilities, and its limitations.  In all of the previous examples, we looked at code that was already in the coverage report.  In other words, the coverage tool knew about this code and was able to watch the code and assess its coverage upon completion of the test suite.  But if we&#8217;re using the coverage report to help us find untested code, how do we deal with code that the coverage tool might not be aware of in the first place?</p>

<p>Let&#8217;s start with a sample Rails app that represents the beginnings of an online store.  The project currently contains the following files (as well as some others that I&#8217;ve omitted for the sake of brevity).</p>

<pre><code>[store]$ tree
...
|-- app
|   |-- controllers
|   |   |-- application.rb
|   |   `-- products_controller.rb
|   |-- helpers
|   |   |-- application_helper.rb
|   |   `-- products_helper.rb
|   |-- models
|   |   `-- product.rb
|   `-- views
|       |-- layouts
|       |   `-- products.html.erb
|       `-- products
|           |-- edit.html.erb
|           |-- index.html.erb
|           |-- new.html.erb
|           `-- show.html.erb
|-- config
|   |-- boot.rb
|   |-- database.yml
|   |-- environment.rb
|   |-- environments
|   |   ...
|   |-- initializers
|   |   |-- inflections.rb
|   |   |-- mime_types.rb
|   |   `-- new_rails_defaults.rb
|   `-- routes.rb
|-- db
|   |-- migrate
|   |   `-- 20080810220638_create_products.rb
|   `-- schema.rb
...
|-- lib
|   |-- product_ftp_importer.rb
|   `-- tasks
|   |   |-- data_load.rake
...
|-- test
|   |-- fixtures
|   |   `-- products.yml
|   |-- functional
|   |   `-- products_controller_test.rb
|   |-- integration
|   |-- test_helper.rb
|   `-- unit
|       `-- product_test.rb
...

37 directories, 63 files
</code></pre>

<p>After installing the <a href="http://agilewebdevelopment.com/plugins/rails_rcov" title="Plugins - Rails rcov - Agile Web Development">rails_rcov plugin</a>, we can easily produce a coverage report to see where we currently stand.</p>

<p><a href="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_1.png"><img src="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_1_thumb.png" alt="100% Test Coverage" title="100% Test Coverage - The Whole Story?" /></a></p>

<p>According to the coverage report, we&#8217;re not aware of any code that isn&#8217;t touched by at least one test.  But is that really the whole story?  The number of test-related files sure accounts for a small proportion of the overall app.  We can see that we have <code>test/unit/product_test.rb</code> and <code>test/functional/products_controller_test.rb</code>, but do those two files really encompass all the developer testing needed for this application?</p>

<h2>Out of Sight, Out of Mind?</h2>

<p>What about that mysterious file hanging out in the <code>lib</code> directory?</p>

<pre><code>[store]$ tree
...
|-- lib
|   |-- product_ftp_importer.rb
...
</code></pre>

<p>Just judging by the name of the file, that sure <em>sounds</em> like functionality that deserves testing, but for some reason it&#8217;s not listed in the coverage report.  And if we take another look at the test files listed above, there are no test files that obviously correlate to <code>product_ftp_importer.rb</code>.  So, how is it that we have 100% coverage?</p>

<p>In order for code to show up in a coverage report, we need to instruct the coverage tool to assess that file.  The approach for doing so tends to vary from tool to tool.  With <a href="http://eigenclass.org/hiki.rb?rcov" title="eigenclass - rcov: code coverage for Ruby">rcov</a>, we first have to tell it which files constitute our test suite (i.e., the files we want rcov to run).  But that alone is not sufficient; we also have to ensure that application files (i.e., the files whose test coverage we want to measure) get <em>loaded</em> as part of the test suite.  Adding this <code>require</code> statement anywhere in our test suite is enough to shed some light on the elusive code in <code>product_ftp_importer.rb</code>.</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1"><span class="kw3">require</span> <span class="kw4">File</span>.<span class="me1">expand_path</span><span class="br0">&#40;</span><span class="kw4">File</span>.<span class="me1">dirname</span><span class="br0">&#40;</span><span class="kw2">__FILE__</span><span class="br0">&#41;</span> + <span class="st0">&quot;/../lib/product_ftp_importer&quot;</span><span class="br0">&#41;</span></div></li></ol></div>

<p><br/></p>

<p><a href="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_2.png"><img src="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_2_thumb.png" alt="71.7% Test Coverage" title="71.7% Test Coverage - The Whole Story" /></a></p>

<p>It&#8217;s hard to feel good about 45 lines of untested FTP-processing voodoo, so how can we unearth this <strong>invisible code</strong> as soon as it tries to sneak its way into our app?</p>

<ol>
<li>Ensure that your coverage task knows where to find your tests, always place new tests where the coverage task can find them, and use a consistent naming scheme so that a simple file-matching pattern can distinguish test files from non-test files.</li>
<li>If you&#8217;re using rcov, add a quick script that will crawl your project tree and <code>require</code> all application files.  Adding individual <code>require</code> statements one-by-one is not a reasonable solution.  If someone&#8217;s not going to write the test in the first place, they&#8217;re sure as heck not gonna take the time to tell the coverage report about that misdeed.  So, walk the tree and require any Ruby file that you encounter in places where application code is likely to turn up.  At the very least, in a Rails app you should include all subdirectories under <code>app</code> (being aggressive enough to catch any <em>new</em> directories that might get added there) and the <code>lib</code> directory.</li>
</ol>

<p><strong>UPDATE (2008-08-21)</strong> At the <a href="http://ruby.meetup.com/3/calendar/7849526/" title="The Raleigh-area Ruby Brigade August Meeting (raleigh.rb) (Raleigh, NC)">&#8220;How to Fail with 100% Test Coverage&#8221; talk</a> earlier this week, a few folks asked if I&#8217;d provide an example script that would perform this task in a Rails app.  Adding this line to <code>test_helper.rb</code> should get you started.</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1"><span class="kw4">Dir</span><span class="br0">&#91;</span><span class="st0">&quot;app/**/*.rb&quot;</span>, <span class="st0">&quot;lib/**/*.rb&quot;</span><span class="br0">&#93;</span>.<span class="me1">each</span> <span class="br0">&#123;</span> |f| <span class="kw3">require</span> <span class="kw4">File</span>.<span class="me1">expand_path</span><span class="br0">&#40;</span>f<span class="br0">&#41;</span> <span class="br0">&#125;</span></div></li></ol></div>

<p><br/></p>

<h2>(Not So) Scenic View Ahead</h2>

<p>View templates have long been a favorite dumping ground for misplaced application logic.  This problem can often go undetected, because view templates fly under the radar of the coverage report.  Most developers know they should minimize the application logic included in the view, but when a deadline&#8217;s looming, the lure of throwing some code in the view &#8220;just this once&#8221; is often hard to resist.  For example, what&#8217;s so wrong with having the view decide whether to display a particular product in the list?</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">&lt;% <span class="kw1">for</span> product <span class="kw1">in</span> <span class="re1">@products</span> %&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &lt;% <span class="kw1">if</span> product.<span class="me1">quantity_in_stock</span> &gt; <span class="nu0">0</span> &amp;&amp; product.<span class="me1">quantity_in_stock</span> &gt; product.<span class="me1">pending_backorder_count</span> %&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &lt;!&#8211; display purchasable product here &#8211;&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &lt;!&#8211; &#8230; &#8211;&gt;</div></li>
<li class="li2"><div class="de2">&nbsp; &lt;% <span class="kw1">end</span> %&gt;</div></li>
<li class="li1"><div class="de1">&lt;% <span class="kw1">end</span> %&gt;</div></li></ol></div>

<p><br/></p>

<p>Well, how exactly will we verify that the view is indeed displaying the right products and suppressing the others?  We could manually test each scenario by visually inspecting the resulting UI, and that might be good enough for us to have confidence that the app is doing the right thing as of this moment.  But code has a life of its own, and it will grow and change over time, and we want automated tests to make sure that this page continues to display the correct data even after those inevitable changes.</p>

<p>So we decide to write tests to verify that we&#8217;re displaying only the right products.  And since this logic is inside our view template, we need to write tests that will render our view template and then dissect the resulting HTML to verify that it contains the products that should be present and that it does not contain the products that should not be present.  But in order to render the HTML, we need to invoke some controller action.  And because that lone <code>if</code> statement needs at least four different test cases to check the various conditions, we get the joy of doing all that setup and dissection at least four times.  That&#8217;s a big enough pain that it quickly becomes very tempting to let this bit of logic remain untested, remain out of sight of the coverage report, and remain &#8220;good enough.&#8221;</p>

<p>We can do better than that.  When something&#8217;s too hard to test, we should refactor it until it&#8217;s easy to test. [1]</p>

<p>We&#8217;re going to need this logic outside of the view anyway, so the sooner we get it into the model the better.  Sure, the view will only display those products that are available for purchase, but we need that logic for server-side validation as well.  Before we process an order, we need to make sure that we still have the product in stock.  If we leave the logic in the view as is, then we&#8217;ll be forced to duplicate that logic elsewhere inside our order-processing code.  There&#8217;s clearly no justification at all for leaving this logic in the view.  </p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">&lt;% <span class="kw1">for</span> product <span class="kw1">in</span> <span class="re1">@products</span> %&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &lt;% <span class="kw1">if</span> product.<span class="me1">available_for_purchase</span>? %&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &lt;!&#8211; display purchasable product here &#8211;&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &lt;!&#8211; &#8230; &#8211;&gt;</div></li>
<li class="li2"><div class="de2">&nbsp; &lt;% <span class="kw1">end</span> %&gt;</div></li>
<li class="li1"><div class="de1">&lt;% <span class="kw1">end</span> %&gt;</div></li></ol></div>

<p><br/></p>

<p>When we encapsulate this logic in the <code>Product</code> class itself, we can test that logic in <em>isolation</em>, without any dependencies on controllers, and without the need for fragile HTML-parsing to verify the result.  Once we perform this refactoring, unit testing the <code>#available_for_purchase?</code> method becomes trivial, <em>and</em> we can refer to that method wherever necessary without unnecessary duplication.</p>

<p>Better still, if we know that we only want to display the products that are available for purchase, we can ensure that our controller provides <em>only</em> those products to the view in the first place.  With this approach, our view then enjoys the pleasant simplicity of just displaying the list of products.</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">&lt;% <span class="kw1">for</span> product <span class="kw1">in</span> <span class="re1">@products</span> %&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &lt;!&#8211; display purchasable product here &#8211;&gt;</div></li>
<li class="li1"><div class="de1">&nbsp; &lt;!&#8211; &#8230; &#8211;&gt;</div></li>
<li class="li1"><div class="de1">&lt;% <span class="kw1">end</span> %&gt;</div></li></ol></div>

<p><br/></p>

<p>The coverage report isn&#8217;t going to alert us to business logic lurking in our view templates.  It&#8217;s up to us to keep our views from becoming <a href="http://www.youtube.com/watch?v=ku3QkWcPSEw" title="YouTube - RailsEnvy MVC Public Service Announcement #3 - Keeping Views Stupid">too smart for their own good</a>, and it&#8217;s up to peer code reviews to keep us honest.</p>

<h2>Raking for Buried Treasure</h2>

<p>While it&#8217;s tempting to let our views acquire too much business logic, there&#8217;s usually an obvious place to <em>move</em> that logic once we realize the error of our ways.  (In Rails, you&#8217;ll typically relocate that logic to a model class or to a helper, either of which are easily tested in isolation.)  But what about the other parts of our application where untested code tends to hide out and germinate?</p>

<p>Perhaps we have some code that only needs to run at application start-up.  In Rails, we&#8217;re talking about code in <code>environment.rb</code> or <code>config/initializers</code>.  In Grails, <code>BootStrap.groovy</code> is home to this logic.  In either case (or in most any other framework), we&#8217;re not likely to see those start-up &#8220;scripts&#8221; included in the coverage report, nor is there a natural and obvious place for testing any complex code that we may need to include in the start-up process.  We&#8217;re used to testing models and controllers and helpers and mailers, but where does this start-up logic fit into the mix?</p>

<p>Data migration suffers from a similar problem.  Rails migrations are great for creating and dropping tables, adding and removing columns, etc., but sometimes we need to do more than just alter the schema; sometimes we want to push <em>data</em> around as well.  Schema transformations are essentially declarative code, and really don&#8217;t warrant anything beyond visual verification of the results.  But when it comes time to migrate 10 million records from some legacy database into our hip new application, chances are we&#8217;re not just talking about simple declarations anymore.  What&#8217;s the worst that could happen though?  This code only has to run once.  And who wants to write a bunch of tests for code that we&#8217;re only gonna run once and then throw away?  And once again, there&#8217;s no obvious place for us to add tests for this kind of data conversion functionality in the first place.  Surely a simple Rake task will suffice.</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">namespace <span class="re3">:db</span> <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1">&nbsp; namespace <span class="re3">:load</span> <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; desc <span class="st0">&#8216;Load products from csv&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; task <span class="re3">:products</span> <span class="kw1">do</span></div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw3">require</span> <span class="st0">&#8216;csv&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw3">require</span> <span class="st0">&#8216;environment&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; CSV.<span class="kw3">open</span><span class="br0">&#40;</span><span class="st0">&quot;#{RAILS_ROOT}/db/input/csv/product-catalog/products.csv&quot;</span>, <span class="st0">&#8216;r&#8217;</span><span class="br0">&#41;</span>.<span class="me1">each_with_index</span> <span class="kw1">do</span> |row, idx|</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">next</span> <span class="kw1">if</span> row<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> == <span class="st0">&quot;Product&quot;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span> = Product.<span class="me1">find_or_create_by_name</span><span class="br0">&#40;</span>row<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span></div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">description</span> = e.<span class="me1">purpose</span> = row<span class="br0">&#91;</span><span class="nu0">5</span><span class="br0">&#93;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">sku</span> = row<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">price</span> = row<span class="br0">&#91;</span><span class="nu0">4</span><span class="br0">&#93;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">save</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; shipping_options = row<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>.<span class="kw3">split</span><span class="br0">&#40;</span><span class="st0">&quot;|&quot;</span><span class="br0">&#41;</span></div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; shipping_options.<span class="me1">each</span> <span class="kw1">do</span> |o|</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">shipping_options</span> &lt;&lt; ShippingOption.<span class="me1">find_by_name</span><span class="br0">&#40;</span>o<span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; vendors = row<span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>.<span class="kw3">split</span><span class="br0">&#40;</span><span class="st0">&quot;|&quot;</span><span class="br0">&#41;</span></div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; vendors.<span class="me1">each</span> <span class="kw1">do</span> |v|</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">p</span>.<span class="me1">vendors</span> &lt;&lt; Vendor.<span class="me1">find_by_number</span><span class="br0">&#40;</span>v<span class="br0">&#41;</span> <span class="kw1">unless</span> v.<span class="me1">downcase</span> == <span class="st0">&#8216;none&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">end</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">end</span></div></li>
<li class="li2"><div class="de2">&nbsp; <span class="kw1">end</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">end</span></div></li></ol></div>

<p><br/></p>

<p>Indeed, a <em>simple</em> Rake task will suffice, but that&#8217;s certainly not what we&#8217;re looking at above.  While we <em>could</em> write tests for this logic in its current state, doing so is unnecessarily difficult.  We&#8217;d be restricted to solely black box tests.  To test each individual decision point, we&#8217;re forced to also construct a new file holding the appropriate dataset, run the Rake task, and then inspect the state of the data in the database.  For <em>every</em> decision point.  </p>

<h2>Scripts Can Be Classy Too</h2>

<p>We shouldn&#8217;t have to also test the ability to read a file (i.e., line 7) just so that we can test the ability to populate a vendor based on a given vendor number (i.e., line 21).  For sure, we want one good end-to-end test to verify that all the cogs are working together correctly.  But if that&#8217;s our sole testing strategy, then we&#8217;ve made testing just painful enough that it probably won&#8217;t happen at all.  </p>

<p>Whether we&#8217;re talking about hard-to-test code in start-up scripts, hard-to-test code in migration scripts, or hard-to-test code hiding out in the handful of other custom scripts that an application tends to accumulate over time, the answer&#8217;s the same in each case.  Just because the coverage report doesn&#8217;t see this hidden code doesn&#8217;t mean that it&#8217;s not worth testing.  And just because our framework-of-choice might not provide a convention for testing this logic, that doesn&#8217;t mean that we should just punt.</p>

<p>When something&#8217;s too hard to test, we should refactor it until it&#8217;s easy to test.  </p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">namespace <span class="re3">:db</span> <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1">&nbsp; namespace <span class="re3">:load</span> <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; desc <span class="st0">&#8216;Load products from csv&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; task <span class="re3">:products</span> <span class="kw1">do</span></div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw3">require</span> <span class="st0">&#8216;environment&#8217;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; importer = ProductCsvImporter.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;#{RAILS_ROOT}/db/input/csv/product-catalog/products.csv&quot;</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; importer.<span class="me1">run</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">end</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">end</span></div></li>
<li class="li2"><div class="de2"><span class="kw1">end</span></div></li></ol></div>

<p><br/></p>

<p>In the case of this Rake task, and in each of the cases discussed above, by simply moving the logic out of the script and into a proper class (or module), the testing strategy goes from clumsy at best to downright obvious.  We no longer need to invoke the whole script in order to verify the particular unit of functionality that we want to test.  Instead, we test that functionality in isolation, and allow the script to resume its trivial role of merely calling our well-tested class.</p>

<h2>Use It Wisely</h2>

<p>In order to make effective use of coverage analysis, it&#8217;s important for us to understand what a coverage report is telling us <em>and</em> what it&#8217;s incapable of telling us.  Tools are imperfect, but we can adopt strategies to make sure we&#8217;re reaping the maximum benefit from the tools we choose to employ.  With good naming conventions and an agreed-upon application structure, we can easily configure an intelligent solution that allows the coverage tool to automatically pick up any new source files that we want included in the report.  With a commitment to testing all application logic - regardless of whether it&#8217;s needed in a model, a view, a script, etc. - we&#8217;ll extract the code that would otherwise be buried in a dark corner of our app.  We&#8217;ll benefit from the ability to test it in isolation, and we&#8217;ll allow the coverage tool to assess that code, giving us a more realistic and complete view of our codebase.</p>

<p>Invisible code is hidden technical debt, but the sooner you expose it, the sooner you can start to pay it down.</p>

<h2>Notes</h2>

<p>[1]  In past posts in this series, I&#8217;ve advocated test-driven development (TDD) as means for combatting the various testing anti-patterns. Invisible code is no exception.  While this post is geared more toward <em>uncovering</em> invisible code so that we can give it the testing it deserves, developing test-first is the best bet for <em>preventing</em> invisible code in the first place.</p>

<hr />

<p>This <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns">series</a> is taken from the <a href="http://blog.thinkrelevance.com/2008/5/23/how-to-fail-with-100-test-coverage" title="Relevance Blog : How To Fail With 100% Test Coverage">How To Fail With 100% Test Coverage</a> talk. Check the <a href="http://thinkrelevance.com/events" title="Relevance: Events">schedule</a> for a talk near you.</p>

<p>&#8211;</p>

<p><strong>Thanks</strong> to <a href="http://muness.blogspot.com/" title="Mundane Essays">Muness Alrubaie</a>, <a href="http://thinkrelevance.com/about/justin-gehtland" title="Relevance: Justin Gehtland">Justin Gehtland</a>, and <a href="http://gigavolt.net/blog/" title="Potential Differences">Greg Vaughn</a> for reading drafts of this post.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=KYLlIk"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=KYLlIk" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=L29AxK"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=L29AxK" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=zydDRk"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=zydDRk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/367967922" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/08/18/testing-anti-patterns-invisible-code/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F08%2F18%2Ftesting-anti-patterns-invisible-code%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/08/18/testing-anti-patterns-invisible-code/</feedburner:origLink></item>
		<item>
		<title>Testing Anti-Patterns: The Ugly Mirror</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/350365940/</link>
		<comments>http://jasonrudolph.com/blog/2008/07/30/testing-anti-patterns-the-ugly-mirror/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 10:30:42 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Testing]]></category>

		<category><![CDATA[Testing Anti-Patterns]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=190</guid>
		<description><![CDATA[When you&#8217;re able to write a test, nay, a spec, that not only verifies your code&#8217;s functionality, but also clearly communicates its intent, you&#8217;ve got a real win on your hands.  It&#8217;s a win when you&#8217;re first writing out your test cases as you&#8217;re TDD&#8217;ing your way to the solution.  It&#8217;s a win [...]]]></description>
			<content:encoded><![CDATA[<p>When you&#8217;re able to write a test, nay, a spec, that not only verifies your code&#8217;s functionality, but also clearly communicates its intent, you&#8217;ve got a real win on your hands.  It&#8217;s a win when you&#8217;re first writing out your test cases as you&#8217;re TDD&#8217;ing your way to the solution.  It&#8217;s a win to the person providing the peer review of your code.  It&#8217;s a win for you (again) when you have to revisit (and relearn) the code six weeks from now.  And it&#8217;s a win for the guy that has to touch this code yet again when you&#8217;re long gone.  [1]  But when you occasionally find yourself staring at a spec that looks exactly like the code under test, there&#8217;s surprisingly little <em>win</em> left to enjoy.  </p>

<p>Consider, for example, the following Ruby Struct tasked with building a friendly string representation of a user&#8217;s name and e-mail address.</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1">User = <span class="kw4">Struct</span>.<span class="me1">new</span><span class="br0">&#40;</span><span class="re3">:first_name</span>, <span class="re3">:last_name</span>, <span class="re3">:email</span><span class="br0">&#41;</span> <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">def</span> to_s</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="st0">&quot;#{last_name}, #{first_name} &lt;#{email}&gt;&quot;</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">end</span></div></li>
<li class="li2"><div class="de2"><span class="kw1">end</span></div></li></ol></div>

<p><br/></p>

<p>I ran across code similar to this example during a recent code review, and when I got to the corresponding test &#8230;</p>

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1"><span class="kw3">require</span> <span class="st0">&quot;test/unit&quot;</span></div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1"><span class="kw1">class</span> UserTest &lt; <span class="re2">Test::Unit::TestCase</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">def</span> test_to_s_includes_name_and_email</div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; user = User.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;John&quot;</span>, <span class="st0">&quot;Smith&quot;</span>, <span class="st0">&quot;jsmith@example.com&quot;</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; assert_equal <span class="st0">&quot;#{user.last_name}, #{user.first_name} &lt;#{user.email}&gt;&quot;</span>, user.<span class="me1">to_s</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">end</span> &nbsp;</div></li>
<li class="li1"><div class="de1"><span class="kw1">end</span></div></li></ol></div>

<p><br/></p>

<p>&#8230; I couldn&#8217;t help but feel like I was staring right back at the very code that was supposedly being tested.</p>

<p><a href="http://www.flickr.com/photos/98621082@N00/434585853/" title="Image courtesy of Pablo Baslini (flickr.com/98621082@N00)"><img src="http://jasonrudolph.com/blog/wp-content/uploads/20080729-ugly-mirror.jpg" alt="Ahhhhhhhh!" title="Image courtesy of Pablo Baslini (flickr.com/98621082@N00)" /></a> [2]</p>

<p>This <strong>ugly mirror</strong> of the production code leaves much to be desired.  Sure, thanks to the name of the test, we get the general idea that <code>to_s</code> will output some combination of the user&#8217;s name and e-mail address.  But when we look at the assertion on line 6, we&#8217;re forced to mentally reverse engineer the code in order to see through to the underlying requirement.  When it comes to quickly and clearly communicating the intent of the underlying code, this test falls far short of its potential.  As it&#8217;s implemented above, we&#8217;re probably better off reviewing the production code itself than bothering to look at the test at all.</p>

<p>Of course, it doesn&#8217;t have to be this way, but it&#8217;s not unusual to stumble across this kind of test.  In fact, it&#8217;s remarkably common to see this kind of test when the test is written <em>after</em> the production code is implemented.  It&#8217;s as if once a developer has written the code to perform a task, the guts of the code can&#8217;t be unseen, and as a consequence, the tests often end up reflecting those inner workings instead of the desired end result.</p>

<h2>No Mental Juggling Necessary</h2>

<p>On the other hand, when we&#8217;re developing test-first, we start out with the end-user requirements in mind, and it&#8217;s easy to make sure our tests communicate those requirements.</p>

<!-- TODO Verify this code looks right once it's posted on the blog -->

<div class="dean_ch" style="white-space: wrap;"><ol><li class="li1"><div class="de1"><span class="kw3">require</span> <span class="st0">&quot;test/unit&quot;</span></div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1"><span class="kw1">class</span> UserTest &lt; <span class="re2">Test::Unit::TestCase</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">def</span> test_to_s_includes_name_and_email</div></li>
<li class="li2"><div class="de2">&nbsp; &nbsp; user = User.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;John&quot;</span>, <span class="st0">&quot;Smith&quot;</span>, <span class="st0">&quot;jsmith@example.com&quot;</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; assert_equal <span class="st0">&quot;Smith, John &lt;jsmith@example.com&gt;&quot;</span>, user.<span class="me1">to_s</span></div></li>
<li class="li1"><div class="de1">&nbsp; <span class="kw1">end</span> &nbsp;</div></li>
<li class="li1"><div class="de1"><span class="kw1">end</span></div></li></ol></div>

<p><br/></p>

<p>When we improve the test to focus on the end result, we can look at the test and instantly see the requirements (and so can all the people that will live with our code long into the future).  Instead of reflecting the ingredients, the test now reflects the end product.  And this allows us to have greater confidence that our code is doing the right thing as well.</p>

<p>Whether it&#8217;s strings, dates, timestamps, or numeric calculations, <a href="http://blog.jayfields.com/2008/02/testing-expect-literals.html" title="Jay Fields' Thoughts: Testing: Expect literals">any time we can assert on a literal value, our test will be better off because of it</a>. [3]  The less logic that&#8217;s in our assertion, the fewer chances we have for that logic to be wrong, and the less logic we have to dig through to grok what&#8217;s being tested in the first place.</p>

<h2>Notes</h2>

<p>[1] And if you&#8217;re writing a library or framework, the tests may be a win for the users (or potential users) of your code as well.  My colleague <a href="http://muness.blogspot.com" title="Mundane Essays">Muness Alrubaie</a> is often seen skipping right over the docs and heading straight for the tests when he wants to check out some new open source code.  (After all, assuming they pass, the tests don&#8217;t lie.)  And if there are no tests, or if the tests fail to cleanly express the underlying functionality, you can rest assured that he won&#8217;t be looking at that project for long.</p>

<p>[2] Image courtesy of Pablo Baslini (<a href="http://www.flickr.com/98621082@N00" title="Flickr: Pablo Baslini's Photostream">flickr.com/98621082@N00</a>)</p>

<hr />

<p>This <a href="http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/" title="jasonrudolph.com/blog - Testing Anti-Patterns">series</a> is taken from the <a href="http://blog.thinkrelevance.com/2008/5/23/how-to-fail-with-100-test-coverage" title="Relevance Blog : How To Fail With 100% Test Coverage">How To Fail With 100% Test Coverage</a> talk. Check the <a href="http://thinkrelevance.com/events" title="Relevance: Events">schedule</a> for a talk near you.</p>

<p>&#8211;</p>

<p><strong>Thanks</strong> to <a href="http://gigavolt.net/blog/" title="Potential Differences">Greg Vaughn</a> for reading drafts of this post.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=vaIshj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=vaIshj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=NseFAJ"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=NseFAJ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=Po08xj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=Po08xj" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/350365940" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/07/30/testing-anti-patterns-the-ugly-mirror/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F07%2F30%2Ftesting-anti-patterns-the-ugly-mirror%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/07/30/testing-anti-patterns-the-ugly-mirror/</feedburner:origLink></item>
		<item>
		<title>Noteworthy Nonsense - July 25, 2008</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/345526812/</link>
		<comments>http://jasonrudolph.com/blog/2008/07/25/noteworthy-nonsense-july-25-2008/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 10:19:40 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[Git]]></category>

		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Groovy]]></category>

		<category><![CDATA[Noteworthy Nonsense]]></category>

		<category><![CDATA[Productivity]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=188</guid>
		<description><![CDATA[
Mixins, meet Groovy.  Groovy, say &#8220;Hello&#8221; to Mixins.
I kindly request that all job postings henceforth forgo the usual mumbo jumbo, replacing it instead with Paul Graham&#8217;s one metric to rule them all: the income-to-boringness ratio.
Snippets and scripts deserve first-class version control too.
If you haven&#8217;t disabled &#8220;new mail&#8221; notifications by the time you finish reading [...]]]></description>
			<content:encoded><![CDATA[<ul>
<li><p>Mixins, meet Groovy.  <a href="http://fisheye.codehaus.org/browse/groovy/trunk/groovy/groovy-core/src/test/groovy/lang/vm5/MixinTest.groovy?r=13045" title="FishEye: file groovy/trunk/groovy/groovy-core/src/test/groovy/lang/vm5/MixinTest.groovy">Groovy, say &#8220;Hello&#8221; to Mixins</a>.</p></li>
<li><p>I kindly request that all job postings henceforth forgo the usual mumbo jumbo, replacing it instead with Paul Graham&#8217;s one metric to rule them all: the <a href="http://www.paulgraham.com/prcmc.html" title="The Pooled-Risk Company Management Company">income-to-boringness ratio</a>.</p></li>
<li><p><a href="http://gist.github.com/gists" title="Gist &mdash; GitHub">Snippets and scripts</a> deserve <a href="http://github.com/blog/119-intro-to-gist-video" title="Intro to Gist Video &mdash; GitHub">first-class version control</a> too.</p></li>
<li><p>If you haven&#8217;t disabled &#8220;new mail&#8221; notifications by the time you finish reading this sentence, I&#8217;ll be forced to hold you personally <a href="http://www.43folders.com/2008/07/21/procrastination-ding" title="Chronic Procrastination and the Cost of the &quot;Ding!&quot; | 43 Folders">responsible for the world&#8217;s economic misfortunes</a>.  Pull, Folks. Pull.</p></li>
<li><p>Remember the <a href="http://jasonrudolph.com/blog/2006/06/20/hoisting-grails-to-your-legacy-db/" title="jasonrudolph.com/blog -- Hoisting Grails to Your Legacy DB">good ol&#8217; days of integrating Grails with a legacy database</a>?  You know, that long walk &#8230; uphill &#8230; in the snow &#8230; both ways.  <a href="http://grag.sourceforge.net/documentation.html" title="GRAG - The GRails Application Generator">Times sure have changed.</a></p></li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=CVatnj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=CVatnj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=dh9g1J"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=dh9g1J" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=T8JKmj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=T8JKmj" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/345526812" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/07/25/noteworthy-nonsense-july-25-2008/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F07%2F25%2Fnoteworthy-nonsense-july-25-2008%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/07/25/noteworthy-nonsense-july-25-2008/</feedburner:origLink></item>
		<item>
		<title>iPhone App Store Now Live</title>
		<link>http://feeds.feedburner.com/~r/jasonrudolph/~3/331702849/</link>
		<comments>http://jasonrudolph.com/blog/2008/07/10/iphone-app-store-now-live/#comments</comments>
		<pubDate>Thu, 10 Jul 2008 12:50:25 +0000</pubDate>
		<dc:creator>Jason Rudolph</dc:creator>
		
		<category><![CDATA[General]]></category>

		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://jasonrudolph.com/blog/?p=185</guid>
		<description><![CDATA[As of 8:55 EDT, there&#8217;s no direct link to the store just yet, but you can &#8220;hack&#8221; your way in.  Just search the iTunes store for the free iTunes Remote app named simply, &#8220;Remote&#8221;.  Click Get App, wait for it to download, and voil&#224;, there&#8217;s the App Store in the sidebar.  



Sweet!
]]></description>
			<content:encoded><![CDATA[<p>As of 8:55 EDT, there&#8217;s no <em>direct</em> link to the store just yet, but you can &#8220;hack&#8221; your way in.  Just search the iTunes store for the free iTunes Remote app named simply, &#8220;Remote&#8221;.  Click <em>Get App</em>, wait for it to download, and voil&agrave;, there&#8217;s the App Store in the sidebar.  </p>

<p><a href="http://jasonrudolph.com/blog/wp-content/uploads/20080710-app-store.png" title=""><img src="http://jasonrudolph.com/blog/wp-content/uploads/20080710-app-store-thumb.png" alt="20080710 App Store Thumb" /></a></p>

<p>Sweet!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/jasonrudolph?a=yu9Nvj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=yu9Nvj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=x8YMQJ"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=x8YMQJ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/jasonrudolph?a=wI3Ouj"><img src="http://feeds.feedburner.com/~f/jasonrudolph?i=wI3Ouj" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/331702849" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jasonrudolph.com/blog/2008/07/10/iphone-app-store-now-live/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=jasonrudolph&amp;itemurl=http%3A%2F%2Fjasonrudolph.com%2Fblog%2F2008%2F07%2F10%2Fiphone-app-store-now-live%2F</feedburner:awareness><feedburner:origLink>http://jasonrudolph.com/blog/2008/07/10/iphone-app-store-now-live/</feedburner:origLink></item>
	<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetFeedData?uri=jasonrudolph</feedburner:awareness></channel>
</rss>
