


<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CantRemembrances &#187; Learning</title>
	<atom:link href="http://blog.cantremember.com/category/learning/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.cantremember.com</link>
	<description>Memes of a technical vein discovered during CantRemember.com implementation</description>
	<lastBuildDate>Tue, 16 Feb 2010 06:36:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Upgrading your Rails Development Mac to Snow Leopard</title>
		<link>http://blog.cantremember.com/upgrading-your-rails-development-mac-to-snow-leopard/</link>
		<comments>http://blog.cantremember.com/upgrading-your-rails-development-mac-to-snow-leopard/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 06:17:12 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=196</guid>
		<description><![CDATA[Oh, there is such joy in the process of upgrading to Mac OS/X Snow Leopard for us developer folks. Me, I chose the in-place ugrade path &#8230; my co-worker, who chose the from-scratch path, was deprived of some of these pleasures. Then again, he had to reconstruct everything from scrach, so he had his own [...]]]></description>
			<content:encoded><![CDATA[<p>Oh, there is such <i>joy</i> in the process of upgrading to Mac OS/X Snow Leopard for us developer folks. Me, I chose the in-place ugrade path &#8230; my co-worker, who chose the from-scratch path, was deprived of some of these pleasures. Then again, he had to reconstruct everything from scrach, so he had his own barrel of monkeys to contend with.</p>
<p>Here&#8217;s all the bumps I ran into, pretty much in reverse order as I tried (unsuccessfully) to do the minimum amount of work possible :) I had to go pretty much this entire process twice &#8212; once on my work Macbook Pro, once on my identical home verison &#8212; so I figured I might as well document all of this crap down in the hope that it may reduce the shock and awe of future migrators. Of course you may run into a mess of fun issues not described here &#8230; And pardon me if the instructions aren&#8217;t <i>perfect</i>, because I&#8217;ve tried to boil a lot of this down to the <b>it-finally-worked</b> steps extracted from the frenzied back-and-forth of my real-time upgrade experience :)</p>
<h3>Backups</h3>
<p>Yes, this is just <i>common-sense developer stuff</i> (as is a number of the other obvious things that I call out in this post). </p>
<p>You&#8217;ll probably want to do a full <code>mysqldump</code> before upgrading. You can dump your <code>port install</code> and <code>gem list --local</code> listings up front as well, or wait &#8217;til you get to those respective steps below.</p>
<h3>MacPorts</h3>
<p>If you also chose the <b>MacPorts</b> library system, you&#8217;ll need to re-install it from scratch. You&#8217;ll need <b>X11</b> from the Snow Leopard from the OS/X install disks, and download the latest version of <a href="http://www.apple.com/macosx/developers/#xcode"><b>Xcode</b></a>. Follow the migration steps <a href="http://trac.macports.org/wiki/Migration">as outlined on their Wiki</a>; it does the trick. </p>
<p>Save off your <code>port install</code> list as a reference. Now, your MacPorts install will be completely toast, so that command won&#8217;t work until you re-install. No problem though &#8212; all of your packages will still be listed even after you upgrade. </p>
<p>The <code>port clean</code> step in the Wiki will crap out in the <code>http*</code> range, but that&#8217;s fine &#8230; you can probably skip that step anyway. Re-install your core packages and you&#8217;re good to go. I suggest installing <code>readline</code> if you haven&#8217;t, because it&#8217;s very useful in <code>irb</code> or any Ruby console.</p>
<h3>MySQL</h3>
<p>It was not necesary for me to build MySQL from source. Instead, I just installed <a href="http://dev.mysql.com/downloads/mysql/">the x86_64 version of <b>MySQL</b></a> &#8212; the latest was <code>mysql-5.1.42-osx10.6-x86_64.dmg</code> af the time of this writing.</p>
<p>If this is a 5.x verison upgrade for you as well, the install will just re-symlink <code>/usr/local/mysql</code>, so your old data will still be in your previous install dir. </p>
<p>I didn&#8217;t make <b>mysqldump</b>s before I did the upgrade <i>(handpalm)</i> so I had to copy over my <code>data/</code> files raw and hope that the new version would make friends with them. Initially I had problems with InnoDB.  It wasn&#8217;t showing up under <code>show engines;</code>, and when I tried to manually install the plug-in &#8212; per <a href="http://bugs.mysql.com/bug.php?id=48787">this bug report</a>, which explains the whole thing &#8212; it would fail on the  &#8216;Plugin initialization function&#8217;. Turns out you need to do <b>two</b> things when you bring over raw data:</p>
<ul>
<li>Whack your <code>/var/log/mysql/*binary*</code> / binary log files in order to get past <code>mysqld</code> startup errors.</li>
<li>Whack your <code>ib_logfile*</code> files too. Once you do that, there&#8217;s a good chance MySQL will regen them in recovery mode. Me, I had no choice (except rolling back with Time Machine). Miracle of miracles &#8230; <i>it works!</i></li>
</ul>
<p>Don&#8217;t try this at home kids.  Make your backups.  Note: here&#8217;s the correct link to the <a href="http://dev.mysql.com/doc/refman/5.1/en/adding-and-removing.html">manual page on InnoDB tablespace fun</a>.</p>
<h3>x86_64 ARCHFLAGS</h3>
<p>Snow Leopard is a lot more native 64-bit than previous OS/X versions, and when you do your manual builds &#038; makes, you may want to set the following <b>environment variable</b>:</p>
<pre><code>export ARCHFLAGS="-Os -arch x86_64 -fno-common"
</code></pre>
<p>You&#8217;ll see a set of similar (though mixed) recommendations in the blogs I reference below; this particular flagset worked for me.</p>
<h3>Ruby</h3>
<p>I built <b>Ruby 1.9</b> at work, and <b>1.8.7</b> on my personal machine.  Either path is fine, just <a href="http://www.ruby-lang.org/en/downloads/">pick up the latest source</a> of your choosing. <a href="http://cho.hapgoods.com/wordpress/?p=158">Chris Cruft&#8217;s blog post</a> goes into some of the details I&#8217;m describing here as well. Basically, the README boils down to:</p>
<pre><code>autoconf
./configure --with-readline-dir=/usr/local
make clean &#038;&#038; make
make install
</code></pre>
<p>Though there&#8217;s no reason in the world that you&#8217;d want to &#8212; it has been superceded &#8212; do <i>not</i> install <b>ruby 1.9.1p243</b>. If you do, you&#8217;ll never get the <code>mysql</code> gem to work. Or wait, or was it <code>mongrel</code>? Well, it was one or the other &#8230; just trust me, it&#8217;s <i>bad</i>.</p>
<h3>Gem</h3>
<p>I re-built <a href="http://rubyforge.org/frs/?group_id=126"><b>gem</b> from source</a> from scratch as well, just to be sure. Save off your <code>gem env</code> and <code>gem list --local</code> as a reference. And before you start installing gems, you&#8217;ll also probably want to make sure you&#8217;re fully up-to-date with <code>gem update --system</code>, though that&#8217;s probably redundant.</p>
<p>Uninstall and re-install all of your gems; if some won&#8217;t uninstall even though they&#8217;re listed, it may be an install path issue. Use <code>gem list -d GEMNAME</code> to find where your gem was installed, and then use <code>gem uninstall -i DIRNAME GEMNAME</code> to finish the job. </p>
<p>With the ARCHFLAGS in place, the vast majority of the native source gem builds will go smoothly, but there are some notable exceptions &#8230;</p>
<h3>The mysql Gem</h3>
<p>Uh huh, this is the one gem that gets me every time. And again, you <i>won&#8217;t</i> have needed to have built MySQL from source. </p>
<p>For starters, you may way want to glance over this very useful <a href="http://www.icoretech.org/2009/08/install-mysql-and-mysql-ruby-gem-on-snow-leopard-64-bit/">iCoreTech blog post</a> to see if it works for you. But if you run into a lot of issues like I did, you may need to do it in two steps:</p>
<h4>Fetch and Install the Gem</h4>
<p>At the time of this writing, either <b>mysql</b> gem version <code>2.7</code> or <code>2.8.1</code> will do the trick.</p>
<pre><code>gem fetch mysql --version VERSION
gem install mysql -- --with-mysql-dir=/usr/local --with-mysql-config=/usr/local/mysql/bin/mysql_config
gem unpack mysql
</code></pre>
<p>Sadly, it may fail, either during the build or when you try to test it. I was able to successfuly run the (included?) <code>test.rb</code> at my workplace, but as simple as that sounds, I swear <i>I don&#8217;t remember how I did it</i> ! The second time, at home, I only found the problems retroactively when I tried to get my Rails projects to boot. If you do find and run the <code>test.rb</code>, you&#8217;ll need to make sure that the standard MySQL <code>test</code> database exists. </p>
<p>Both times, one of the big blockers that I &#8212; and many other people &#8212; ran into was:</p>
<pre><code>NameError: uninitialized constant MysqlCompat::MysqlRes
</code></pre>
<p>If so, try this:</p>
<h4>Manually Re-build the Binary</h4>
<p>Go into <code>ext/mysql_api</code>, make sure your <b>ARCHFLAGS</b> are exported as described above, and &#8230;</p>
<pre><code>ruby extconf.rb --with-mysql-config=/usr/local/mysql/bin/mysql_config
make clean &#038;&#038; make
make install
</code></pre>
<p>Hopefully your newly built &#038; installed binaries will resolve the issue.</p>
<h3>Mongrel</h3>
<p>It took me a little effort to build <a href="http://mongrel.rubyforge.org/"><b>mongrel</b></a> on Ruby 1.9 with the x86_64 architecture. My memory is a little hazy &#8212; since my 1.8.7 build at home worked perfectly through standard <code>gem install</code> &#8212; but buried deep in this <a href="http://isitruby19.com/mongrel">Is It Ruby contributory blog post</a> are probably all the answers you&#8217;ll need.</p>
<p>Under Ruby 1.9, I <i>did</i> had to modify the source, which (to paraphrase) involved some global code replacements:</p>
<ul>
<li><code>RSTRING(foo)->len</code> with <code>RSTRING_LEN(foo)</code></li>
<li><code>RSTRING(foo)->ptr</code> with <code>RSTRING_PTR(foo)</code></il>
<li>change the one-line <code>case ... when</code> statements from Java-esque <code>:</code> delimiters to <code>then</code>&#8217;s.
</ul>
<p>And then the re-build:</p>
<pre><code>ruby extconf.rb install mongrel
make
make install
cd ../..
ruby setup.rb
gem build mongrel.gemspec
gem install mongrel.gem
</code></pre>
<h3>Conclusion</h3>
<p>And that&#8217;s as far as I had to go. <i>Whew!</i> I certainly hope that my post has been of some assistance to you (and with a minimum of unintended mis-direction). Of course, I learned everything the I reiterated above by searching the &#8216;net and plugging away. And there&#8217;s plenty of other folks who&#8217;ve gone down this insane path as well. Good luck, brave soul!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/upgrading-your-rails-development-mac-to-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Snake &#8216;n&#8217; Bacon in The DDOS Caper!</title>
		<link>http://blog.cantremember.com/snake-n-bacon-in-the-ddos-caper/</link>
		<comments>http://blog.cantremember.com/snake-n-bacon-in-the-ddos-caper/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 04:52:48 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[bot]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=168</guid>
		<description><![CDATA[


ah, come in!  we&#8217;re so glad you&#8217;ve come Snake &#8216;n&#8217; Bacon!
i&#8217;m crisp delicious bacon
sssss
glad you asked.  it seems there&#8217;s a group of hackers, and we want you to go in under-cover
i go great on a sandwich
sssss
&#8230;



When Twitter came back online yesterday afternoon after their networking attacks, I got a torrent of @cr_snake_bacon tweets. [...]]]></description>
			<content:encoded><![CDATA[<dl>
<dt>
<dd><i><br />
ah, come in!  we&#8217;re so glad you&#8217;ve come <a href="http://twitter.com/cr_snake_bacon">Snake &#8216;n&#8217; Bacon</a>!<br />
i&#8217;m crisp delicious bacon<br />
sssss</p>
<p>glad you asked.  it seems there&#8217;s a group of hackers, and we want you to go in under-cover<br />
i go great on a sandwich<br />
sssss</p>
<p>&#8230;<br />
</i></dd>
</dt>
</dl>
<p>When Twitter came back online yesterday afternoon after their <a href="http://news.cnet.com/8301-27080_3-10305200-245.html">networking attacks</a>, I got a torrent of <b>@cr_snake_bacon</b> tweets. Wasn&#8217;t sure why, but it seemed suspicious. Twitter&#8217;s API had flopped around for most of the day, so the logs were full of Exceptions and &#8230; <em>oops!</em> &#8230; re-connect attempts!</p>
<p>Of course I&#8217;d built the bots to re-tweet on an Exception. They&#8217;re all configured to wait 60 seconds, then try again. But of course until I fixed the configuration over night, they did <em>exactly what a bot would do</em> &#8230; <span style="color: #c00; font-style: italic;"><blink>conspicuous</blink></span> &#8230;</p>
<p>The service attacks on Twitter <a href="http://www.techcrunch.com/2009/08/07/geopolitical-attacks-on-twitter-intensified-almost-tenfold-last-night/">continued through today</a>, and I&#8217;m sure that the birdy techs are furiously building black ice fortresses in Scala even now. Again, I saw a burst this afternoon from <strong>all</strong> of my bots. <a href="http://twitter.com/cr_pokey">Pokey the Penguin</a>,<a href="http://twitter.com/cr_conet"> Conet Project</a>, and <a href="http://twitter.com/cr_wookie">Chewbacca</a> all had several things to say, all at once. Obviously I had fucked something else up, so I hurriedly checked the logs. And nope &#8230; actually, my change had worked &#8230; Twitter had just un-blocked my IP.</p>
<p><em>*whew*</em></p>
<p>I&#8217;m not exactly sure how many bots are out there &#8230; here&#8217;s a <a href="http://twitter.pbworks.com/Bots">nice wiki</a> being kept of them. But I can imagine I&#8217;m not the only one who made that try-again coding mis-calculation. What&#8217;s sweet is that it&#8217;s un-done now, and my toys can continue prattling on.</p>
<p>Thanks, guys. Sorry we looked like a vicious autonoma for a while there. Glad to be back.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/snake-n-bacon-in-the-ddos-caper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>random problem in your cloud-hosted app?  try a new instance!</title>
		<link>http://blog.cantremember.com/random-problem-in-your-cloud-hosted-app/</link>
		<comments>http://blog.cantremember.com/random-problem-in-your-cloud-hosted-app/#comments</comments>
		<pubDate>Wed, 27 May 2009 06:02:00 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[ops]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=152</guid>
		<description><![CDATA[chalk this one up under &#8216;Time Sunk&#8217;.
my Ambience for the Masses app is a Spring / Hibernate / JSP stack, with a couple of other sweet components.  i run it in on an AWS instance.  it&#8217;s been purring along just wonderfully for months now.  then, about ten days ago, it just stopped [...]]]></description>
			<content:encoded><![CDATA[<p>chalk this one up under &#8216;Time Sunk&#8217;.</p>
<p>my <a href="http://sleepbot.com/seb">Ambience for the Masses</a> app is a Spring / Hibernate / JSP stack, with a couple of other sweet components.  i run it in on an <a href="http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud">AWS</a> instance.  it&#8217;s been purring along just wonderfully for months now.  then, about ten days ago, it just <em>stopped working</em></p>
<p>normally Java apps don&#8217;t die without throwing some sort of Exception.  but that&#8217;s just what was happening.  so i stripped out various components &#8212; thank you, <a href="http://www.martinfowler.com/articles/injection.html">Dependency Injection</a> pattern! &#8212; and found that it would sometimes die instantly (if i was lucky) but usually it took a couple of hours.  i don&#8217;t have a lot of free time to track down random intermittent bullshit like this, so it took me about a week to boil it down</p>
<p>it was somewhere in the <a href="http://sleepbot.com/ambience/broadcast/map.html">Current Listener Map</a> &#8212; my Shoutcast-listener-tracking geo-positioning statistics-gathering data sculpture back-end engine.  i hear that the kids call them things <em>mash-ups</em>.  the geo-lookup APIs were the most delicate part, and it seemed to work with them omitted.  that red herring aside, it turned out to be the IP address resolution</p>
<pre><code>try {
	if (getLog().isTraceEnabled())
		getLog().trace("lookup : " + hostname);

	// oh, lookup!
	<strong>InetAddress ipAddress = InetAddress.getByName(hostname);</strong>

	//	NOTE: this is where it went bad on the AWS image
	//		*sigh*

	<strong>return ipAddress.getHostAddress();</strong>
}
<strong>catch (UnknownHostException e) { }</strong>
catch (Exception e) {
	getLog().warn("failed to lookup " + hostname, e);
}</code></pre>
<p>that block was just a couple of lines until i&#8217;d added all the logging and desperate Exception handling.  the app launches a lot of threads, so tracking down the issue was annoying &#8230; but eventually there it was in the traces.  the stack just terminated when the app tried to <code>getHostAddress</code> (not during <code>getByName</code> though &#8230; must be a lazy-loading thing)</p>
<p>so i nearly had it all tracked down to that.  then Tomcat <em>inexplicably</em> became unable to find basic JARs in <code>/usr/share/java</code> &#8212; i was using Fedora 8&#8217;s RPM version vs. raw Apache, and it&#8217;s organized real funny-like</p>
<p>so i threw up my hands and started up a fresh instance of my webapp AWS image.  i&#8217;d rebooted the existing one, and that hadn&#8217;t helped at all.  of course, the issue <strong>magically disappeared</strong> on the new instance.  did anyone see that coming from a distance?  ya probably did.  cuz it&#8217;s ironic.  and it&#8217;s the title line of the damn blog post</p>
<p>the hostname resoultion is surely a low-level OS thing.  both Linux JavaSE 6 and IcedTea 7 just shat the bed when they got to that point, unlikely unless they both leveraged the same lib call.  something must have gone wonk in the virtualization, and apparently a key part of the solution was running it inside of a different farm.  i wasted a helluva lot of time to find that out</p>
<p><strong>lesson !!</strong>  if weird inexplicable freaky-ass things start happening to your cloud-hosted app, load it up on a new VM <em>earlier than later</em>.  i&#8217;d taken a late-stage backup of the failed instance and assumed it would be corrupted with the Mystery Bug (read as: a waste of time to attempt). but oh no, it worked just great :) .  next time it&#8217;ll be a cinch to just bundle the instance up, image it, and use it to launch a new one</p>
<p>and ultimately &#8230; <em>it wasn&#8217;t a bug in my code !!!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/random-problem-in-your-cloud-hosted-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>being too rapid on the things that matter</title>
		<link>http://blog.cantremember.com/being-too-rapid-on-the-things-that-matter/</link>
		<comments>http://blog.cantremember.com/being-too-rapid-on-the-things-that-matter/#comments</comments>
		<pubDate>Fri, 08 May 2009 05:04:51 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[mentor]]></category>
		<category><![CDATA[startup]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=144</guid>
		<description><![CDATA[it took me a while to come up with the title for this post.  and it&#8217;s and Opinion Piece, not Techincal &#8230; so you&#8217;ll see why &#8230;
i&#8217;m working for a new company now, and they&#8217;re rocking it for RoR apps on the iPhone. sounds like a good place to be. one of the many [...]]]></description>
			<content:encoded><![CDATA[<p>it took me a while to come up with the title for this post.  and it&#8217;s and Opinion Piece, not Techincal &#8230; so you&#8217;ll see why &#8230;</p>
<p>i&#8217;m working for a new company now, and they&#8217;re rocking it for RoR apps on the iPhone. sounds like a good place to be. one of the many reasons why this position works for me is because these guys are all about GTD and getting it out there. lean &#8216;n&#8217; mean</p>
<p>whereas i&#8217;ve become very used to a holistic detail-orented, wisened test-backed process. great for Enterprise, but not so much for the reckless streets of Startup 3.0 .  so i&#8217;m in a learning process. i&#8217;ve turned around some good stuff quickly, and it&#8217;s very satisfying</p>
<p>but i&#8217;ve screwed the pooch twice since i&#8217;ve been there.  it&#8217;s totally a judgement call thing &#8212; i&#8217;m shooting <i>too</i> fast from the hip, and don&#8217;t feel like i really grasp the balance here &#8230;</p>
<p>first project i worked on was related to account management. they wanted a quick turn-around, i gave it a shot, had the whole thing backed with solid testing, and ready for on-time deployment with a smile. and in trying to keep track of all the new system permutations &#8212; i&#8217;d been there 2 weeks or so &#8212; i forgot one basic thing, and forgot to test for another. a nice little Perfect Storm. one emergency 1am database rollback later, we had a load of pissed customers and a helluva lot of explaining to do</p>
<p>so, then this past week, i went in to fix a minor rounding issue bug.  those can be touchy.  the <b>right</b> way to do it is with <a href="http://www.ruby-doc.org/stdlib/libdoc/bigdecimal/rdoc/classes/BigDecimal.html"><code>BigDecimal</code></a>. yep, i&#8217;ve done that in Java too with <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html"><code>BigDecimal</code></a>.  overall, it&#8217;s somewhat ponderous, detail-oriented, and can easily be polluted with <code>Float</code>s and the like.  so i&#8217;d taken a shortcut, realizing that the low-level C impl was doing String conversion without the rounding issue.  so i took the low-hanging fruit:</p>
<pre><code>total.to_s.to_i</code></pre>
<p><i>awesome !!1!</i>. well, that is until you get into the 100-of-trillions area, otherwise shown as <code>1.0e+14</code>. guess what happens when you parse that into a Fixnum? no database rollback this time, but Da Boss had to spend <i>days</i> sorting out the visceral impact of ridiculous sums of bogus exploit money pouring into our RPG</p>
<p>security, privacy and account management.  payment calculations.  not the sort of things to take shortcuts on.  yet, if you&#8217;re embracing a culture that wants it done quickly and with minimum impact, it&#8217;s a risk you might be willing to take.  it&#8217;s not like i didn&#8217;t have test scripts &#8230; i just forgot to head into scientific notation territory.  just like i forgot to check for the implication of null password acceptance <em>( long story there, special account cases, etc. )</em></p>
<p>i&#8217;m putting these things up here for my fellow developers to laugh at. &nbsp; &#8220;I mean, c&#8217;mon. All that&#8217;s totally obvious stuff.&#8221; &nbsp; &#8220;I&#8217;d never miss that, that&#8217;s sophmore shit.&#8221; &nbsp; good, get it out of your system, laughing boy</p>
<p>but believe me, when you&#8217;re on the other end of it, and had been in the middle of it and all full of all the other things that you needed to keep track of at that time, heh, well, that&#8217;s when you&#8217;ll really need to keep yerself laughing :)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/being-too-rapid-on-the-things-that-matter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When Broken Toys Impact your Friends</title>
		<link>http://blog.cantremember.com/when-broken-toys-impact-your-friends/</link>
		<comments>http://blog.cantremember.com/when-broken-toys-impact-your-friends/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 22:21:07 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[bot]]></category>
		<category><![CDATA[mentor]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=114</guid>
		<description><![CDATA[This sure was an interesting morning!  I woke up to find that I&#8217;d unintentionally sent direct messages to all of the followers on my personal Twitter account.  And I&#8217;d sent them out at 1a PST, which means that anyone who (a) uses SMS capabilities, and (b) has some text message notification sound set [...]]]></description>
			<content:encoded><![CDATA[<p>This sure was an interesting morning!  I woke up to find that I&#8217;d unintentionally sent direct messages to <strong>all</strong> of the followers on my <a href="http://twitter.com/sleepbotzz">personal Twitter account</a>.  And I&#8217;d sent them out at 1a PST, which means that anyone who <em>(a)</em> uses SMS capabilities, and<em> (b)</em> has some text message notification sound set up would have been rudely interrupted in the middle of the night.</p>
<p>Fortunately, I haven&#8217;t lost any followers (yet).  But this was a perfect case of how mixing business with pleasure can have unintended consequences.</p>
<h3>What Have I Learned</h3>
<p>Or rather, what have I <em>re-learned</em> &#8230;</p>
<dl>
<dt><strong>Soft-disable features in Production at Launch Time</strong></dt>
<dd>&nbsp;<br />
My Twitter engines are built with both an <code>:enable_tweet</code> and <code>:enable_greeting</code> config setting.  In the git repo, they&#8217;re both <code>true</code>.  When I did my local testing, I&#8217;d disabled them correctly.  When I launched in Production, I neglected to make the quick-and-dirty changes; after all, everything worked great.  And once started, my scripts correctly responded to the no-initial-state condition, and greeted <em>everybody</em>.</p>
<p>Launch preparation is critical, even for little projects.  The start-up mentality is to move fast and lean, but there&#8217;s such as thing as too fast, and probably as too lean too.  Gradual uptake migration is a wise strategy even for the &#8216;little things&#8217;.
</dd>
<dt><strong>Mock and Integration Testing Only Gets You So Far</strong></dt>
<dd>&nbsp;<br />
I used <a href="http://rspec.info">rspec</a> to mock out the full capabilities of the engine.  Found some real-world issues, resolved them.  I also wrote some core <a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">integration tests</a>, ran them locally.  Immediate failures. I had mocked documented features that <em>didn&#8217;t actually exist</em>.  Fixed, re-mocked, re-tested, fixed again, <em>etc</em> .</p>
<p>Another great reminder that you can only mock something you trust, and how can you trust something you haven&#8217;t actually run under integration conditions to start with!  Re-tested integration, and everything passed with flying colors.  Sure, the features worked great now!  And when I launched them, they did exactly what I asked.</p>
<p>So, as if we haven&#8217;t heard it enough times, be careful what you ask for!
</dd>
</dl>
<p>All of this is familiar to anyone who has made a mistake in the software industry.  It&#8217;s not like I haven&#8217;t successfully executed dozens of critical launches in the past, and most with virtually no issues at all.  But what&#8217;s interesting is what happens when these mistakes happen in a public forum, and whom you expose them to &#8212; say, <em>your friends</em> :)</p>
<p>And who can say when two ounces of caution is more deserving than one &#8230; without the benefit of hindsight.</p>
<p>Just ask anyone who has a stringent backup policy how much time &#038; effort they invest to avoid an event that may never actually happen.  That stringency usually comes from that one unforgettable experience, and from there is born an extra layer of caution, and an additional time-sink (eg. mock &#038; integration testing)</p>
<p>Heh.  <a href="http://en.wikipedia.org/wiki/Keep_it_simple_stupid">KISS</a>.  So, what exactly is simple?  <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>.  Isn&#8217;t that supposed to be a time-saver?  Well, it depends on what you&#8217;re not trying to repeat.  Strange how these cuddly and liberating acronyms can have more than one interpretation.</p>
<p>Experience taints everything.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/when-broken-toys-impact-your-friends/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter4R shifts RSpec onto my Front Burner</title>
		<link>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/</link>
		<comments>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 09:00:33 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=94</guid>
		<description><![CDATA[As usual, my day did not pan out as expected.  But, also as usual, I learned a lot!
Coming Up To Speed on Rspec
So, learning rspec has been on my list for a while.  I finally got around to it.  Nice framework.  I am familiar with EasyMock, and am aware of JMock. [...]]]></description>
			<content:encoded><![CDATA[<p>As usual, my day did not pan out as expected.  But, also as usual, I learned a lot!</p>
<h3>Coming Up To Speed on Rspec</h3>
<p>So, learning <a href="http://rspec.info/"><strong>rspec</strong></a> has been on my list for a while.  I finally got around to it.  Nice framework.  I am familiar with <a href="http://www.easymock.org/">EasyMock</a>, and am aware of <a href="http://www.jmock.org/">JMock</a>.  I never had an opportunity to get into <a href="http://code.google.com/p/mockito/">Mockito</a>, but I&#8217;d give it a glance next time I put on my Java hat.</p>
<p>There is some decent documentation on it out there.  I found these links particularly helpful:</p>
<ul>
<li>The <a href="http://rspec.info/documentation/">formal documentation</a>.</li>
<li>David Chelimsky&#8217;s <a href="http://blog.davidchelimsky.net/articles/2007/05/14/an-introduction-to-rspec-part-i">from-the-ground-up description</a></li>
<li>rspec.info&#8217;s drill-down into <a href="http://rspec.info/documentation/mocks/">Mocks and Stubs</a></li>
<li>Luke Redpath&#8217;s cross-over into <a href="http://www.lukeredpath.co.uk/blog/developing-a-rails-model-using-bdd-and-rspec-part-1.html">usage under Rails</a></li>
</ul>
<p>During my ramping-up, I took the <a href="http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/">usual meta-approach</a> of creating a test suite &#8212; and <em>yaaay</em>, that&#8217;s what <code>rspec</code> is meant for! &#8212; which I then used to test out its own range of capabilities.  The <a href="http://rspec.rubyforge.org/rspec/1.1.12/">Modules in the rdoc</a> which I&#8217;ve found to provide the most value are:</p>
<ul>
<li><strong>Spec::Expectations::ObjectExpectations</strong> for conditionals (eg. <code>should</code> &#038; <code>should_not</code>)</li>
<li><strong>Spec::Matchers</strong> for expectations (eg. <code>equal(<em>value</em>)</code>, <code>be_a(<em>class</em>)</code>, <code>respond_to(<em>method_sym</em>)</code>, <code>raise_error</code>)</li>
<li><strong>Spec::Mocks::Methods</strong> for mock method definition (eg. <code>should_receive(<em>method_sym</em>)</code>)</li>
<li><strong>Spec::Mocks::MessageExpectation</strong> for mock behaviour (eg. <code>with(<em>*args</em>)</code>, <code>once</code>, <code>exactly(<em>n</em>).times</code>, <code>any_number_of_times</code>)</li>
<li><strong>Spec::Mocks::ArgumentConstraints</strong> for mock arguments (eg. <code>an_instance_of(<em>class</em>)</code>, <code>anything</code>)</li>
<li><strong>Spec::Mocks::BaseExpectation</strong> for mock responses (eg. <code>and_return(<em>value</em>)</code>, <code>and_yield(<em>&#038;block</em>)</code>)</li>
</ul>
<p>I won&#8217;t got into the deep details, but here are some examples of conditionals and expectations that I paraphrased into my meta-test:</p>
<div class="pre_wrap">
<pre><code>	specify "knowledge of nil" do
		''.should_not be_nil
	end

	specify "numeric calculations" do
		(355.0 / 113).should be_close(Math::PI, 0.1)
	end

	specify "changes made by a closure" do
		array = []
		lambda {
			array << :a
		}.should change(array, :size)
	end

	specify "equality" do
		5.should eql 5
		5.should equal 5
		[:a].should_not equal [:a]
	end

	specify "raising of errors" do
		#	always construct fresh!!!
		#		otherwise it won't be re-wrappable
		def raiser(s=nil)
			lambda { raise(RuntimeError, s) if s }
		end

		raiser('x').should raise_error
		raiser('y').should raise_error(RuntimeError, 'y')
	end

	specify "closure satisfaction" do
		5.should satisfy {|n| (4..6).include?(n) }
	end

	specify "what lists do" do
		[].should respond_to(:each, :find, :size)
	end</code></code></pre>
</div>
<p>And here&#8217;s a little bit of silly mocking:</p>
<div class="pre_wrap">
<pre><code>	def expect_raise(type=Spec::Mocks::MockExpectationError, &#038;block)
		abort 'block must be provided' unless block_given?
		block.should raise_error(type)
	end

	specify "the basics" do
		@mock.should_receive :hello
		@mock.should_not_receive :goodbye

		@mock.hello
		expect_raise { @mock.stay }
		expect_raise { @mock.goodbye }
	end

	specify "how many times, and with what" do
		@mock.should_receive(:one).once.with(1)
		@mock.one 1

		@mock.should_receive(:string).exactly(1).times.with(an_instance_of(String))
		@mock.string 'a string'

		@mock.should_receive(:anything).exactly(3).times.with(any_args())
		@mock.anything
		@mock.anything :again
		@mock.anything :third, 'time'

		@mock.should_receive(:array_ish).with(duck_type(:each, :find, :size))
		@mock.array_ish [:item]
	end

	specify "what i return, raise or throw" do
		@mock.should_receive(:get_one).and_return(1)
		@mock.should_receive(:put_one).with(1)
		@mock.put_one @mock.get_one

		@mock.should_receive(:increment).any_number_of_times.with(instance_of(Fixnum)).and_return {|i| i + 1 }
		@mock.increment(1).should equal(2)

		@mock.should_receive(:raises_string).and_raise('something runtime')
		expect_raise(RuntimeError) { @mock.raises_string }

		@mock.should_receive(:pitch).and_throw(:ball)
		lambda { @mock.pitch }.should throw_symbol(:ball)
	end

	specify "yielding in a complex fashion" do
		@mock.should_receive(:gimmee).exactly(3).times.and_yield(:x)

		holder = []
		@mock.gimmee {|value| holder << value }
		holder.should eql([:x])
		2.times { @mock.gimmee {|value| holder << value } }
		holder.should eql([:x, :x, :x])
	end

	specify "validation via closure" do
		(@mock.should_receive(:threely) do |value|
			value.to_s.size.should eql(3)
		end).exactly(3).times

		@mock.threely 'x' * 3
		@mock.threely :key
		@mock.threely 333
	end</code></code></pre>
</div>
<p>These are just ways I thought of to exercise the width and breadth of the library.  Very nice.  I hope that these are useful examples for people new to this gem.</p>
<p>I recommend the other references from above for filling in the missing details.  Once you have a <code>context / specify</code> or a <code>describe / it</code> specification set up, you&#8217;ll be good to go.  There&#8217;s much more to the library &#8212; Stories, for instance &#8212; but that&#8217;s <a href="http://blog.emson.co.uk/2008/06/understanding-rspec-stories-a-tutorial/">for another day</a>.</p>
<h3>An Informative Walk through Twitter4R</h3>
<p>No, I didn&#8217;t really <em>want</em> to spend time learning <code>rspec</code> &#8212; I mean heck, I&#8217;m busy &#8212; but I had a personal need to expand the <a href="http://twitter4r.rubyforge.org/"><strong>Twitter4R</strong></a> gem.  Specifically, I wanted to add on some <a href="http://apiwiki.twitter.com/Search+API+Documentation">Twitter search</a> features, and I was very impressed with how this library has been built.  Contribution-wise, the final step that <a href="http://susanpotter.net/">Susan Potter</a> recommends is to craft up some rspec tests.</p>
<p>Of course, mock testing is only as good as the framework you&#8217;re built upon.  The assumption is that <code>Net::HTTP</code> is going to do it&#8217;s job, so mock it up and you can even test your Twitter features offline.  When I built <a href="http://wiki.cantremember.com/Bitly4R"><strong>Bitly4R</strong></a> (given that name, my thinking has clearly been <em>influenced</em>), I did everything as full-on functional tests.  It was easy; <a href="http://bit.ly/">bit.ly</a> has both <code>shorten</code> and <code>expand</code> commands, so I could reverse-test real values without having any fixed expectations.</p>
<p>However, Twitter is <a href="http://twitter.com/public_timeline">live</a> and user-generated, so who knows <em>what</em> you&#8217;ll find.  Mocking covers that for you.  And of course not having to hit the service itself shortest testing time dramatically.</p>
<p>Here&#8217;s one of my tests, again foreshortened:</p>
<div class="pre_wrap">
<pre><code>	before(:each) do
		Twitter::Client.send :public, :create_http_get_request

		@client = Twitter::Client.new
		@client_clone = Twitter::Client.new
	end

	it "produces a querystring with all the crazy stuff Twitter imagined" do
		the_params = nil

		@client.should_receive(:create_http_get_request).and_return {|uri, params|
			the_params = params
			@client_clone.create_http_get_request(uri, params)
		}
		@client.should_receive(:http_connect).and_return Net::HTTPNotFound.mock(:code => '404')

		#	pass through a few we can pick back out
		#	also, side-effect ... nil on invalid response
		@client.search('query_value', :rpp => 3).should be_nil

		the_params.should_not be_nil
		the_params[:q].should eql('query_value')
		the_params[:rpp].should eql(3)
	end</code></code></pre>
</div>
<p>Plus a little mocking of <code>Net::HTTPResponse</code>:</p>
<div class="pre_wrap">
<pre><code>class Net::HTTPResponse
	def self.mock(ops={})
		#	defaults
		ops = {
			:http_version => '1.1',
			:code => '200',
			:message => 'OK',
			:body => nil,
		}.merge(ops || {})

		#	construct
		###clazz = CODE_TO_OBJ[ops[:code]]
		clazz = self
		response = clazz.new(ops[:http_version], ops[:code], ops[:message])

		#	inject
		ops.each do |k, v|
			response.instance_variable_set "@#{k}".to_sym, v
		end

		#	mockulate
		response.instance_eval %q{
			def body; @body; end
		}

		response
	end
end</code></code></pre>
</div>
<p>Nothing like having some good inspiration to get you thinking about maintainability.  I&#8217;m a not a strong adherent to any of the <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> or <a href="http://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a> denominations, but testability itself is close to my heart.  Just ask the folks who&#8217;ll be looking at the micro-assertion Module that I wrote for my <a href="http://www.facebook.com/jobs_puzzles/">Facebook Puzzle</a> submissions (which work locally under test conditions but fail <em>miserably</em> once thrown over their wall).  Then again, I won&#8217;t need to write that (and test that) from scratch again.</p>
<p>So, back to talking glowingly about the <code>Twitter4R</code> architecture.  Yes, I used <strong>that</strong> word.  Yet regardless of that term&#8217;s heavyweightedness, it&#8217;s simply the result of carefully thinking out the formalization of a complex design.  And once a non-author delves into extending an existing implementation, that impl&#8217;s demeanor becomes readily clear :)</p>
<p>Some of the interesting things I saw:</p>
<ul>
<li>An inner <code>bless</code>-ish strategy, to inject the <code>Twitter::Client</code> into instanciated result classes.  I&#8217;ve seen blessing as an OO-Perl-ism, for self-ication, and that metaphor carries over very nicely to this context.</li>
<li>Generous use of blocks / lambdas / closures in methods, for contextual iteration (eg. iterate through each <code>Twitter::Message</code> in a <code>timeline</code> response).  Unnecessary, but an excellent convenience for a language that offers that optional capability in a very disposable fashion (from the caller&#8217;s perspective).</li>
<li>Retroactive sub-object population after construction.  <code>Twitter4R</code> relies upon the <a href="http://json.rubyforge.org/">json</a> gem, which deals primarily in Hashes.  Post-injection, the library itereates through Arrays of Hashes and transforms them into suitable <code>Twiltter::User</code> containers, etc.  A great place to put such logic in the construction chain, and it doesn&#8217;t take long to get really tired of Hash hierarchies.</li>
</ul>
<p>Good stuff, and learning with in a Ruby-centric mindset was invaluable for me.  We all have to start somewhere, eh.</p>
<h3>The Acute Long-Term Pain of Staticness</h3>
<p>There was one issue that I ran into; <em>static configuration</em>.  During my years of using the <a href="http://www.springsource.org/">Spring Framework</a>, my <a href="http://en.wikipedia.org/wiki/Inversion_of_Control">IOC</a>-addled brain started thinking of everything in terms of instances &#8212; Factory Beans, POJOs, Observers &#038; Listeners, Chain-of-Responsibility wrappers.  Static configuration is a common metaphor, and in this case, there&#8217;s a static <code>Twitter::Config</code> instance.  Convenient and centralized.  Makes perfect sense.</p>
<p>I mean, the fact that it was a configurable library <em>at all</em> was awesome.  I was able to easily set up a <code>Twitter::Client</code> to reference <a href="http://search.twitter.com">search.twitter.com</a>.  However, of course as soon as I did that, I whacked the ability for clients to talk to <code>twitter.com</code> in the process.  <em>Oops!</em></p>
<p>On GPs, I refused to modify the original code.  And I wanted to make sure that my superficial tweaks to the library would be thread-safe &#8212; temporarily swaping out the global <code>Twitter::Config</code> in mid-operation would be an issue.  Using <code>Mutex.synchronize</code> seemed like the perfect choice.  After finding that the same thread can&#8217;t lock a <code>Mutex</code> instance twice &#8212; grr!, that&#8217;s a great trick if you can work it &#8212; I overrode the one method that cared the most about <code>@@config</code>:</p>
<div class="pre_wrap">
<pre><code>	@@config_mutex = Mutex.new
	def configuration_mutex
		@@config_mutex
	end

	alias :raw_http_connect :http_connect
	def <strong>http_connect</strong>(*args, &#038;block)
		ops = (Hash === args.last) ? args.pop : {}

		result = nil
		self.configuration_mutex.synchronize do
			ops[:call_before].call if ops[:call_before]
			result = raw_http_connect *args, &#038;block
			ops[:call_after].call if ops[:call_after]
		end

		result
	end

	#
	#	...
	#

	@@SEARCH_CONNECT_HOOKS = {
		:call_before => lambda { self.configure_apply(:search) },
		:call_after => lambda { self.configure_apply(:default) },
	}

	#
	#	...
	#

	#	broken out of closure for mocking
	req = create_http_get_request(uri, params)
	response = http_connect(@@SEARCH_CONNECT_HOOKS) {|conn|	req }
	return nil unless Net::HTTPOK === response

	model = bless_model(Twitter::Search.unmarshal(response.body))</code></code></pre>
</div>
<p>It works like a charm.  Please, everyone just line up to tell me how I could have done it better.  And I don&#8217;t mean <em>quicker</em> or <em>cheaper</em>, I mean better.  Believe me, I would not have sunk the time into this end-around approach, if not for the fact that:</p>
<ol>
<li>I don&#8217;t want to maintain a local gem code modification (even though my impl is closely coupled to the gem impl already)</li>
<li>I intend to follow that practice, so every opportunity to pull and end-around is a Valuable Learning Experience.</li>
</ol>
<p>So, now my local <code>Twitter4R</code> has search capability gracefully latched onto it (and implemented much in the flavor of the library itself).  I have a mass of <code>rspec</code> examples to work off in the future.</p>
<p>Now, I haven&#8217;t spent a great amount of time testing the thread-safeness &#8212; no one in their right mind <em>wants</em> to do that &#8212; but my sundry <code>Twitter::Client</code> instances play nicely together in between searches and normal status operations.</p>
<p>And I had something useful to blog about!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Learning Ruby through Assertions and Podcasts</title>
		<link>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/</link>
		<comments>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 00:59:34 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[podcast]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=50</guid>
		<description><![CDATA[I&#8217;ve been working with the Ruby language since March 2008.  So (as of this writing) I&#8217;m still on the n00b path.
Assertions
The first thing I did was to follow the great advice of Dierk Koenig, writer of Groovy in Action and general Groovy / Grails advocate.  The book itself doesn&#8217;t use the typical print-the-result-based [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with the Ruby language since March 2008.  So (as of this writing) I&#8217;m still on the <a href="http://www.urbandictionary.com/define.php?term=n00b">n00b</a> path.</p>
<h3>Assertions</h3>
<p>The first thing I did was to follow the great advice of <a href="http://www.manning.com/koenig/">Dierk Koenig</a>, writer of <strong>Groovy in Action</strong> and general <a href="http://groovy.codehaus.org/">Groovy</a> / <a href="http://grails.org/">Grails</a> advocate.  The book itself doesn&#8217;t use the typical print-the-result-based code examples; it encourages the reader to learn the language <a href="http://groovy.codehaus.org/Quick+Start">through assertions</a>.  And that&#8217;s how I learned Groovy; I took the examples from the book, paraphrased them, tried variations on a theme, and then asserted that my results were true.  Now when I need to know how to use a language feature, I simply look back at my assertion code to re-edjumicate myself.</p>
<p>I learned the core Ruby language via <a href="http://rubyforge.org/projects/test-unit">Test::Unit</a>.  I spent three weeks (please don&#8217;t laugh) worth of my daily commute writing assertions for the core language, the standard packages, plus ActiveRecord and other common gems.  It allowed me to get a handle on the concepts, syntax, semantics and the sheer range of capabilities of he language.  I frequently look back at my <code>language_test_unit.rb</code> to figure out the best use of <code>Array.collect</code>, <code>catch..throw</code>, <code>Regexp</code> quirks, and using declared <code>lambda</code>s as blocks (etc).  More importantly, I&#8217;ve already written code using all of those techniques, so it&#8217;s just a referesher.</p>
<p>I <em>cannot recommend this technique enough</em> for coming up to speed on a language!</p>
<h3>Podcasts</h3>
<p>With that under my belt, plus some command-line scripts and a solid Rails project, I&#8217;m not spending time back-consuming posts from the following Podcast blogs:</p>
<h4>Rubyology</h4>
<p><a href="http://www.rubyology.com/">Site</a> : <a href="http://feeds.feedburner.com/rubyology">Feed</a></p>
<p>I&#8217;m actively back-consuming a lot of content from this wealth that Chris Matthieu has provided.  There are some great talks on <a href="http://www.rubyology.com/podcasts/show/70">Journeta</a>, using <a href="http://www.rubyology.com/podcasts/show/59">EC2</a>, great tutorials covering <a href="http://www.rubyology.com/podcasts/show/44">basic</a> and <a href="http://www.rubyology.com/podcasts/show/45"> RoR, and some <a href="http://www.rubyology.com/podcasts/show/13">scaling recommendations</a>.</p>
<h4>sd.rb Podcast</h4>
<p><a href="http://podcast.sdruby.com/">Site</a> : <a href="http://feeds.feedburner.com/sdrbpodcast">Feed</a></p>
<p>Straight from the mouth of the San Diego Ruby Users group.  A good variety of topics, focusing more on the Ruby language than on the Rails poster-child itself.  Nice talks on <a href="http://podcast.sdruby.com/2008/6/5/episode-046-rspec-in-15-minutes">rspec</a>, <a href="http://podcast.sdruby.com/2008/4/28/episode-041-mysql-clustering">MySQL clustering</a> and <a href="http://podcast.sdruby.com/2008/9/12/episode-053-ruby-arduino-development-rad">Arduino</a>, amongst many others.</p>
<h4>Railscasts</h4>
<p><a href="http://railscasts.com/">Site</a> : <a href="http://feeds.feedburner.com/railscasts">Feed</a></p>
<p>With 145 postings and counting, there&#8217;s a lot to be consumed here.  However, this is the last on my list, because none of them download to my iPhone 3G :( .  Lots of cross coverage on <a href="http://railscasts.com/episodes/133-capistrano-tasks">Capistrano</a>, <a href="http://railscasts.com/episodes/99-complex-partials">Partials</a>, custom <a href="http://railscasts.com/episodes/70-custom-routes">Routes</a>, <a href="http://railscasts.com/episodes/54-debugging-with-ruby-debug">ruby-debug</a> &#8230; the list goes on.</p>
<h4>Ruby on Rails Podcast</h4>
<p><a href="http://podcast.rubyonrails.org/">Site</a> : <a href="http://feeds.feedburner.com/rubyonrailspodcast">Feed</a></p>
<p>Geoffrey Grosenbach&#8217;s podcasts are seminal.  I&#8217;ll leave it up to the reader to <a href="http://answers.yahoo.com/question/index?qid=20080108230303AARcDfm">pore through</a> the years of accumulated wisdom.  How can you go wrong when you&#8217;re part of the <a href="http://rubyonrails.org">rubyonrails.org</a> domain!</p>
<h3>In Summary</h3>
<p>A number of these feeds provide screencasts and/or video.  A few of the files are old-school QuickTime MOVs which are problematic for the iPhone, which is annoying (definitely not the podcaster&#8217;s fault&#8230; get your head in gear, Apple).  And unfortunately when I break away to write down something in <a href="http://evernote.com/"><strong>Evernote</strong></a><strong>.app</strong>, and there&#8217;s any visuals associated with the cast, the iPhone halts playback.  <em>Grr.</em>  So I&#8217;m getting into the archaic habit of creating a <strong>Notes</strong> page and mailing it to myself :)</p>
<p>I recommend <em>each and all</em> of these podcasts.  Be prepared to sink a lot of time into them, so you might as well upload them onto your iPhone and take them to the beach!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
