<?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>Open Sourcery &#187; ruby</title>
	<atom:link href="http://www.opensourcery.co.za/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.opensourcery.co.za</link>
	<description>Wizardry through open source</description>
	<lastBuildDate>Wed, 04 Aug 2010 13:04:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>daemon-kit 0.1.8 released</title>
		<link>http://www.opensourcery.co.za/2010/08/04/daemon-kit-0-1-8-released/</link>
		<comments>http://www.opensourcery.co.za/2010/08/04/daemon-kit-0-1-8-released/#comments</comments>
		<pubDate>Wed, 04 Aug 2010 13:04:46 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[daemon-kit]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=292</guid>
		<description><![CDATA[I&#8217;m proud to announce that daemon-kit has finally made it to 0.1.8.1, almost a year after the last patch release. There has been a lot of changes since the last release, mostly cleanly up and staying with the times (so to speak). Github has an awesome compare view, detailing the historic moment, and I&#8217;ll go [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m proud to announce that daemon-kit has finally made it to 0.1.8.1, almost a year after the last patch release. There has been a lot of changes since the last release, mostly cleanly up and staying with the times (so to speak). Github has an awesome compare view, <a href="http://github.com/kennethkalmer/daemon-kit/compare/0.1.7.12...0.1.8" target="_blank">detailing the historic moment</a>, and I&#8217;ll go through it here in some detail as well.</p>
<p>First off I&#8217;d like to thank a few people who have quietly and vocally contributed to or promoted daemon-kit. In no particular order, thanks goes to:</p>
<ul>
<li><a href="http://fourbeansoup.com">Josh Owens</a> (<a href="http://twitter.com/joshowens">@joshowens</a>) for actively testing bug fixes and promoting the project</li>
<li><a href="http://www.mikeperham.com">Mike Perham</a> (<a href="http://twitter.com/mperham">@mperham</a>) for actively reporting bugs, providing patches and promoting the project</li>
<li>I&#8217;ve pulled in patches from the forks of <a href="http://github.com/mhutchin">Michael Hutchinson</a>, <a href="http://github.com/milann">Milan Novota</a>, <a href="http://github.com/jgeiger">Joey Geiger</a>, and <a href="http://github.com/merrells">John Merrels</a></li>
<li><a href="http://github.com/gcampbell">Greg Campbell</a> reported an issue with the AMQP generated daemons only hours after pushing 0.1.8 to gemcutter</li>
</ul>
<p>The two biggest changes for me has been converting all the generators to use Thor, and using Bundler in the generated daemons. Both of these projects have received some flack, but they both continue to serve me very well and I&#8217;m sure they&#8217;ll serve daemon-kit well.</p>
<p>The logger got some minor updates, to be more compatible with the standard Ruby logger class. A brand new XMPP generator is included, and it uses Blather for some awesome evented-goodness. Argument handling got fixed up, email exceptions got removed from the project (I might consider implementing them after overhauling the error reporting features of dk). Hoptoad error reporting got upgraded to the use the newer API. The generated rake tasks are more forgiving when rspec/cucumber or other gems are missing. The cron daemon got some love, allowing easier exception logging/notification for when scheduled tasks fail.</p>
<p>I&#8217;ll continue chipping away at the project, tidying up loose ends as they are reported, and start developing a proper test suite for everything.</p>
<p>Over the long term I&#8217;m hoping to reach the following goals:</p>
<ul>
<li>Always running the eventmachine reactor (think node.rb)</li>
<li>Support for more modular daemons, including &#8217;single-file&#8217; daemons</li>
<li>Support for daemons inside Rails projects</li>
</ul>
<p>Some things will probably get thrown out, like generating configs for god &amp; monit. The more I use chef, the more I realize that those responsibilities lie with the infrastructure management (or devops), and not within the project itself. I&#8217;m aware this might cause an upset, however I firmly believe that a lighter and smaller daemon-kit will serve the greater community better.</p>
<p>Thanks for making daemon-kit the number 1 daemonizing project. Please share the love and send feedback, and more importantly use Github issues to log issues, feedback, and wishes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2010/08/04/daemon-kit-0-1-8-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paginating documents with couchrest and will_paginate</title>
		<link>http://www.opensourcery.co.za/2010/02/08/paginating-documents-with-couchrest-and-will_paginate/</link>
		<comments>http://www.opensourcery.co.za/2010/02/08/paginating-documents-with-couchrest-and-will_paginate/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 20:34:16 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[nosql]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[couchrest]]></category>
		<category><![CDATA[will_paginate]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=283</guid>
		<description><![CDATA[CouchDB is hands down my favorite of the NoSQL variants and offers some pretty spectacular features, none of which I will bore you with in this post. I will however jot down how I (fairly easily) achieved pagination with couchrest &#38; will_paginate in a fairly large Rails application recently.
John P Wood discussed some issues they [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://couchdb.apache.org/">CouchD</a>B is hands down my favorite of the NoSQL variants and offers some pretty spectacular features, none of which I will bore you with in this post. I will however jot down how I (fairly easily) achieved pagination with <a href="http://github.com/couchrest/couchrest">couchrest</a> &amp; <a href="http://github.com/mislav/will_paginate">will_paginate</a> in a fairly large Rails application recently.</p>
<p>John P Wood <a href="http://johnpwood.net/2009/08/18/couchdb-the-last-mile/">discussed some issues</a> they faced with will_paginate and couchrest during the migration of TextMe to CouchDB, but l left out some code to work with. Couchrest itself had some pagination support that got pulled to some extent&#8230; This left me wanting, and wondering, since it was my turn to walk down this path.</p>
<p>CouchDB is a different beast, its aggressive use of indexes means that occasionally you loose some functionality that you&#8217;ve been accustomed to having in other persistence mechanisms, like the number of rows matching a query. Jan Lenhardt explains on the <a href="https://issues.apache.org/jira/browse/COUCHDB-82">CouchDB issue tracker in more detail</a>, but it boils down that you need a reduce function to calculate the number of rows. Sounds difficult? Not at all!</p>
<p>In my case I had a collection of announcements to deal with, and the announcement archives is a paginating collection of documents. Standard will_paginate stuff, nothing special.</p>
<p><em>Those reading in a reader would want to click through to the post to view the embedded gists further down, or view them <a href="http://gist.github.com/298523">directly at Github</a></em><em>.</em></p>
<p>Below is a condensed version of the model from our paginating system:</p>
<p><script src="http://gist.github.com/298523.js?file=announcement.rb"></script> I&#8217;ve included only one view and a corresponding class method, as it is enough to proof the principle. Lets dissect.</p>
<p>The map/reduce functions are extremely simplistic, they simply emit the announcer and the date the announcement was created. This allows for easy scoping and ordering of the announcements. The reduce simply counts our returned records.  The magic is in the class method that sets up our WillPaginate::Collection with data from our views.</p>
<p>Line 30 creates a new WillPaginate::Collection instance, passing it the page number and total per page as parameters, it gives us back a pager that we can manipulate.</p>
<p>Lines 31 through 38 uses couchrest&#8217;s pagination support to pull out data from our view. The most important things to note here are that the <em>page</em> and <em>per_page</em> options are sent to the paginator and <em>we skip the reduce step</em>.</p>
<p>Once we have our records loaded, we &#8216;replace&#8217;  the pager&#8217;s collection with our results from our view (line 40).</p>
<p>The final step is to determine the total number of documents available to us, and for this we need the reduce function. On line 42 we call the same view, with the same arguments, except for requiring the reduce step to happen. We use the results (lines 43 to 47) to inform the pager (will_paginate&#8217;s pager) how many rows there are in total.</p>
<p>The controller and the views might look something like this:  <script src="http://gist.github.com/298523.js?file=announcements_controller.rb"></script><br />
<script src="http://gist.github.com/298523.js?file=index.html.haml"></script></p>
<p>It worked, and it shows that we don&#8217;t loose as much as we might think when moving away from ActiveRecord and the ton of plugins surrounding it.</p>
<p>Thanks to John for documenting the migration of TextMe, just knowing that it was possible to combine couchrest &amp; will_paginate gave me the push I needed to figure this out.</p>
<p>Disclaimer: This code is extracted &#8220;as is&#8221; from a real life system and might contain idioms/phrases, and even code, that doesn&#8217;t make 100% when viewed in a gist. Please wear your thinking cap when applying this lesson to your own projects.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2010/02/08/paginating-documents-with-couchrest-and-will_paginate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Correlating documents in CouchDB</title>
		<link>http://www.opensourcery.co.za/2009/12/13/correlating-documents-in-couchdb/</link>
		<comments>http://www.opensourcery.co.za/2009/12/13/correlating-documents-in-couchdb/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 20:40:35 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[couchdb]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=275</guid>
		<description><![CDATA[I&#8217;m in the very fortunate position, two actually, of being able to 1) migrate my biggest production application from MySQL to CouchDB, and 2) build a stunning new system for a multinational welfare organization on top of CouchDB.
I&#8217;ve been lurking in the CouchDB world for quite some time and have spent a lot of time [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in the very fortunate position, two actually, of being able to 1) migrate my biggest production application from MySQL to CouchDB, and 2) build a stunning new system for a multinational welfare organization on top of CouchDB.</p>
<p>I&#8217;ve been lurking in the CouchDB world for quite some time and have spent a lot of time wrestling with how to loosely relate documents in CouchDB to each other. A big part of learning to use CouchDB successfully is to break away from the shackles of the relational world. Relationships between documents is one such a shackle that seems hard to break.</p>
<p>It is unavoidable that data has to be correlated, and I wanted to rethink how to do it. After plenty of discussions in #ruote with John Mettraux we came up with a model based on how the web works. Since CouchDB is &#8220;off the web&#8221;, the approach feels quite fitting to me and hopefully to you too.</p>
<p>First some insight into my thinking at this stage.</p>
<p>The web has been successful in loosely expressing relationships between documents. Take two examples:</p>
<p><script src="http://gist.github.com/255582.js?file=gistfile1.htm"></script> and  <script src="http://gist.github.com/255582.js?file=gistfile2.htm"></script></p>
<p><em>For those of you reading this through a reader, click through to see the gist&#8217;s above.</em></p>
<p>Simple as it seems, in both cases we have a document that is somehow related to the page. The nature of the relationship is expressed via the <em>rel</em> attribute, and the target specified via the <em>href</em> attribute. This got me thinking. Since CouchDB is made <em>off the web, </em>can&#8217;t these same principles be applied?</p>
<p>Yes, they can. And here is how:</p>
<p>Currently you might be tempted to express relationships link this in your JSON:</p>
<p><script src="http://gist.github.com/255582.js?file=gistfile3.js"></script> Where changing it to this holds the key:  <script src="http://gist.github.com/255582.js?file=gistfile4.js"></script></p>
<p>If anything this format, albeit more verbose, expresses the relationships more clearly and in a format that is web friendly. We&#8217;ve broken the shackles of relational thinking.</p>
<p><strong>Enter Correlate</strong></p>
<p><a href="http://github.com/kennethkalmer/correlate" target="_blank">Correlate</a> is an experiment in this line of thinking. It is a mixin for CouchRest&#8217;s extended documents that allows you to express these relationships:</p>
<p><script src="http://gist.github.com/255582.js?file=gistfile5.rb"></script></p>
<p>Correlate generates getter and setter methods for working with your relationships and lot more (review the <a href="http://github.com/kennethkalmer/correlate/blob/master/README.rdoc" target="_blank">README</a>). It also includes a compatibility layer for ActiveRecord to help when you&#8217;re migrating from ActiveRecord to CouchRest or building a system on CouchDB that needs to access legacy data via ActiveRecord.</p>
<p>The project is still pretty much a moving target, but I&#8217;d love to hear how others address the same issues. Correlate does a great job at maintaining relationship information in a <em>web friendly</em> manner and providing you with some convenience around the verbose data structure. Correlate also has a lot of room for improvement, but that will hopefully change over the coming days as I continue integrating it deeply into my existing projects.</p>
<p>Please fork the project on github and join the experiment with me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/12/13/correlating-documents-in-couchdb/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Rails specs not running under Ruby 1.9 ?</title>
		<link>http://www.opensourcery.co.za/2009/09/27/rails-specs-not-running-under-ruby-1-9/</link>
		<comments>http://www.opensourcery.co.za/2009/09/27/rails-specs-not-running-under-ruby-1-9/#comments</comments>
		<pubDate>Sun, 27 Sep 2009 08:08:11 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby19]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=265</guid>
		<description><![CDATA[I spent some time getting PowerDNS on Rails to run on Ruby 1.9.1, which ended up being very easy due to the small amount of plugins &#38; gems used by the project. The only change I had to make myself was to the acts_as_audited plugin, where the one-line fix got merged upstream.
The worst part of [...]]]></description>
			<content:encoded><![CDATA[<p>I spent some time getting <a href="http://github.com/kennethkalmer/powerdns-on-rails">PowerDNS on Rails</a> to run on Ruby 1.9.1, which ended up being very easy due to the small amount of plugins &amp; gems used by the project. The only change I had to make myself was to the <a href="http://github.com/kennethkalmer/acts_as_audited">acts_as_audited</a> plugin, where the <a href="http://github.com/collectiveidea/acts_as_audited/commit/02e35ac368f3125887c4752a39610f5e914ff6b7#L0L40">one-line fix got merged upstream</a>.</p>
<p>The worst part of the process was getting the specs to run with <em>rake spec</em>. Using <em>./script/spec</em> it worked on individual specs and on all the specs worked as advertised, but <em>rake spec</em> didn&#8217;t do anything.</p>
<p>After a lot of time spent in the debugger I wasn&#8217;t any wiser. The only difference was that in Ruby 1.8 the example groups were fully loaded, and in Ruby 1.9 they were empty. I gave up and started searching relentlessly for some information on the issue. I couldn&#8217;t find anything, until I found an indirect solution on the <a href="http://wiki.github.com/dchelimsky/rspec/ruby-191">rspec wiki</a>. It seems that if you have any versions of the test-unit gem after the 1.2.3 release installed, your Rails specs will simply not run. For me, removing test-unit 2.0.3 made the difference and the specs ran properly. PowerDNS on Rails has now joined the ranks of my <a href="/ruby-19-progress-report/">Ruby 1.9 compatible projects</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/09/27/rails-specs-not-running-under-ruby-1-9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruote in 20 minutes video</title>
		<link>http://www.opensourcery.co.za/2009/08/25/ruote-in-20-minutes-video/</link>
		<comments>http://www.opensourcery.co.za/2009/08/25/ruote-in-20-minutes-video/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 17:45:29 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=258</guid>
		<description><![CDATA[Kudos to my brother and the rest of the guys at Monopost for cleaning up the bad audio as best they can.

Ruote in 20 minutes from Kenneth Kalmer on Vimeo.
The original post of the presentation is over here.
]]></description>
			<content:encoded><![CDATA[<p>Kudos to my <a href="http://twitter.com/Will_Mono">brother</a> and the rest of the guys at <a href="http://www.monopost.tv">Monopost</a> for cleaning up the bad audio as best they can.</p>
<p><object width="400" height="300" data="http://vimeo.com/moogaloop.swf?clip_id=6261927&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=6261927&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /></object></p>
<p><a href="http://vimeo.com/6261927">Ruote in 20 minutes</a> from <a href="http://vimeo.com/kennethkalmer">Kenneth Kalmer</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>The original post of the presentation is over <a href="/2009/03/04/ruote-in-20-minutes/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/08/25/ruote-in-20-minutes-video/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Getting the Ruby 1.9 ball rolling</title>
		<link>http://www.opensourcery.co.za/2009/08/14/getting-the-ruby-19-ball-rolling/</link>
		<comments>http://www.opensourcery.co.za/2009/08/14/getting-the-ruby-19-ball-rolling/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 15:36:51 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby19]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=243</guid>
		<description><![CDATA[
After I read this post on Labnotes I decided to &#8220;take the plunge&#8221; into the world of Ruby 1.9 properly. I mean, I was at RubyKaigi where the biggest lesson of all was &#8220;Change!&#8221; (and changing to 1.9). Ruby 1.9.1 has been stable for quite some time now, and 1.9.2 is due out on Christmas. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.labnotes.org/2009/08/13/i-switched-to-ruby-1-9-and-you-should-too/"><img src="http://twictur.es/i/3306126571.gif" alt="" /></a></p>
<p>After I read <a href="http://blog.labnotes.org/2009/08/13/i-switched-to-ruby-1-9-and-you-should-too/">this post</a> on Labnotes I decided to &#8220;take the plunge&#8221; into the world of Ruby 1.9 properly. I mean, I was at RubyKaigi where the biggest lesson of all was &#8220;Change!&#8221; (and changing to 1.9). Ruby 1.9.1 has been stable for quite some time now, and 1.9.2 is due out on Christmas. And we&#8217;re still stuck on 1.8.6 ? <strong>WTF</strong></p>
<p>Getting started with Ruby 1.9 is easy (only time will tell <a href="http://twitter.com/vandermerwe/status/3307761128">how much pain</a> is caused). I have to admit I&#8217;m not as brave to wipe my rubygems installation, I might still need 1.8.6 (and I seriously hope I don&#8217;t).</p>
<p>So Relevance made this awesome bash script called <a href="http://blog.thinkrelevance.com/2009/7/29/ruby-switcher-working-with-multiple-ruby-versions-has-never-been-this-easy">ruby_switcher.sh</a> that you absolutely have to try. Once you have it installed and working as per their instructions you need to make one small change to the very last line of ruby_switcher.sh. That change looks like this:</p>
<pre>#use_leopard_ruby
use_ruby_191</pre>
<p>Simple and I can easily toggle 1.8.6 mode if needed.</p>
<p><img src="http://twictur.es/i/3307027729.gif" alt="" /></p>
<p>Yes, I did.</p>
<p>So over the coming days I&#8217;ll be working through all 28 of my github repos and making sure they run on 1.9. This is no small task, but I&#8217;m looking forward to getting my &#8220;house&#8221; in order.</p>
<p>At this stage I know <a href="http://github.com/kennethkalmer/acts_as_audited">acts_as_audited</a> is 1.9 compatible, I fixed it earlier the week while testing ruby_switcher. I had a look at <a href="http://github.com/kennethkalmer/activerecord-tableless-models">ActiveRecord::Tableless</a> and decided to pull the plug on the project completely (<a href="http://github.com/kennethkalmer/activerecord-tableless-models/commit/097ad7f5f2d5589beb867790873df04f25c5b842">see here</a>).</p>
<p>I&#8217;m really looking forward to this adventure and sharing the ups and downs of the road with everyone. Ultimately I would love it if we can get the South Africa Ruby ecosystem on 1.9.X ASAP.</p>
<p>Follow my project updates over on my <a href="/ruby-19-progress-report">Ruby 1.9 Progress Report</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/08/14/getting-the-ruby-19-ball-rolling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looking beyond daemon-kit 0.2</title>
		<link>http://www.opensourcery.co.za/2009/08/09/looking-beyond-daemon-kit-02/</link>
		<comments>http://www.opensourcery.co.za/2009/08/09/looking-beyond-daemon-kit-02/#comments</comments>
		<pubDate>Sun, 09 Aug 2009 21:40:07 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[daemon-kit]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=234</guid>
		<description><![CDATA[
I wrote daemon-kit to solve two big issues with writing daemon processes in Ruby:

Everyone is re-inventing the daemons gem
Individual daemons share a lot common code, apart from the daemonizing bits

As for #1, daemon-kit at first wrapped the daemons gem, and later ripped it out completely as it was difficult to wrap up the worst of [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-237 alignright" title="Works Ahead - Singapore Department of Transport " src="http://www.opensourcery.co.za/wp-content/uploads/2009/08/works-ahead.jpg" alt="Works Ahead - Singapore Department of Transport " width="180" height="150" /></p>
<p>I wrote <a href="http://github.com/kennethkalmer/daemon-kit">daemon-kit</a> to solve two big issues with writing daemon processes in Ruby:</p>
<ol>
<li>Everyone is re-inventing the <a href="http://daemons.rubyforge.org/">daemons gem</a></li>
<li>Individual daemons share a lot common code, apart from the daemonizing bits</li>
</ol>
<p>As for #1, daemon-kit at first wrapped the daemons gem, and later ripped it out completely as it was difficult to wrap up the worst of the daemons gem properly.</p>
<p>#2 seemed to be a twofold problem that daemon-kit has also addressed with great success. The first was addressing the all too common issues of logging, pid file management, umasks, signal traps, config files, exception handling and other &#8220;low-level&#8221; issues. Everyone was implementing these things to a limited extent in their daemons and this could cause a lot of frustration when done wrong. The second part was the need, even if undiscovered, for higher level re-use and development speed. Daemon-kit addresses this with some limited generators, making it easy to get going with a cron-style daemon, AMQP &amp; XMPP bots as well as the newest addition, Ruote remote participants.</p>
<p>All this is fine and well, and people seem to like the project. The mailing list is getting some noise, we&#8217;re over <a href="http://github.com/kennethkalmer/daemon-kit/watchers">200 watchers strong</a> on Github and the IRC channel has some folks popping in to say hi.</p>
<p>However, daemon-kit quickly made me lazy and realize there is a couple of things it can do much better. If you&#8217;ve used a generator before, you&#8217;ll notice the generated code is very much stuck to that type of daemon. Changing from XMPP to AMQP (for illustrative purposes) would be best accomplished by generating a new project and copying over the <em>lib/</em> folder only. This sucks.</p>
<p>Another problem is people, myself included, would like to have <a href="http://groups.google.com/group/eventmachine/msg/84372822d1cb06db">Sinatra-style daemons</a> (i.e. one file) for smaller tasks. Currently this is not possible at all. Another thing I know people are doing behind my back is generating daemons inside Rails projects, which may or may not work, depending on whether you load Rails&#8217; environment.rb.</p>
<p><strong>So, what happens now?</strong></p>
<p>My thoughts are to implement privilege dropping support and tag a 0.2 release. This gives us a feature complete framework, albeit not as good as it can be. I&#8217;ll maintain 0.2 as a stable while undertaking the rewrite. A rewrite? Read on.</p>
<p>I <a href="http://groups.google.com/group/daemon-kit/browse_thread/thread/6d8be608798f67e6">posted to the daemon-kit list</a> a suggestion for stackable daemon environments. I&#8217;ve discussed this in IRC with a few folks as well. <a href="http://github.com/jpr5">Jordan Ritter</a> gave me an exceptional breakdown of the dangers of doing something because it is &#8220;neat&#8221; and I&#8217;ve taken his warning to heart. However, I cannot seem to argue against stackable daemon environments, it sounds too good.</p>
<p>The idea is pretty simple. Stack-entries can be compared to Rack applications, with two significant differences. The first is that they will be <em>called only once</em>. They have the opportunity to change the environment in which the final code runs. The second is that they can be called at four different stages of the daemon lifecycle: argument processing, pre-daemonization, post-daemonization and shutdown. This differs from Rack&#8217;s single <em>call()</em> method.</p>
<p>The stackable nature also gives the stack members easier ways to set conventions and can dramatically minimize configuration. It paves the way for plugins, sinatra-style daemons, rails-based daemons and easier packaging of distributable daemons, and so much more. Looking at the internals of daemon-kit, it would greatly help simplify the existing code as well as help separate utility classes from stack members.</p>
<p>The more I think about it, the more obvious this becomes, and the more possibilities unfold for the framework. This will definitely make daemon-kit a force to be reckoned with, and hopefully I can persuade other library developers to offload their daemonizing code to daemon-kit, just like rack developers offload their HTTP handling to rack.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/08/09/looking-beyond-daemon-kit-02/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>DaemonKit Lightning Talk RubyKaigi 2009</title>
		<link>http://www.opensourcery.co.za/2009/07/18/daemonkit-lightning-talk-rubykaigi-2009/</link>
		<comments>http://www.opensourcery.co.za/2009/07/18/daemonkit-lightning-talk-rubykaigi-2009/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 15:30:46 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[daemon-kit]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[rubykaigi]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=231</guid>
		<description><![CDATA[Daemon Kit &#8211; RubyKaigi 2009
View more documents from Kenneth Kalmer.

Undoubtedly my worst time on stage ever! Ubuntu gave me issues with the projector, so I actually had to leave the stage to go to another conference hall to get the setup working again and run back up to the main hall&#8230; Once there, I was [...]]]></description>
			<content:encoded><![CDATA[<div id="__ss_1738038" style="width: 425px; text-align: left;"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" title="Daemon Kit - RubyKaigi 2009" href="http://www.slideshare.net/kenneth.kalmer/daemon-kit-rubykaigi-2009">Daemon Kit &#8211; RubyKaigi 2009</a><object width="425" height="355" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=daemon-kit20090718kaigi-090718102212-phpapp02&amp;stripped_title=daemon-kit-rubykaigi-2009" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=daemon-kit20090718kaigi-090718102212-phpapp02&amp;stripped_title=daemon-kit-rubykaigi-2009" /><param name="allowfullscreen" value="true" /></object></p>
<div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">documents</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kenneth.kalmer">Kenneth Kalmer</a>.</div>
</div>
<p>Undoubtedly my worst time on stage ever! Ubuntu gave me issues with the projector, so I actually had to leave the stage to go to another conference hall to get the setup working again and run back up to the main hall&#8230; Once there, I was a mumbling mess, but made it through without the buzzer beating me.</p>
<p>Presenting a lightning talk at a Japanese conference is surely something else, the audience expects fireworks and the presenters deliver. It was truly an amazing experience, humilation and all, and I&#8217;m looking forward to the last day of the conference.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/07/18/daemonkit-lightning-talk-rubykaigi-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Driving Business Processes in Ruby</title>
		<link>http://www.opensourcery.co.za/2009/07/06/driving-business-processes-in-ruby/</link>
		<comments>http://www.opensourcery.co.za/2009/07/06/driving-business-processes-in-ruby/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 07:44:44 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>
		<category><![CDATA[state_machine]]></category>
		<category><![CDATA[workflows]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=218</guid>
		<description><![CDATA[Decisions decisions, as Ruby developers we face them every day. Some are easier to make than others, they have the ability to shape or break a project (even a business). We&#8217;ve faced the decisions of ActiveRecord or DataMapper, jQuery or Prototype, Merb or Rails. Now the decisions are getting tough, and the impact of the [...]]]></description>
			<content:encoded><![CDATA[<p>Decisions decisions, as Ruby developers we face them every day. Some are easier to make than others, they have the ability to shape or break a project (even a business). We&#8217;ve faced the decisions of ActiveRecord or DataMapper, jQuery or Prototype, Merb or Rails. Now the decisions are getting tough, and the impact of the next decisions are even bigger. I recently tackled the issue of <a href="http://www.opensourcery.co.za/2009/04/19/to-amqp-or-to-xmpp-that-is-the-question/">choosing between AMQP and XMPP</a> (and I&#8217;m honestly still on the bench, even when I&#8217;m using <em>both</em> in production), and there is the SQL or NoSQL decision.  So what is your next big decision?</p>
<p><strong>Do you externalize your business processes? Or, do you use a state machine or workflow engine?</strong></p>
<p><strong></strong>John Mettraux posted a powerful read on the fact that <a href="http://jmettraux.wordpress.com/2009/07/03/state-machine-workflow-engine/">state machines are not workflow engines</a>, and I share the sentiment completely. I&#8217;m a vocal user of John&#8217;s <a href="http://ruote.rubyforge.org">ruote</a>, a Ruby workflow engine, but I also use state machines, and I use them in tandem.</p>
<p>I choose early on that I need to externalize my business processes for our <a href="http://www.ispinabox.co.za/">ISP in a Box</a> product, to help break the project into manageable components, and this article shares how and why.</p>
<p><strong>Limitations of state machines</strong></p>
<p>I&#8217;m not giving any background on <a href="http://en.wikipedia.org/wiki/Finite-state_machine">what state machines are</a>, or any of the possible uses. I&#8217;m going to highlight some limitations of state machines from a business process perspective, especially state machines that hook into ActiveRecord (or database models).</p>
<p><em>Lack of context</em></p>
<p>Knowing in what state the object is isn&#8217;t always enough. For decision makers (autonomous or human), context plays a definitive part in making a business decision. If a service ends up in a &#8220;suspended&#8221; state, for arguments sake, decision makers need to know why. Was the service suspended due to bad payment, was it suspended due to abuse of the terms of use, or was it suspended because client relations had a bad day. Having multiple states to disambiguate the precariousness of the suspension is not cool.<br style="text-decoration: line-through;" /><br />
<em>Lack of history</em></p>
<p>Extending on the context topic above, the history of how an object got to a state might be just as important to a decision maker. It is also important for a reporter, or observer in the process. Business processes inherently have multiple paths, it is just never as simple as it seems. Placing an order for a book at Amazon, in theory, fires off business processes unimaginable to us mere mortals. Think about it for a second, they need to check stock, decide from which warehouse to dispense stock, optimum shipping combinations, manage re-orders, handle invalid shipping destinations, and so much more. Calling events on an order object just won&#8217;t cut it. Each decision maker in such a huge process needs to know why the work ended up at them. A shipping coordinator in New York might question why he has to ship a book to Seattle, but if he knows that Los Angeles is out of stock he doesn&#8217;t mind to do it. I know they&#8217;re fully automated, but play along for a second.</p>
<p><em>Open ended</em></p>
<p>Another thing about state machines is their open ended nature. For a lot of applications this is brilliant, but not for business processes. Business processes have a definite start and end, with whatever means needed to get from the one to the other. State machines can change from any state to another. This can however be controlled with guards, or setting up a limited transition table, but then the machine gets clunky and difficult to manage. It looses it&#8217;s appeal.</p>
<p><em>Versionless</em></p>
<p>State machines are versionless by nature, and business processes are constantly evolving and getting refactored. As decision makers gain more experience, business processes get leaner and meaner. Especially in times of financial uncertainty there is a big focus on driving down costs and cutting out unneeded, costly steps from business processes. In a state machine this doesn&#8217;t necessarily translate into less states, or less transitions, but it does make it difficult to determine if a process is still part of the old regime, or the new one.</p>
<p><em>State machines are good at expressing behaviors</em></p>
<p><em></em>And this should be leveraged by the developer, however, behaviors hardly come close to defining a business process as a whole. The behavior of an object can be seen as how it it behaves during a business process, and not the process itself. More on this later when I discuss combining state machines and workflow engines.</p>
<p><em>Don&#8217;t abandon state machines!</em></p>
<p>To proponents of state machines this post will definitely seem like heresy, and I do apologise. State machines are wonderful tools, and at the end of the article you&#8217;ll see how I do use them together with a workflow engine. My argument for the post is that state machines are not the right tool to drive business processes. Business processes are big and bulky and far more complex than what they appear on the surface. They need a suitable environment to run in, something stable to drive them, and a database model with a state machine is hardly the place.</p>
<p><strong>Externalize your business processes</strong></p>
<p><strong></strong>Externalizing your business processes, and running them inside a workflow engine is a big decision that has massive payoffs if you implement it correctly. If you do it wrong, you will most likely hate me for writing this article, and pretty much everyone in the BPM/WFE space. For me, the decision to externalize the process is busy paying off handsomely, albeit I&#8217;m still resolving a lot of unanticipated issues (ie scaling the workflows).</p>
<p><em>Enter ruote</em></p>
<p>ruote is a Ruby workflow engine, which parses process definitions into expression trees and executes them. Greek? Don&#8217;t worry. Process definitions, a ruote DSEL, are Ruby classes that definite the flow of your business process. They are made up off expressions (think methods), and each expression plays its part in the business process. This is akin to a flowchart, where you have a start and an end, or multiple ends to the process. Expressions can be decision points (diamonds), participants that perform work (blocks), looping constructs and plenty of other goodies. ruote is a business process operating system&#8230;</p>
<p><em>Workflow engines are business process operating systems</em></p>
<p><em></em>Bold statement, yes, but not a lie. Workflow engines need to be solid and reliable environments. We rely on Apache to reliably house our running application, or databases to reliably store our information, and the operating system to reliably run all of this. If the environment is stable, we can focus on our own code, without much care. The same holds true for our business processes. A workflow engine doesn&#8217;t have office hours, needs to be available at all times and running flawlessly. It also requires a lot of instruments that coordinate our efforts, to keep our business afloat. There is persistence, thread safety and concurrent access of work, schedulers and much more at play.</p>
<p>A part of me thinks that state machines are so attractive to us as Ruby developers because we don&#8217;t want to manage all the real work involved in running business processes. We like turning ORM&#8217;s into Thor&#8217;s hammer, so to speak.</p>
<p><em>Participation</em></p>
<p><em></em>As your business process is executing it will interact with various participants. Participants can be be fully autonomous, or people. The concepts of participants is foreign at first, because it doesn&#8217;t map to users of the system directly. To give you a rough idea of participants, consider a simple domain registration process. Our clients register a new domain in the system, which initiates a new instance of a defined business process. First we add the domain to our DNS servers, then we register the domain with a registrar, then we notify the client. Without automation we&#8217;ll have one participant: ActiveRecord participant. This participant simply saves workitems in a table in a database, and we can poll this table looking for work. Using the workitem&#8217;s payload we can determine whether the workitem indicates one of three unique pieces of work that needs to be performed:</p>
<ol>
<li>DNS Admin to add domain to servers</li>
<li>DNS Admin to register domain with registrar</li>
<li>Client message when they log back in again (or view domain, or whatever)</li>
</ol>
<p>With automation the participation changes to something like this:</p>
<div>
<table id="lhqo" class="zeroBorder" border="0" cellspacing="0" cellpadding="3" bordercolor="#000000">
<tbody>
<tr>
<td>PowerDNS Participant</td>
<td>Use ActiveResource to add the domain via <a href="http://kennethkalmer.github.com/powerdns-on-rails/">PowerDNS on Rails</a></td>
</tr>
<tr>
<td>Registrar Participant</td>
<td>Register the domain via registrars pathetic XML API</td>
</tr>
<tr>
<td>Notification Participant</td>
<td>Send an email to the client to tell them registration has completed</td>
</tr>
<tr>
<td>ActiveRecord Participant</td>
<td>If automation fails, have a workitem ready for support personnel</td>
</tr>
</tbody>
</table>
</div>
<p><em>History and context</em></p>
<p>Using the above example of automating processes, history and context becomes quite important when a workitem lands at the support personnel desk. They need to know where the error happened, what lead up to the error, who is involved in the process, and maybe something more. The ability to extract a JSON-formatted expression tree from the engine allows us use ruote-fluo to graph the process on a canvas tag for the support personnel, so they know exactly what happened prior to the error being reported. This knowledge of prior actions is invaluable when deciding on a course of action, which in business is the difference between closing or cancelling a deal.</p>
<p><em>Time sensitive &amp; long running processes</em></p>
<p>Automated business processes can usually finish within a couple of minutes, or seconds, depending on their complexity and the number of autonomous participants involved. But business is never as simple as it seems, and time is usually the enemy. A business process might indicate that if a support call has been opened without an initial response for more than 4 hours it needs to be escalated. Others might have indicate that we don&#8217;t send SMS messages between 19:00 and 6:00, so we don&#8217;t wake our clients. This mixed bag of <em>sleep</em> and <em>timeout</em> expressions are difficult to get done on your own, and a workflow engine should (ruote does) support this out of the box.</p>
<p><em>Versioned processes</em></p>
<p>Process definitions in ruote are parsed upon launching the process. Ruote converts the process definition into an expression tree and works with the expression tree from that point forward. Process definitions can then be fine-tuned and altered and all new launches will use the updated definitions. Existing process instances stick to their expression tree in the engine, so they remain unaffected to the changes and will play out exactly as intended. But the expression trees are not concrete either, once in the engine they can be altered at runtime, but I still have to explore those abilities of ruote myself.</p>
<p><strong>Going hybrid, using the best of both</strong></p>
<p><strong></strong>I said earlier that I haven&#8217;t abandoned state machines, and that I rather use the two instruments together to accomplish what my system requires. This is in fact very simple to implement and works brilliantly.</p>
<p>ISP in a Box sells services, and these services need to acquired/provisioned for our clients to make use of them. All our models share, a mostly common, state machine. When services are provisioned for the first time, they enter their initial state called &#8220;pending&#8221;, and the provisioning process for said service is launched. The state machine has no idea what is going on at this stage, but ruote runs and happily executes the process. Each process is usually a mix of mostly autonomous participants and then some human intervention if the automation breaks. Other processes are purely human (like web design).</p>
<p>While the service is &#8220;pending&#8221;, now changes are allowed to the service. Instead, when the process completes in ruote there is a callback, a &#8220;webhook&#8221;, that calls back to Rails and activates the service. This &#8220;activation&#8221; is an event defined in the state machine and transitions from &#8220;pending&#8221; to &#8220;active&#8221;. Once a service is active (ie provisioned) the owner of the service is presented with a lot of new options. These options include changing passwords, upgrading &amp; downgrading and even cancelling. Whenever a change is requested by the client we need to fire off another process, and while the process runs we place the service in an &#8220;integrating&#8221; state. While a service is &#8220;integrating&#8221; no changes are allowed, and when the process is done it &#8220;activates&#8221; the service again.</p>
<p>There are plenty of other states and transitions defined, including states for &#8220;suspended&#8221; and &#8220;deleted&#8221; (we don&#8217;t remove data from the database). Each event fires off a different process in ruote, leaving the service with only one decision to make: Which process to I launch under these circumstances?</p>
<p>This combination works extremely well for us since the state machines are very small and lean, and they do exactly what is expected of them: indicate state and handle/prevent transitions between said states. They are not burdened with making business decisions, the handle state. Simple, powerful, effective.</p>
<p><strong>Wow! How do I get going?</strong></p>
<p><strong></strong>Glad you like it, but be careful. As wonderful as the BPM/WFE world sounds, it is a serious leap to take. First off all make sure that your situation necessitates a workflow engine. I&#8217;ve pointed a lot of people to a simpler daemon-kit + AMQP combination for their needs when asking about ruote. In the majority of simple automated tasks a state machine with worker processes will suffice. ruote is all about business processes and automating those processes.</p>
<p>Implementing ruote also brings a lot of changes to the way you develop software. For one, ruote cannot run inside Rails like a normal plugin. It needs one instance to be running, not multiple ones, due to the internal scheduler. We&#8217;re trying to work out away around this, but it&#8217;s on the back burners for now. This means you&#8217;ll be deploying two applications side by side. You&#8217;ll probably also start moving some of your code into gems, so you can share it between ruote and your Rails project.</p>
<p>You&#8217;ll also need to implement a communication channel between your Rails instances and ruote, or use an existing engine &#8220;housing&#8221; like ruote-rest, or give me time to finish ruote-kit. Both ruote-rest and ruote-kit offers a RESTful interface to the engine, allowing all your projects in any language to leverage the power of ruote.</p>
<p><em>State machine versus workflow aside, a major downside to an externalized workflow is the distribution of architecture.  The golden rule for distribution is &#8220;don&#8217;t&#8221;, but that&#8217;s unrealistic, because large, complex systems often require it, and it pays off in the form of serious decoupling in these cases.  So if a workflow engine will be the first distributed step you make then you should think very carefully about what that will cost you.  Not to say don&#8217;t do it, but it&#8217;s not going to fit everywhere, sometimes the &#8220;process&#8221; is simple enough not to warrant a workflow engine this specialized.  There&#8217;s no silver bullet.</em> &#8211; Nic Young, a recent reviewer of ruote.</p>
<p>But sometimes the distribution already has occurred because of a service oriented architecture. It is natural to wrap participants around services, or to use participants as facades to services. SOA is usually thought of as &#8220;in the bank&#8221;, but in our case the applications are already playing with services outside of the building. We had no choice, the distribution was already here. Ruote doesn&#8217;t know much about distribution, it just dispatches to participants and sometimes receives workitems back, whether it happend in process, or on the other side of the world.</p>
<p>Another thing potential pitfall is database access. Personally I use ActiveResource to suck data into my participants on a &#8220;need to know&#8221; basis instead of giving ruote database access and duplicating my models between two projects.</p>
<p>The biggest pitfall of all is learning to write these processes in a concise fashion. The engine and expression language is very very powerful, and you don&#8217;t realise at first how to chain things together. Even now, almost a year later, I find myself refining my process definitions to become leaner and cleaner and easier to maintain. The second biggest pitfall, testing business processes is a pain in the ass. I&#8217;m definitely making some progress on conceptualizing a testing methodology for process definitions, but it is still some way off.</p>
<p><strong>Is it worth all this trouble?</strong></p>
<p><strong></strong>Yes! As far as I know we might have the biggest implementation of ruote at the moment. I have roughly 70 process definitions in production, and about 20 different autonomous participants. As for human participants, it&#8217;s potentially over a thousand, though in ruote terms it is only one, and I map the payload of the workitem back to the user in our systems.</p>
<p>The next best thing that happened to us while implementing business process definitions was it gave us a chance to refactor the business as whole. We&#8217;re a small outfit, less than 20 people, so the excercise went well. In a large organization them impact of business process refactoring, or even just formalizing, is a massive undertaking and increases the number of stakeholders in the project dramatically, use more time, and translates into a higher up front cost.</p>
<p><strong>Looking forward</strong></p>
<p>John is working hard on ruote 2.0, which is a complete rewrite of the 0.9 code base. From the outside it will pretty much look the same, but internally it is a whole new beast. I&#8217;m taking on a complete rewrite of ruote-rest rest, christened ruote-kit, which will become the prefered means of exposing ruote to Rails applications. After a lot of chatting with Andrew Timberlake and others in #ruote and on the mailing list, it&#8217;s become a real neccesity that we provide a framework for testing/specing process definitions. I&#8217;ll tackle this once ruote-kit has made it from vaporware into a polished product, and I&#8217;m thinking ruote-spec will be its name.</p>
<p><strong>Resources</strong><em><br />
</em></p>
<ul>
<li><a href="http://github.com/pluginaweek/state_machine">pluginaweek/state_machine</a></li>
<li><a href="http://ruote.rubyforge.org">ruote</a></li>
<li><a href="http://www.opensourcery.co.za/2009/03/04/ruote-in-20-minutes/">ruote in 20 minutes</a></li>
<li><a href="http://jmettraux.wordpress.com/2009/07/03/state-machine-workflow-engine/">John&#8217;s article</a></li>
<li><a href="http://railsmagazine.com/issues/3">Rails Magazine 3</a></li>
<li><a href="http://en.wikipedia.org/wiki/Finite-state_machine">Wikipedia on Finite State Machines</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/07/06/driving-business-processes-in-ruby/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Cleaning up your act, with a little handsoap</title>
		<link>http://www.opensourcery.co.za/2009/06/12/cleaning-up-your-act-with-a-little-handsoap/</link>
		<comments>http://www.opensourcery.co.za/2009/06/12/cleaning-up-your-act-with-a-little-handsoap/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 18:10:36 +0000</pubDate>
		<dc:creator>Kenneth Kalmer</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[postini]]></category>
		<category><![CDATA[soap]]></category>

		<guid isPermaLink="false">http://www.opensourcery.co.za/?p=213</guid>
		<description><![CDATA[Handsoap is a new, fresh Ruby library for creating SOAP clients. Why am I excited about soap? I&#8217;m not, unless they&#8217;re beautiful. Yet, somewhere along the line you are going to be faced with writing a client for a SOAP service. Whether it is from your suppliers (4 different crap API&#8217;s in my case), or [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-214" title="Dettol Handsoap" src="http://www.opensourcery.co.za/wp-content/uploads/2009/06/dettol-1.jpg" alt="Dettol Handsoap" width="200" height="200" /><a href="http://github.com/troelskn/handsoap">Handsoap</a> is a new, fresh Ruby library for creating<a href="http://en.wikipedia.org/wiki/SOAP"> SOAP</a> clients. Why am I excited about soap? <a href="http://twitter.com/kennethkalmer/status/1096642892">I&#8217;m not</a>, unless they&#8217;re <a href="http://twitter.com/kennethkalmer/status/1307995769">beautiful</a>. Yet, somewhere along the line you are going to be faced with writing a client for a SOAP service. Whether it is from your suppliers (4 different crap API&#8217;s in my case), or just for mashing up data from a rest-less source.</p>
<p>Ruby has very little to offer in terms of SOAP, afaik it only had <a href="http://dev.ctor.org/doc/soap4r/">soap4r</a> until handsoap came along&#8230;</p>
<p><em>BIG DISCLAIMER: This is not a flame war against soap4r, it&#8217;s against SOAP.</em></p>
<p>The authors and contributors have spent a lot of time and effort over the years to build soap4r up to where it is currently. It is a remarkable piece of work, but the cracks are showing. I&#8217;ve spent countless hours digging through the code trying to figure out why my mappings and registeries aren&#8217;t working as expected. You find code working around bugs in Ruby 1.8.2 and 1.8.4, and we&#8217;re all trying to move to 1.9. That is a lot of skeletons to hide&#8230;</p>
<p>It&#8217;s not all doom for soap4r, I&#8217;ve used it to play around with some public API&#8217;s for weather and currency data, and if the API is well defined and leverages SOAP as a protocol, soap4r really rocks. The results of wsdl2ruby is bit tricky to navigate, but mostly you can leave that alone and focus on your code.</p>
<p>But, and there always has to be a but&#8230;</p>
<p>A lot of API&#8217;s are written by people who have no idea what it is like to be on the consuming side of their mess. This is where soap4r falls flat on its face. Take the case of <a href="http://www.postini.com/">Postini</a> and the <a href="http://github.com/kennethkalmer/postini4r-postini">postini</a> gem for instance. The gem was my first gem ever and as far as I&#8217;m considered it was my worst code ever (open source at least). It was an absolute mess, barely worked more than what our systems required, and was not expandable in any way. The root of the problem was not soap4r, but the worst combination of WSDL and PDF docs to land on any developers screen. The documentation and the WSDL don&#8217;t match, not by a long shot, and you have to debug minor issues with wiredumps. I&#8217;ll stop my rant now.</p>
<p><strong>Enter handsoap</strong></p>
<p>As development of <a href="http://www.inx.co.za">our</a> <a href="http://www.ispinabox.co.za/">premier product</a> comes closer to launch, our email systems came under scrutiny and I needed to update the way we interact with Postini through our gem. I couldn&#8217;t, I could barely figure out what I did in the first place. If there was any proper use of the gem outside our company, I would have probably been summoned to criminal court for the injustice I had done in the first release.</p>
<p>So I started over, and I learned about handsoap a couple of weeks ago already.</p>
<p>This was the result in 24 hours:</p>
<pre>
<div id="LC3" class="line">$ git log --stat 2f91d4d6eaa8bd76c188f20929a19e456d1bb52e..HEAD | grep changed</div>

2 files changed, 15 insertions(+), 4 deletions(-)
 1 files changed, 38 insertions(+), 0 deletions(-)
 2 files changed, 282 insertions(+), 1 deletions(-)
 1 files changed, 1 insertions(+), 1 deletions(-)
 12 files changed, 9 insertions(+), 682 deletions(-)
 1 files changed, 1 insertions(+), 0 deletions(-)
 8 files changed, 184 insertions(+), 3883 deletions(-)
 6 files changed, 154 insertions(+), 18 deletions(-)</pre>
<p>That is over 4000 lines of code, gone! Talk about <a href="http://www.flickr.com/photos/jmettraux/3162884472/">beauty soap</a>&#8230;</p>
<p>At the moment the library is a super thin layer on top of the raw API, but it works surprisingly well and easier to comprehend.</p>
<p>Handsoap&#8217;s beauty comes that it leaves you to do all the parsing and prepping of the SOAP requests/responses. At first this sounds daunting, but as you start using it the benefits become very clear and you are in full control of your client. The author published a <a href="http://www.vimeo.com/4813848">video tutorial</a> which shows how to build a weather server client in Rails. It is a very fast paced video, but download a copy and step through it piece by piece.</p>
<p>Handsoap does an excellent job at bringing together <a href="http://curb.rubyforge.org">curb</a> as the HTTP client, and <a href="http://nokogiri.rubyforge.org">Nokogiri</a> for the XML parsing. It delivers, blazingly fast.</p>
<p><strong>Code Teaser</strong></p>
<p>The <a href="http://github.com/kennethkalmer/postini4r-postini/blob/2dfced395e2ac7c479232e96b9a372046ff33329/lib/postini/endpoint_resolver_service.rb">EndpointResolverService</a> in the postini gem is a nice example of a single method service that is used to return another endpoint for subsequent API calls.</p>
<p>At the very least you need a skeleton class that looks something like this:</p>
<pre>EXAMPLE_SERVICE_ENDPOINT = {
  :uri =&gt; 'http://example.org/ws/service',
  :version =&gt; 2
}

class SomeService &lt; Handsoap::Service
  endpoint EXAMPLE_SERVICE_ENDPOINT
  on_create_document do |doc|
    doc.alias 'end', 'https://api-meta.postini.com/api2/endpointresolver'
  end
end</pre>
<p>After that, you&#8217;re pretty much on your own (which turns out to be great).  Troels shows in the video tutorial how to use a clever Java application called <a href="http://www.soapui.org/">soapUI</a> to analyze the WSDL and prepare your request markup and response parsing accordingly. It works like I charm.</p>
<p>I have three other internal soap4r-based gems that work on the worst API&#8217;s you&#8217;ve seen in your life (can you say nusoap?). One of them even lacks a WSDL, and returns serialized PHP data. They were a nightmare to consume, and I&#8217;m looking forward to cleaning them up with handsoap as well.</p>
<p>I&#8217;m hoping this blog post serves as a motivator for you to clean up your (SOAP) act too. I&#8217;ve got two more posts lined up on handsoap, one about mocking your way through writing a SOAP client, and another on using soapUI&#8217;s mock service capabilities.</p>
<p>Until then, please share in the comments your worst Ruby SOAP stories (and go easy on soap4r, it&#8217;s not their fault).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.opensourcery.co.za/2009/06/12/cleaning-up-your-act-with-a-little-handsoap/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
