<?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"
	>

<channel>
	<title>RiboComments</title>
	<atom:link href="http://blog.ribomation.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ribomation.com</link>
	<description>Some random comments on software development</description>
	<pubDate>Thu, 25 Feb 2010 06:14:40 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Cloud Computing and Testing</title>
		<link>http://blog.ribomation.com/2010/02/25/cloud-computing-and-testing/</link>
		<comments>http://blog.ribomation.com/2010/02/25/cloud-computing-and-testing/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 06:14:40 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Speeches]]></category>

		<category><![CDATA[AWS]]></category>

		<category><![CDATA[EC2]]></category>

		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=404</guid>
		<description><![CDATA[Yesterday evening I gave a seminar about Cloud Computing with the bias towards testing. I have uploaded my slides to SlideShare (see below).
Cloud Computing Och Testning   FöR DataföReningen   2010 02 24 Final
View more presentations from Ribomation.

]]></description>
			<content:encoded><![CDATA[<p>Yesterday evening I gave a seminar about Cloud Computing with the bias towards testing. I have uploaded my slides to SlideShare (see below).</p>
<div style="width:425px" id="__ss_3268030"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ribomation/cloud-computing-och-testning-fr-datafreningen-2010-02-24-final" title="Cloud Computing Och Testning   FöR DataföReningen   2010 02 24 Final">Cloud Computing Och Testning   FöR DataföReningen   2010 02 24 Final</a></strong><object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cloudcomputingochtestning-frdatafreningen-2010-02-24final-100224144039-phpapp02&#038;stripped_title=cloud-computing-och-testning-fr-datafreningen-2010-02-24-final" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cloudcomputingochtestning-frdatafreningen-2010-02-24final-100224144039-phpapp02&#038;stripped_title=cloud-computing-och-testning-fr-datafreningen-2010-02-24-final" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ribomation">Ribomation</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2010/02/25/cloud-computing-and-testing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>We got some snow</title>
		<link>http://blog.ribomation.com/2010/02/21/we-got-some-snow/</link>
		<comments>http://blog.ribomation.com/2010/02/21/we-got-some-snow/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 12:51:25 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<category><![CDATA[snow]]></category>

		<category><![CDATA[winter]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=396</guid>
		<description><![CDATA[There has been some amount of snow this winter, here in Sweden. Well, we usually do have snow during the winter, but this amount is plain ridiculous. Who was that guy talking about global warming, was it Al Gone or Al Wrong?






]]></description>
			<content:encoded><![CDATA[<p>There has been some amount of snow this winter, here in Sweden. Well, we usually do have snow during the winter, but this amount is plain ridiculous. Who was that guy talking about global warming, was it Al Gone or Al Wrong?<br />
<br/><br />
<a href="http://www.flickr.com/photos/jens_riboe/4375019531/" title="Mycket snö vintern feb 2010 011 by jens.riboe, on Flickr"><img src="http://farm5.static.flickr.com/4016/4375019531_2994df58a9.jpg" width="500" height="375" alt="Mycket snö vintern feb 2010 011" /></a><br />
<br/><br />
<a href="http://www.flickr.com/photos/jens_riboe/4375017109/" title="Mycket snö vintern feb 2010 003 by jens.riboe, on Flickr"><img src="http://farm5.static.flickr.com/4009/4375017109_9a7b182e34.jpg" width="500" height="375" alt="Mycket snö vintern feb 2010 003" /></a><br />
<br/><br />
<a href="http://www.flickr.com/photos/jens_riboe/4375016029/" title="Mycket snö vintern feb 2010 001 by jens.riboe, on Flickr"><img src="http://farm5.static.flickr.com/4057/4375016029_7617798199.jpg" width="500" height="375" alt="Mycket snö vintern feb 2010 001" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2010/02/21/we-got-some-snow/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Cloud Computing seminar at easyFairs IT-Show</title>
		<link>http://blog.ribomation.com/2010/02/17/cloud-computing-seminar-at-easyfairs-it-show/</link>
		<comments>http://blog.ribomation.com/2010/02/17/cloud-computing-seminar-at-easyfairs-it-show/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 15:23:04 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[AppEngine]]></category>

		<category><![CDATA[AWS]]></category>

		<category><![CDATA[EC2]]></category>

		<category><![CDATA[SaaS]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=394</guid>
		<description><![CDATA[Today, I gave a seminar (in Swedish) about what is Cloud Computing and how to use it. Here are my slides from the presentation.
Vad är Cloud Computing, easyFairs, 17 feb 2010
View more presentations from Ribomation.

]]></description>
			<content:encoded><![CDATA[<p>Today, I gave a seminar (in Swedish) about what is Cloud Computing and how to use it. Here are my slides from the presentation.</p>
<div style="width:425px;text-align:left" id="__ss_3208412"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/ribomation/vad-r-cloud-computing-easyfairs-17-feb-2010" title="Vad är Cloud Computing, easyFairs, 17 feb 2010">Vad är Cloud Computing, easyFairs, 17 feb 2010</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vadrcloudcomputing-freasyfairs-2010-02-17-100217084234-phpapp02&#038;stripped_title=vad-r-cloud-computing-easyfairs-17-feb-2010" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vadrcloudcomputing-freasyfairs-2010-02-17-100217084234-phpapp02&#038;stripped_title=vad-r-cloud-computing-easyfairs-17-feb-2010" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<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/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/ribomation">Ribomation</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2010/02/17/cloud-computing-seminar-at-easyfairs-it-show/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Droid@Screen</title>
		<link>http://blog.ribomation.com/2010/01/21/droidscreen/</link>
		<comments>http://blog.ribomation.com/2010/01/21/droidscreen/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 23:38:43 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[android]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=378</guid>
		<description><![CDATA[I have recently start to learn programming Android. It&#8217;s Java, but the environment is very, very different from ordinary server and/or desktop Java programming. Mostly because the device is limited in all sorts of resources. Therefore, the API puts some burden on the lone hacker.
Anyway, I needed a simple tool to project the screen of [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">I have recently start to learn programming Android. It&#8217;s Java, but the environment is very, very different from ordinary server and/or desktop Java programming. Mostly because the device is limited in all sorts of resources. Therefore, the API puts some burden on the lone hacker.</p>
<p style="text-align: left;">Anyway, I needed a simple tool to project the screen of my HTC Hero device on my PC, for showing it to an audience. I found one such application, but wasn&#8217;t really satisfied with its functionality and because I didn&#8217;t want to step on someones toes by messing around and changing way to much of the code I went for my own solution. My primary objective was to ensure it was operational before next Sunday, when I will need it.</p>
<p style="text-align: left;">Here is how it looks like</p>
<p style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/showing-device.jpg"><img class="size-medium wp-image-380   aligncenter" title="showing-device" src="http://blog.ribomation.com/wp-content/uploads//2010/01/showing-device-300x235.jpg" alt="" width="300" height="235" /></a></p>
<p style="text-align: left;">It is a simple Java Swing application, delivered as an all-inclusive executable JAR file. Therefore, one can launch it simply by double-clicking on the JAR file, or run the following command</p>
<pre style="padding-left: 30px; text-align: left;">java -jar droidAtScreen-0.3.jar</pre>
<p style="text-align: left;">The Droid@Screen JAR file can be found here (pls understand it is <em>alpha</em> software)</p>
<ul style="text-align: left;">
<li><a href="http://lib.ribomation.com/files/droidAtScreen-0.3.jar">droidAtScreen-03.jar</a></li>
</ul>
<h2 style="text-align: left;">Source Code</h2>
<p style="text-align: left;">The source code is open source and I have put all of it to my git repo at Codaset.</p>
<ul style="text-align: left;">
<li><a href="http://codaset.com/jens-riboe/droidatscreen/wiki">Wiki page</a></li>
<li><a href="http://codaset.com/jens-riboe/droidatscreen/source">GIT repo</a></li>
</ul>
<p style="text-align: left;">The project is built using Maven. Before you can compile, you need to install two Android JAR files to your Maven repo. It is the android.jar and the ddmlib.jar files. Use the mvn install-file command. The easiest to get the mvn syntax right is to try compile it and wait for Maven to point out how to run the install-file command.</p>
<h2 style="text-align: left;">Screen-Shots</h2>
<p style="text-align: left;">Here are some more screen-shots.</p>
<h3 style="text-align: left;">Landscape mode</h3>
<p style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/landscape-mode.jpg"><img class="size-medium wp-image-383  aligncenter" title="landscape-mode" src="http://blog.ribomation.com/wp-content/uploads//2010/01/landscape-mode-300x259.jpg" alt="" width="300" height="259" /></a></p>
<h3 style="text-align: left;">Scaled image</h3>
<h3 style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/scaled-down.jpg"><img class="aligncenter size-medium wp-image-385" title="scaled-down" src="http://blog.ribomation.com/wp-content/uploads//2010/01/scaled-down-300x195.jpg" alt="" width="300" height="195" /></a></h3>
<h3 style="text-align: left;">Multiple windows</h3>
<h3 style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/multi-windows.jpg"><img class="aligncenter size-medium wp-image-384" title="multi-windows" src="http://blog.ribomation.com/wp-content/uploads//2010/01/multi-windows-246x300.jpg" alt="" width="246" height="300" /></a></h3>
<h3 style="text-align: left;">Save screenshots</h3>
<h3 style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/saved-screenshot.jpg"><img class="aligncenter size-medium wp-image-386" title="saved-screenshot" src="http://blog.ribomation.com/wp-content/uploads//2010/01/saved-screenshot-300x263.jpg" alt="" width="300" height="263" /></a></h3>
<h3 style="text-align: left;">Setting the path to the ADB executable</h3>
<p style="text-align: left;">The application relies upon the Android Debug Bridge (ADB) application, which will be started unless it&#8217;s already running. So the very first thing Droid@Screen does is to prompt for that path.</p>
<p style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads//2010/01/setting-adb-path.jpg"><img class="size-medium wp-image-387  aligncenter" title="setting-adb-path" src="http://blog.ribomation.com/wp-content/uploads//2010/01/setting-adb-path-300x175.jpg" alt="" width="300" height="175" /></a></p>
<p style="text-align: left;">&#8212;-</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2010/01/21/droidscreen/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Back again</title>
		<link>http://blog.ribomation.com/2010/01/21/back-again/</link>
		<comments>http://blog.ribomation.com/2010/01/21/back-again/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 22:59:45 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=376</guid>
		<description><![CDATA[I have been, sort of, away from this blog for a while. Primarily this comes from me being occupied with lots of other stuff. The past couple of months I have been busy with teaching/training most of the time.
I have given several courses over a broad spectrum. It has been in

Erlang programming
Threads-programming in C++
Java fundamentals
Java [...]]]></description>
			<content:encoded><![CDATA[<p>I have been, sort of, away from this blog for a while. Primarily this comes from me being occupied with lots of other stuff. The past couple of months I have been busy with teaching/training most of the time.</p>
<p>I have given several courses over a broad spectrum. It has been in</p>
<ul>
<li>Erlang programming</li>
<li>Threads-programming in C++</li>
<li>Java fundamentals</li>
<li>Java advanced</li>
<li>Cloud Computing</li>
</ul>
<p>Over Christmas/NewYear I started to learn Android programming, which is really fun.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2010/01/21/back-again/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Posting from my Android phone</title>
		<link>http://blog.ribomation.com/2009/10/03/posting-from-my-android-phone/</link>
		<comments>http://blog.ribomation.com/2009/10/03/posting-from-my-android-phone/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 11:26:59 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<category><![CDATA[android]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=370</guid>
		<description><![CDATA[Just checking how easy it is to write a blog post using my HTC Hero Android phone with wpToGo. Although the typing on the soft keyboard is a pain.
]]></description>
			<content:encoded><![CDATA[<p>Just checking how easy it is to write a blog post using my HTC Hero Android phone with <a title="wpToGo" href="http://www.androlib.com/android.application.com-roundhill-androidwp-wFB.aspx" target="_blank">wpToGo</a>. Although the typing on the soft keyboard is a pain.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/10/03/posting-from-my-android-phone/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Trends in Application Development</title>
		<link>http://blog.ribomation.com/2009/09/13/trends-in-application-development/</link>
		<comments>http://blog.ribomation.com/2009/09/13/trends-in-application-development/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 13:02:09 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Speeches]]></category>

		<category><![CDATA[Consulting]]></category>

		<category><![CDATA[DynamicLanguages]]></category>

		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=343</guid>
		<description><![CDATA[Last Wednesday I gave an internal seminar for a well-known and large Swedish company. The topic was on software development and I had decided to talk about my reflections/observation of software project failures.
The major theme of the speech was the paradox of at one hand we have seen a tremendous improvements of languages, tools and [...]]]></description>
			<content:encoded><![CDATA[<p>Last Wednesday I gave an internal seminar for a well-known and large Swedish company. The topic was on software development and I had decided to talk about my reflections/observation of software project failures.</p>
<p>The major theme of the speech was the paradox of at one hand we have seen a tremendous improvements of languages, tools and methodologies over the last quarter of a century , but on the other hand we haven&#8217;t seen the proportional improvement in application quality and development velocity.</p>
<p>Over the years I have been working in both small organizations and large organizations. Based on my own experience and observations it seems to me that the likelihood of project failure is direct proportional to the size of the organization. One explanation is, of course, that I have been particular unlucky in chosing the right kind of organization. However, my observations tend to be on par with what other old veterans admit over a beer or a cup of coffe.</p>
<p>The first half of the seminar describes briefly some the advances in languages, tools and methodology. That means, the affecting forces of improved software quality and development velocity. The rest of the seminar tries to analyze why, despite of the just mentioned improvements, projects still fail.</p>
<p>One source is the ongoing transformation of the consultancy market. The whole software industri is affected by this transition, even if a single company do not engage consultants. This transition, in turn, is a respons to the ongoing organizational optimizations large corporations exercises in order to achieve lean-and-mean cash flow.</p>
<p>A single consultant is a revenue unit and we can formulate its revenue as product of its utlization and the max revenue.</p>
<div id="attachment_346" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/revenue-of-a-single-consultant.jpg"><img class="size-medium wp-image-346" title="revenue-of-a-single-consultant" src="http://blog.ribomation.com/wp-content/uploads//2009/09/revenue-of-a-single-consultant-300x200.jpg" alt="revenue-of-a-single-consultant" width="300" height="200" /></a><p class="wp-caption-text">revenue-of-a-single-consultant</p></div>
<p>The utilization is a number in [0, 1] and captures in average the net time a consultant produces income. An emperical observation of the utilization (my), is that it is an approximate constant.</p>
<div id="attachment_347" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-1.jpg"><img class="size-medium wp-image-347" title="emperical-observation-1" src="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-1-300x136.jpg" alt="emperical-observation-1" width="300" height="136" /></a><p class="wp-caption-text">emperical-observation-1</p></div>
<p>Two other emperical observations state that the time and team size, is direct proportional to the likelihood that the hourly rate is the same as the market average.</p>
<div id="attachment_348" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-2.jpg"><img class="size-medium wp-image-348 " title="emperical-observation-2" src="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-2-300x143.jpg" alt="emperical-observation-2" width="300" height="143" /></a><p class="wp-caption-text">emperical-observation-2</p></div>
<div id="attachment_349" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-3.jpg"><img class="size-medium wp-image-349" title="emperical-observation-3" src="http://blog.ribomation.com/wp-content/uploads//2009/09/emperical-observation-3-300x122.jpg" alt="emperical-observation-3" width="300" height="122" /></a><p class="wp-caption-text">emperical-observation-3</p></div>
<p>This leads to we can re-formulate the consultancy equation to be a product of the utilization, the market average and the competence coefficient (kappa).</p>
<div id="attachment_350" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/revenue-of-a-single-consultant-refined.jpg"><img class="size-medium wp-image-350" title="revenue-of-a-single-consultant-refined" src="http://blog.ribomation.com/wp-content/uploads//2009/09/revenue-of-a-single-consultant-refined-300x209.jpg" alt="revenue-of-a-single-consultant-refined" width="300" height="209" /></a><p class="wp-caption-text">revenue-of-a-single-consultant-refined</p></div>
<p>Using this, we can formulate the revenue equation for the whole team as a product of the team size, market average, utilization and the team (average) competence.</p>
<div id="attachment_351" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/the-consultancy-equation.jpg"><img class="size-medium wp-image-351" title="the-consultancy-equation" src="http://blog.ribomation.com/wp-content/uploads//2009/09/the-consultancy-equation-300x203.jpg" alt="the-consultancy-equation" width="300" height="203" /></a><p class="wp-caption-text">the-consultancy-equation</p></div>
<p>Based on the consultancy equation, we can then formulate the obvious economic in-equality as the salary plus the cost contribution must be less than the team revenue. This revenue, in turn, is a linear function of the team competence.</p>
<div id="attachment_352" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/the-law-of-gravity-for-consultancy-life.jpg"><img class="size-medium wp-image-352" title="the-law-of-gravity-for-consultancy-life" src="http://blog.ribomation.com/wp-content/uploads//2009/09/the-law-of-gravity-for-consultancy-life-300x172.jpg" alt="the-law-of-gravity-for-consultancy-life" width="300" height="172" /></a><p class="wp-caption-text">the-law-of-gravity-for-consultancy-life</p></div>
<p>I refer to this equation as the <em>Law of Gravity for the Consultancy Life</em>. That means, in a short time frame it is impossible to adapt to changes in market fluctuations, as we have seen during the last year.</p>
<p>The consultancy buyers tend to devaluate, or ignore, the competence coefficient (kappa) and the seller naturally tend to overstate it.</p>
<div id="attachment_354" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/competence-factor.jpg"><img class="size-medium wp-image-354" title="competence-factor" src="http://blog.ribomation.com/wp-content/uploads//2009/09/competence-factor-300x195.jpg" alt="competence-factor" width="300" height="195" /></a><p class="wp-caption-text">competence-factor</p></div>
<p>The involved players perform different compensational strategies to lower the cost and circumvent the consultancy equation. The buyers goes elsewhere, using off-shoring to take advantage of lower salaries. The sellers, employ rookies to take advantage of of low salaries (called <em>junior-shoring</em>). An finally, the consultants themself in order to maintain competence-based salary improvement, has two options to choose between; job-hopping or career change.</p>
<div id="attachment_355" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/compensational-strategies.jpg"><img class="size-medium wp-image-355" title="compensational-strategies" src="http://blog.ribomation.com/wp-content/uploads//2009/09/compensational-strategies-300x198.jpg" alt="compensational-strategies" width="300" height="198" /></a><p class="wp-caption-text">compensational-strategies</p></div>
<p>Over time, this transforms the whole consultancy market. Let&#8217;s look at the food chain of the consultancy market.</p>
<div id="attachment_357" class="wp-caption aligncenter" style="width: 309px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/the-food-chain-of-the-consultancy-market.jpg"><img class="size-medium wp-image-357" title="the-food-chain-of-the-consultancy-market" src="http://blog.ribomation.com/wp-content/uploads//2009/09/the-food-chain-of-the-consultancy-market-299x191.jpg" alt="the-food-chain-of-the-consultancy-market" width="299" height="191" /></a><p class="wp-caption-text">the-food-chain-of-the-consultancy-market</p></div>
<p>At the top we have the traditional consultancy company that deliver a defined result (<em>solution</em>) for a defined amount of money. The trick in pricing, is of course to add some margin to account for unknowns. Based on this margin, the hourly rate might seem too high for many buyers. The hourly rate is a very concrete factor, but delivered quality on the other hand a very fluffy factor. The former is imminent before the project start, but the latter is only possible to measure towards the end of the project. Therefore, buyers tend to ignore the latter and goes for companies that offer lower hourly rates.</p>
<p>At the bottom of the food chain, we have the new kind of consultancy <em>brokerage </em>firms, that can offer low hourly rates because they have zero overhead costs for non-enganged personell (people on the bench).</p>
<p>Squeezed in between we have the former solutions delivering companies, that nowadays tries to survive with pure <em>staffing </em>business. However, in the long haul they cannot compete with pure brokerage companies.</p>
<p>The trend in the industry is clearly towards lower hourly rates and therefore towards brokerage consultancy companies. But how does that affect the long term software quality?</p>
<p>To understand that, we have to look at the effective business model of traditional and new consultancy companies. With the word <em>effective</em>, I mean what happens in the real and not what people say.</p>
<div id="attachment_359" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/effective-business-model.jpg"><img class="size-medium wp-image-359" title="effective-business-model" src="http://blog.ribomation.com/wp-content/uploads//2009/09/effective-business-model-300x194.jpg" alt="effective-business-model" width="300" height="194" /></a><p class="wp-caption-text">effective-business-model</p></div>
<p>When the business focus is on delivering results, the sales people says &#8220;<em>we need to sell more projects</em>&#8221; and the technical people responds with &#8220;<em>sure, if we work smarter and faster using modern tools and languages, we can complete projects in short time</em>&#8220;. On the other hand, if the effective business model is on delivering hours, the sales people says &#8220;<em>sell more hours</em>&#8221; and the technical people responds &#8220;<em>ok, if we introduce more bugs we can stay longer at the same project</em>&#8220;.</p>
<p>Of course, nobody ever tell you this, but as a technical consultant you feel this very concrete. For example, the sales people tell you that they have sold you for 1000 hours. Then you ask what you are supposed to do and you get an answer similar to &#8220;<em>I don&#8217;t know and I don&#8217;t care, just sit on your ass the amount of time we have sold you for and try do look busy</em>&#8220;.</p>
<p>So, what is the impact of competence development for the single consultant in these two opposing business models?</p>
<div id="attachment_360" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/impact-of-competence-development.jpg"><img class="size-medium wp-image-360" title="impact-of-competence-development" src="http://blog.ribomation.com/wp-content/uploads//2009/09/impact-of-competence-development-300x179.jpg" alt="impact-of-competence-development" width="300" height="179" /></a><p class="wp-caption-text">impact-of-competence-development</p></div>
<p>Clearly, for hour delivering businesses being a better software developer is counter productive. It is considered a problem if you complete the task in half of the time you have been sold for.</p>
<p>In order to understand how this affect the software quality over time, we need to get familiar with two components. The first is the <em>collective project knowledge</em>, which is composed of both formal (written) documentation and informal (invisible) knowledge. The problems of this are the accuracy of the former and the propagation of the latter. We refer to this as project knowledge transfer. However, knowledge transfer takes time and therefore steals time and concentration from software development.</p>
<p>The second component is the <em>draining vs. contribution time</em> for a single project member. Every new member need to acquire the collective project knowledge in order to contribute to project. Before that happens, the person is draining the project instead, measured in time and cost.</p>
<div id="attachment_362" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/project-contribution-curve.jpg"><img class="size-medium wp-image-362" title="project-contribution-curve" src="http://blog.ribomation.com/wp-content/uploads//2009/09/project-contribution-curve-300x143.jpg" alt="project-contribution-curve" width="300" height="143" /></a><p class="wp-caption-text">project-contribution-curve</p></div>
<p>The draining time is always a positve non-negative number and is affected by the amount of invisble but necessary project knowledge.  However, knowledge-level, experience and professional seniority is reversely proportional to the draining time.</p>
<p>What happens is that for a long term project, which typically is the case for large organizations, and if the staff turnover rate is too high, the average contribution time becomes too low. If the non-contribution period starts to take a significant portion of the project time, the project is gradually loosing its collective knowledge. At the end, &#8220;<em>nobody has a clue</em>&#8220;.</p>
<div id="attachment_364" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/accumulated-project-knowledge.jpg"><img class="size-medium wp-image-364" title="accumulated-project-knowledge" src="http://blog.ribomation.com/wp-content/uploads//2009/09/accumulated-project-knowledge-300x139.jpg" alt="accumulated-project-knowledge" width="300" height="139" /></a><p class="wp-caption-text">accumulated-project-knowledge</p></div>
<p>The sad fact is that individuals and organizations has opposing ambitions, both trying to get <em>more bang for the bucks</em>.</p>
<div id="attachment_365" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.ribomation.com/wp-content/uploads//2009/09/opposing-ambitions.jpg"><img class="size-medium wp-image-365" title="opposing-ambitions" src="http://blog.ribomation.com/wp-content/uploads//2009/09/opposing-ambitions-300x192.jpg" alt="opposing-ambitions" width="300" height="192" /></a><p class="wp-caption-text">opposing-ambitions</p></div>
<p>In one direction goes the technological evolution with higher abstraction levels and more involvment required and therefore higher competence required. In the opposite direction goes, the organizational evolution with standardization and policies which requires low involment and therefore the tendency to completely ignore the competency level.</p>
<p>The net effect, can we all read abount in the news papers; a never ending series of failed software projects.</p>
<p>You can view the whole slide deck at SlideShare</p>
<div id="__ss_1988882" 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="Trends In Application Development" href="http://www.slideshare.net/ribomation/trends-in-application-development">Trends In Application Development</a><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=trendsinapplicationdevelopment-090912115512-phpapp02&amp;stripped_title=trends-in-application-development" /><embed type="application/x-shockwave-flash" width="425" height="355" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=trendsinapplicationdevelopment-090912115512-phpapp02&amp;stripped_title=trends-in-application-development" allowscriptaccess="always" allowfullscreen="true"></embed></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/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/ribomation">Ribomation</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/09/13/trends-in-application-development/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Seminars in Cloud Computing and Groovy&#038;Grails</title>
		<link>http://blog.ribomation.com/2009/09/08/seminars-in-cloud-computing-and-groovygrails/</link>
		<comments>http://blog.ribomation.com/2009/09/08/seminars-in-cloud-computing-and-groovygrails/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 19:54:08 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Speeches]]></category>

		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=340</guid>
		<description><![CDATA[Today I gave two seminars (2 hours each) in Stockholm. The first, before lunch, was about Cloud Computing and the second, after lunch, was an gentle introduction to Groovy and Grails.
Here a the slides PDF (in Swedish)

Vad är Cloud Computing?
Vad är Groovy och Grails?

I will repeat these seminars in Gothenburg on Thursday.
Tomorrow (Wednesday) I will [...]]]></description>
			<content:encoded><![CDATA[<p>Today I gave two seminars (2 hours each) in Stockholm. The first, before lunch, was about Cloud Computing and the second, after lunch, was an gentle introduction to Groovy and Grails.</p>
<p>Here a the slides PDF (in Swedish)</p>
<ul>
<li><a href="http://video.ribomation.com/Vad-ar-Cloud-Computing-sep-2009.pdf">Vad är Cloud Computing?</a></li>
<li><a href="http://video.ribomation.com/Vad-ar-Groovy-och-Grails-sep-2009.pdf">Vad är Groovy och Grails?</a></li>
</ul>
<p>I will repeat these seminars in Gothenburg on Thursday.</p>
<p>Tomorrow (Wednesday) I will give a company internal seminar regarding trends in software development.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/09/08/seminars-in-cloud-computing-and-groovygrails/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mail migration</title>
		<link>http://blog.ribomation.com/2009/09/03/mail-migration/</link>
		<comments>http://blog.ribomation.com/2009/09/03/mail-migration/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 08:27:01 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<category><![CDATA[Add new tag]]></category>

		<category><![CDATA[SmoothWall]]></category>

		<category><![CDATA[Ubuntu Server]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=337</guid>
		<description><![CDATA[As a response to my crashed firewall, I decided to retire my hobby mail server running Postfix/Dovecot on Ubuntu Server. Instead I have decided to join the masses and go for a hosted exchange service instead. For a die-hard Linux freak as yours truly, this sucks. However, on the flip side, I gain better reliability [...]]]></description>
			<content:encoded><![CDATA[<p>As a response to my crashed firewall, I decided to retire my hobby mail server running Postfix/Dovecot on Ubuntu Server. Instead I have decided to join the masses and go for a hosted exchange service instead. For a die-hard Linux freak as yours truly, this sucks. However, on the flip side, I gain better reliability and set of services, such as beside of synching mail to my Android HTC Hero mobile, I also get calendar and contacts.</p>
<p>Before summer I was looking intensively for a open source version of calendaring and contacts that allowed me to synch to a mobile phone. I tried eGroupware with Funambole client. But there were allways some part that didn&#8217;t work, whever I got something to work.</p>
<p>Now, when I&#8217;m on the move frequently I need a working solution for mobile mail/calendar/contacts that also works with a desktop client. Google mail wasn&#8217;t an option becuase they doesn&#8217;t seem to have a professional solution for a small-business.</p>
<p>As long as it comes to pure mail management using the postfix/dovecot/spam-assasin/postgray combo, it works flawlessly. But finding a decent (open source) calendar and contacts server, accessing them over HTTPS from a hotel room or via a mobile phone, is not possible.</p>
<p>Running a SOHO server(s) has its moments, when the broadband connection goes down, when the home assembled firewall crashes or just the cat plays with a cable that happens to be cord to the ADSL modem. Last summer (2008), the firewall crashed due to iover-heating. It was an old PC baught for my son when we were living in London 2001. The problem was, me and my wife was at the Canary Islands for another two weeks. After that I got some new hardware from a local computer store and it lasted for a year. The firewall software I&#8217;m using is Smoothwall, which used to be a very decent OS-based firewall. However, they haven&#8217;t upgraded the bundled drivers for many years, which results in it&#8217;s not able to install on modern hardware.</p>
<p>When the firewall crashed recently I bought a brand-new (cheap) PC, just to discover for the second time that Smoothwall doesn&#8217;t install on contemporary hardware. I wasn&#8217;t particulary tempted to build my own distribution with the appropriate drivers, at the same time I was cut-off from the net. So, I found a spare machine from 2004, which allowed installation of Smoothwall. But, as I said in the beginning of this post, I will not wait for this junk to crash, so I have migrated the mail handling elsewhere.</p>
<p>The next step will be to migrate the webs {www, blog, lib}.ribomation.com. I will write another post, when it&#8217;s done. Probably it will take some time, because I will be on the move for several weeks during September and October. Next week I will run a series of seminars on Cloud Computing, Groovy &amp; Grails and trends in Application Development. The following weeks I will teach Erlang, Real-time Systems Programming in C++, more seminars and then more Erlang and RT++. It goes on like this until November. It&#8217;s fun and intensive.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/09/03/mail-migration/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Crashed firewall</title>
		<link>http://blog.ribomation.com/2009/08/23/crashed-firewall/</link>
		<comments>http://blog.ribomation.com/2009/08/23/crashed-firewall/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 23:44:17 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<category><![CDATA[Erlang]]></category>

		<category><![CDATA[HomeServer]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=335</guid>
		<description><![CDATA[Last week I was away from home/office the whole week giving for the first time my Erlang course in Linköping (200 km south of Stockholm). A day after my departure, my firewall crashed due to some hardware failure. It has been very frustrating &#8216;watching&#8217; from a distant position no access to either this blog, my [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I was away from home/office the whole week giving for the first time my Erlang course in Linköping (200 km south of Stockholm). A day after my departure, my firewall crashed due to some hardware failure. It has been very frustrating &#8216;watching&#8217; from a distant position no access to either this blog, my company web and the mail. Finally, after a lot of work during Saturday I got a replacement maching up and running again. Sorry for being offline for such a long time.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/08/23/crashed-firewall/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Generating prime numbers with Erlang and Java</title>
		<link>http://blog.ribomation.com/2009/08/06/generating-prime-numbers-with-erlang-and-java/</link>
		<comments>http://blog.ribomation.com/2009/08/06/generating-prime-numbers-with-erlang-and-java/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 11:54:11 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Erlang]]></category>

		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=314</guid>
		<description><![CDATA[During my work with the course-ware of a new Erlang course, I experimented with one of the programming assignments to compare the threading performance of Erlang versus Java. The assignment is one of the classical programs from teaching concurrent programming: How to generate prime numbers using a pipeline of sieve threads. The algorithm is based [...]]]></description>
			<content:encoded><![CDATA[<p>During my work with the course-ware of a new Erlang course, I experimented with one of the programming assignments to compare the threading performance of Erlang versus Java. The assignment is one of the classical programs from teaching concurrent programming: How to generate prime numbers using a pipeline of sieve threads. The algorithm is based on the <a href="http://en.wikipedia.org/wiki/Eratosthenes_Sieve" target="_blank">Sieve of Eratosthenes</a>, but modified to use threads instead.</p>
<h2>The primes in [2..N]</h2>
<p>An initial version sends the numbers [3..N] to the first sieve thread representing the prime number 2. Each seive thread receives a number and checks if it&#8217;s divisable with the prime number of the sieve. If not, the number is forward to the next sieve. If there is no next seive, it is created using the current number as its prime number. That means, we have a pipeline of sieve threads that grows with each prime number found. The initial version of the solution finds all prime numbers in the given interval [2..N]. When the generator has sent all numbers, it sends a &#8216;done&#8217; marker, which is forwarded throughout the pipe and each sieve terminates.</p>
<p>Here are the relevant portions of the code (the full source code can be found at the end of this blog post)</p>
<pre>generator(N, interval, Stats) -&gt;
  Next = sieve_create(1, 0, 2, stats_create(Stats)),
  iterate(3, N, send_and_forget(Next));

send_and_forget(Next) -&gt;
  fun
     (done)   -&gt; Next ! {done, []}, done;
     (Number) -&gt; Next ! Number
  end.

iterate(N, N, Send) -&gt;
  Send(done);
iterate(Number, MaxNumber, Send) when Number &lt; MaxNumber -&gt;
  case Send(Number) of
    done   -&gt; iterate(MaxNumber , MaxNumber, Send);
    Number -&gt; iterate(Number + 1, MaxNumber, Send)
  end.

sieve_create(Ordinal, MaxOrdinal, Prime, Stats) -&gt;
  spawn(?MODULE, sieve_init, [Ordinal, MaxOrdinal, Prime, stats_create(Stats)]).

sieve_init(Ordinal, MaxOrdinal, Prime, Stats) -&gt;
  StatsNew = stats_print(Ordinal, Prime, Stats),
  sieve_loop(Ordinal, MaxOrdinal, Prime, none, StatsNew).

sieve_loop(Ordinal, MaxOrdinal, Prime, none, Stats) -&gt;
  receive
    {done, PrimeNumbers}  -&gt;
      generator ! {done, [Prime | PrimeNumbers]};
    Number when (Number rem Prime) == 0 -&gt;
      sieve_loop(Ordinal, MaxOrdinal, Prime, none, Stats);
    Number when (Number rem Prime) /= 0 -&gt;
      Next = sieve_create(Ordinal+1, MaxOrdinal, Number, Stats),
      sieve_loop(Ordinal, MaxOrdinal, Prime, Next, Stats)
  end;
sieve_loop(Ordinal, MaxOrdinal, Prime, Next, Stats) -&gt;
  receive
    {done, PrimeNumbers} -&gt;
      Next ! {done, [Prime | PrimeNumbers]};
    Number when (Number rem Prime) == 0 -&gt;
      sieve_loop(Ordinal, MaxOrdinal, Prime, Next, Stats);
    Number when (Number rem Prime) /= 0  -&gt;
      Next ! Number,
      sieve_loop(Ordinal, MaxOrdinal, Prime, Next, Stats)
  end.</pre>
<p>The drawback of this solution from a concurrency point of view is that it does not create particular many concurrent threads. At the time the generator sends the done marker, the pipeline is still under construction. Here is snippet showing it in action</p>
<pre>$ erl -noshell -pa target/beam -run prime exe 10000 interval stats
1) 2 [processes 1/1, messages 18/18]
2) 3 [processes 2/2, messages 31/31]
3) 5 [processes 3/3, messages 29/31]
4) 7 [processes 4/4, messages 31/31]
5) 11 [processes 5/5, messages 31/31]
. . .
38) 163 [processes 38/38, messages 23/31]
. . .
72) 359 [processes 72/72, messages 31/31]
73) 367 [processes 58/72, messages 31/31]
. . .
728) 5507 [processes 31/72, messages 31/120]
. .
1226) 9941 [processes 1/72, messages 4/349]
1227) 9949 [processes 1/72, messages 3/349]
1228) 9967 [processes 1/72, messages 2/349]
1229) 9973 [processes 1/72, messages 1/349]
Prime Numbers [2,3,5,7,11,13,17,...,9941,9949,9967,9973]
$</pre>
<p>In this case, I&#8217;m computing the prime numbers in the interval [2..10000]. Each line shows the ordinal number, the prime number and some stats. The stats shows the actual and maximum number of threads created and the length of the input queue of each sieve. At most 72 concurrent threads are running at the same time and most of the time essentially fewer threads.</p>
<h2>The first N primes</h2>
<p>More interesting is generating the N first prime numbers, because it will create N threads as well. That means I can study the threading and messaging performance. Here are the missing portions of the program</p>
<pre>run(N, Mode, Stats) -&gt;
  register(generator, self()),
  generator(N, Mode, Stats),
  Result = receive
    {done, PrimeNumbers} -&gt; lists:reverse(PrimeNumbers)
  end,
  unregister(generator),
  Result.

generator(N, count, Stats) -&gt;
    Next = sieve_create(1, N, 2, stats_create(Stats)),
    iterate(3, infinity, send_and_receive(Next)).

send_and_receive(Next) -&gt;
    fun
       (done)   -&gt; done;
       (Number) -&gt;
            receive
                done    -&gt; Next ! {done, []}, done
                after 0 -&gt; Next ! Number
            end
    end.

sieve_loop(MaxOrdinal, MaxOrdinal, Prime, none, Stats) -&gt;
    receive
        {done, PrimeNumbers} -&gt;
            generator ! {done, [Prime | PrimeNumbers]};
        _Number -&gt;
            sieve_loop(MaxOrdinal, MaxOrdinal, Prime, none, Stats)
    end;</pre>
<p>However, I decided to re-write the program to avoid the list reverse in run/3, but also to make the stats more accurate. I show you the relevant portions of the new version below. The complete source can be found at the end of this post.</p>
<pre>generator_loop(Number, Next) -&gt;
    receive
        done -&gt;
            Next ! {done, self()},
            unregister(generator),
            receive
                {result, Primes, StatsLst} -&gt; {Primes, StatsLst}
            end
        after 0 -&gt;
            Next ! Number,
            generator_loop(Number + 1, Next)
    end.

sieve_create(Prime, Ordinal, MaxOrdinal, Verbose) -&gt;
    print_progress(Prime, Ordinal, Verbose),
    check_if_last(Ordinal, MaxOrdinal),
    spawn(?MODULE, sieve_loop, [Prime, Ordinal, MaxOrdinal, none, Verbose, stats_create()]).

check_if_last(N, N) -&gt; generator ! done;
check_if_last(N, M) when N &lt; M -&gt; ok.

sieve_loop(Prime, Ordinal, MaxOrdinal, Next, Verbose, Stats) when Ordinal &lt; MaxOrdinal -&gt;
    receive
        Number when (Number rem Prime) == 0 -&gt;
            sieve_loop(Prime, Ordinal, MaxOrdinal, Next, Verbose, stats_update(Stats));

        Number when (Number rem Prime) /= 0 -&gt;
            NextNew = case Next of
                none -&gt; sieve_create(Number, Ordinal+1, MaxOrdinal, Verbose);
                Pid  -&gt; Pid ! Number, Pid
            end,
            sieve_loop(Prime, Ordinal, MaxOrdinal, NextNew, Verbose, stats_update(Stats));

        {done, Prev} -&gt;
            Next ! {done, self()},
            receive
                {result, Primes, StatsLst} -&gt;
                    Prev ! {result, [Prime | Primes], [stats_id(Stats, Ordinal, Prime) | StatsLst]}
            end
    end;
sieve_loop(Prime, MaxOrdinal, MaxOrdinal, _Next, _Verbose, Stats) -&gt;
    receive
        Number when is_integer(Number) -&gt;
            sieve_loop(Prime, MaxOrdinal, MaxOrdinal, none, none, stats_update(Stats));

        {done, Prev} -&gt;
            Prev ! {result, [Prime], [stats_id(Stats, MaxOrdinal, Prime)]}
    end.</pre>
<p>When the last sieve is created (Ordinal == MaxOrdinal) it sends the done marker to the generator. The generator the sends its own PID to its next seive and each sieve forwards the done marker together with its PID. When the done marker hits the last seive, it creates the last item of the resulting prime number list and sends it to its predecessor. Each sieve prepends its own prime and finally the complete list of prime numbers arrives to the generator. Finally, we are done with the preludium of this blog post. Let&#8217;s study its execution.</p>
<h2>Running the Erlang version</h2>
<p>Here is a first run with the dedicated &#8216;N first primes&#8217; version.</p>
<pre>jens@spooky:~/workspace/Prime$ /usr/lib/erlang/bin/erl -pa target/beams/
Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:2] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5  (abort with ^G)
1&gt; prime:run(10).
1) 2
2) 3
3) 5
4) 7
5) 11
6) 13
7) 17
8 ) 19
9) 23
10) 29
Elapsed time 0.002 secs
[2,3,5,7,11,13,17,19,23,29]
2&gt; prime:run(1000).
1) 2
2) 3
3) 5
. . .
999) 7907
1000) 7919
Elapsed time 5.886 secs
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
 79,83,89,97,101,103,107,109|...]
3&gt;</pre>
<p>Spawning 1000 threads in Erlang is a no-brainer and we can see it performs pretty good. The program also collects some statistics of each sieve input queue and writes it out to a CSV file. Here comes the interesting part</p>
<table style="border-collapse: collapse; text-align: right; height: 442px;" border="0" cellspacing="0" cellpadding="0" width="253"><col style="width: 52pt;" width="69"></col> <col style="width: 23pt;" width="31"></col> <col style="width: 44pt;" width="58"></col> <col style="width: 25pt;" width="33"></col> <col style="width: 33pt;" width="44"></col></p>
<tbody>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt; width: 52pt;" width="69" height="21"><strong>Thread</strong></td>
<td style="width: 23pt;" width="31"><strong>Min</strong></td>
<td style="width: 44pt;" width="58"><strong>Average</strong></td>
<td style="width: 25pt;" width="33"><strong>Max</strong></td>
<td style="width: 33pt;" width="44"><strong>Count</strong></td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">1-2</td>
<td align="right">0</td>
<td align="right">37</td>
<td align="right">147</td>
<td align="right">86410</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">2-3</td>
<td align="right">0</td>
<td align="right">11</td>
<td align="right">36</td>
<td align="right">43204</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">3-5</td>
<td align="right">0</td>
<td align="right">8</td>
<td align="right">33</td>
<td align="right">28802</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">4-7</td>
<td align="right">0</td>
<td align="right">6</td>
<td align="right">35</td>
<td align="right">23041</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">5-11</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">40</td>
<td align="right">19749</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">6-13</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">40</td>
<td align="right">17953</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">7-17</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">41</td>
<td align="right">16572</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">8-19</td>
<td align="right">0</td>
<td align="right">4</td>
<td align="right">42</td>
<td align="right">15597</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">9-23</td>
<td align="right">0</td>
<td align="right">4</td>
<td align="right">42</td>
<td align="right">14776</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">10-29</td>
<td align="right">0</td>
<td align="right">4</td>
<td align="right">52</td>
<td align="right">14137</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">11-31</td>
<td align="right">0</td>
<td align="right">4</td>
<td align="right">52</td>
<td align="right">13655</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">. . .</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">993-7867</td>
<td align="right">0</td>
<td align="right">13</td>
<td align="right">65</td>
<td align="right">7410</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">994-7873</td>
<td align="right">0</td>
<td align="right">12</td>
<td align="right">42</td>
<td align="right">7409</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">995-7877</td>
<td align="right">0</td>
<td align="right">12</td>
<td align="right">51</td>
<td align="right">7408</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">996-7879</td>
<td align="right">0</td>
<td align="right">12</td>
<td align="right">52</td>
<td align="right">7407</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">997-7883</td>
<td align="right">0</td>
<td align="right">12</td>
<td align="right">52</td>
<td align="right">7406</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">998-7901</td>
<td align="right">0</td>
<td align="right">11</td>
<td align="right">42</td>
<td align="right">7405</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">999-7907</td>
<td align="right">0</td>
<td align="right">11</td>
<td align="right">67</td>
<td align="right">7404</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl63" style="height: 15.75pt;" height="21">1000-7919</td>
<td align="right">0</td>
<td align="right">10</td>
<td align="right">28</td>
<td align="right">7403</td>
</tr>
</tbody>
</table>
<p>We can see that at most 147 messages was in the message queue of sieve(1,2), but in average the queue length is way more moderate, fluctuating around 10. Let&#8217;s do another round, this time with 10.000 threads, before starting the discussion.</p>
<pre>$ erl -pa target/beams/
Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:2] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5  (abort with ^G)
1&gt; prime:run(10000, no).
Elapsed time 272.172 secs
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
 79,83,89,97,101,103,107,109|...]
2&gt;
Here are the message queue stats:</pre>
<table style="border-collapse: collapse; text-align: right; height: 357px;" border="0" cellspacing="0" cellpadding="0" width="307"><col style="width: 68pt;" width="91"></col> <col style="width: 48pt;" span="4" width="64"></col></p>
<tbody>
<tr style="height: 15.75pt;" height="21">
<td class="xl66" style="height: 15.75pt; width: 68pt;" width="91" height="21"><strong>Thread</strong></td>
<td class="xl66" style="width: 48pt;" width="64"><strong>Min</strong></td>
<td class="xl66" style="width: 48pt;" width="64"><strong>Average</strong></td>
<td class="xl66" style="width: 48pt;" width="64"><strong>Max</strong></td>
<td class="xl66" style="width: 48pt;" width="64"><strong>Count</strong></td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">1-2</td>
<td align="right">0</td>
<td align="right">42</td>
<td align="right">803</td>
<td align="right">483183</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">2-3</td>
<td align="right">0</td>
<td align="right">12</td>
<td align="right">30</td>
<td align="right">241591</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">3-5</td>
<td align="right">0</td>
<td align="right">8</td>
<td align="right">33</td>
<td align="right">161060</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">4-7</td>
<td align="right">0</td>
<td align="right">7</td>
<td align="right">28</td>
<td align="right">128847</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">5-11</td>
<td align="right">0</td>
<td align="right">6</td>
<td align="right">28</td>
<td align="right">110440</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">6-13</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">28</td>
<td align="right">100400</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">7-17</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">28</td>
<td align="right">92677</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td class="xl65" style="height: 15.75pt;" height="21">8-19</td>
<td align="right">0</td>
<td align="right">5</td>
<td align="right">28</td>
<td align="right">87225</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">. . .</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9994-104693</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30258</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9995-104701</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30257</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9996-104707</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30256</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9997-104711</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30255</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9998-104717</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30254</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">9999-104723</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30253</td>
</tr>
<tr style="height: 15.75pt;" height="21">
<td style="height: 15.75pt;" height="21">10000-104729</td>
<td align="right">0</td>
<td align="right">3</td>
<td align="right">20</td>
<td align="right">30252</td>
</tr>
</tbody>
</table>
<p>Even this time we can see that the message queue length is very moderate. In both cases the first sieve receives the major hit of messages and after that for the rest of the pipeline, the queue length is around 10 or less.</p>
<p>If you knew the concurrency model of Erlang, but not its implementation, this is suspicious. Erlang messages are sent by asynchronous message passing, which means that a thread loops and sends an unbounded number of messages until the thread is put on hold for a while (i.e., it runs out of reduction ticks).</p>
<p>What we should have seen; is a large amount of messages in the beginning of the pipeline. However, that doesn&#8217;t happen because the Erlang runtime system takes care of the fine-tuning of its thread scheduling. A thread is allowed to perform a certain number of reductions (e.g. function calls and pattern matching) before it is put on hold and inserted last in the ready-queue. This queue contains all threads that do not wait for some condition, like a receive statement. So instead of running for a certain amount of time it runs for a certain number of operations. The consequence is paramount; a thread cannot send too many messages before the recipient has a chance to &#8216;receive&#8217; them. In addition, the Erlang runtime system tries to level the send rate so the recipient&#8217;s message queue doesn&#8217;t get flooded. To fully understand this and fully appreciate it, let&#8217;s study the same program in Java.</p>
<h2>The Java version</h2>
<p>I will just show you fragments of the Java code. You can find all sources at the end of this post.</p>
<h3>Class Sieve</h3>
<pre>public class Sieve extends Thread {
    public static int               maxOrdinal = 0;
    private int                     ordinal, prime;
    private Sieve                   next;
    private LinkedList&lt;Integer&gt;     numbersInput = new LinkedList&lt;Integer&gt;();
    private volatile boolean        running = true;

    public Sieve(int ordinal, int prime) {
        this.ordinal  = ordinal;
        this.prime    = prime;
        start();
    }

    public void run() {
        if (ordinal == maxOrdinal) {Generator.done();}

        int n;
        while ((n = getNumber()) &gt; 0) {
            if (ordinal == maxOrdinal) continue;
            if (n % prime != 0) {
                if (next == null) {
                    next = new Sieve(ordinal+1, n);
                } else {
                    next.putNumber(n);
                }
            }
        }
        if (next != null) next.putNumber(0);
    }

    public synchronized void putNumber(int n) {
        if (n &gt; 0) {
            numbersInput.addLast(n);
        } else {
            running = false;
        }
        notify();
    }

    private int getNumber() {
        int n;
        synchronized (this) {
            while (running &amp;&amp; numbersInput.isEmpty()) {
                try{ wait(); }catch (InterruptedException e) {}
            }
            n = running ? numbersInput.removeFirst() : 0;
        }
        return n;
    }
}</pre>
<p>Inside the run() method we recognizes the sieve algorithm. Java do have support for message passing, so we have to implement it. I&#8217;m using a linked-list and synchronized methods. The public putNumber() method is called by the predecessor and inserts a message last in the queue/list. The private getNumber() is used by the sieve loop to fetch the next number. If the input queue is empty, it waits until notify() is called in putNumber(). The last sieve calls the done() method of the generator, which sends &#8216;0&#8242; to all sieves.</p>
<h3>Class Generator</h3>
<pre>public class Generator extends Thread {
    private static volatile boolean     running = true;
    private Sieve                       next = new Sieve(1, 2);

    public void run() {
        for (int n = 3; running; ++n) {
            next.putNumber(n);
        }
        next.putNumber(0);
    }
    public static void done() {running = false;}
    //. . .
}</pre>
<p>I have remove some code from the generator, but the important part is retained. In the run() method, the generator thread sends an unbounded sequence of numbers to its successor. When the last seive calls done() it breaks the loop and sends &#8216;0&#8242;. You might wonder why done() is not synchronized. That is because it&#8217;s exactly one thread that will call done() and it&#8217;s harmless to assign &#8216;running&#8217; a new value.</p>
<h2>Running the Java version</h2>
<p>Let&#8217;s start with an easy one; the 100 first prime numbers.</p>
<pre>$ java -cp target/classes/ Prime -y 0 -b 0 -n 100
1) 2
2) 3
3) 5
4) 7
. . .
75) 379
76) 383
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Thread-1" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space
	at java.lang.Integer.valueOf(Integer.java:601)
	at Sieve.putNumber(Sieve.java:56)
	at Sieve.run(Sieve.java:39)
$</pre>
<p>Whoa!!! It crashed after just 76 threads! Can this be true? What is happening? I managed to run it to completion, when starting a second time.</p>
<pre>$ java -cp target/classes/ Prime -y 0 -b 0 -n 100
1) 2
2) 3
. . .
99) 523
100) 541
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541]
Elapsed time: 35.872 secs
$</pre>
<p>Hmmm, the Erlang version running up to 1000 sieves took 5 secs and the Java version running a just up to 100 threads took 35 secs. Let&#8217;s see what is going on in the Java program and the true side of asynchronous message passing - as it had been seen in Erlang if not its runtime system had been so helpful.</p>
<table style="border-collapse: collapse; width: 195pt; text-align: right;" border="0" cellspacing="0" cellpadding="0" width="259"><col style="width: 41pt;" width="54"></col> <col style="width: 26pt;" width="35"></col> <col style="width: 44pt;" width="58"></col> <col style="width: 42pt;" span="2" width="56"></col></p>
<tbody>
<tr style="height: 15pt;" height="20">
<td class="xl64" style="height: 15pt; width: 41pt;" width="54" height="20"><strong>Thread</strong></td>
<td class="xl65" style="width: 26pt;" width="35"><strong>Min</strong></td>
<td class="xl65" style="width: 44pt;" width="58"><strong>Average</strong></td>
<td class="xl65" style="width: 42pt;" width="56"><strong>Max</strong></td>
<td class="xl65" style="width: 42pt;" width="56"><strong>Count</strong></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">1-2</td>
<td align="right">5326</td>
<td align="right">2463146</td>
<td align="right">5983878</td>
<td align="right">2584638</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">2-3</td>
<td align="right">0</td>
<td align="right">19077</td>
<td align="right">128598</td>
<td align="right">1292319</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">3-5</td>
<td align="right">0</td>
<td align="right">9645</td>
<td align="right">55008</td>
<td align="right">851453</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">4-7</td>
<td align="right">0</td>
<td align="right">8728</td>
<td align="right">41121</td>
<td align="right">681161</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">5-11</td>
<td align="right">0</td>
<td align="right">7216</td>
<td align="right">38952</td>
<td align="right">583852</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">6-13</td>
<td align="right">0</td>
<td align="right">7294</td>
<td align="right">41757</td>
<td align="right">530775</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">7-17</td>
<td align="right">0</td>
<td align="right">6292</td>
<td align="right">30771</td>
<td align="right">489945</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">. . .<span> </span></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">95-499</td>
<td align="right">0</td>
<td align="right">26395</td>
<td align="right">59904</td>
<td align="right">133446</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">96-503</td>
<td align="right">0</td>
<td align="right">23891</td>
<td align="right">51488</td>
<td align="right">113883</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">97-509</td>
<td align="right">0</td>
<td align="right">6376</td>
<td align="right">32185</td>
<td align="right">81409</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">98-521</td>
<td align="right">0</td>
<td align="right">14685</td>
<td align="right">38199</td>
<td align="right">81215</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">99-523</td>
<td align="right">0</td>
<td align="right">20810</td>
<td align="right">57653</td>
<td align="right">81029</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl63" style="height: 15pt;" height="20">100-541</td>
<td align="right">0</td>
<td align="right">25095</td>
<td align="right">58695</td>
<td align="right">78282</td>
</tr>
</tbody>
</table>
<p>Five million (5,983,878) messages in the first sieve and in average 50,000 messages in each sieve&#8217;s message queue! We can clearly see why it&#8217;s so important that the Erlang runtime system manages and levels how many messages are permitted to be sent, to prevent it ending up in the situation our Java version is in.</p>
<p>Java is using native threads, which on my Ubuntu Linux machine means POSIX Threads (<a href="http://en.wikipedia.org/wiki/NPTL" target="_blank">NPTL</a>). The threads are scheduled using interrupt-driven preemptive scheduling, which means at a regular frequency a clock interrupt switches the currently executing thread. This can happen as a &#8216;bolt from the blue&#8217;.</p>
<p>To compare with cooperative scheduling, let&#8217;s introduce a helper class that invokes yield() and call it inside each loop of the generator and the sieve.</p>
<pre>public class ThreadSwitcher {
  private long  count  = 0;
  private int    factor = 1;
  public ThreadSwitcher(int factor) {this.factor = factor;}
  public void yield() {
    if ((factor &gt; 0) &amp;&amp; (++count % factor) == 0) {
      Thread.yield();
    }
  }
}</pre>
<p>If I run it with factor=10, it completes in 18 secs.</p>
<pre>$ java -cp target/classes/ Prime -y 10 -b 0 -n 100
1) 2
2) 3
. . .
99) 523
100) 541
[2, 3, 5, 7, 11, 13, ..., 523, 541]
Elapsed time: 18.495 secs</pre>
<p>If I decrease the factor=1, meaning a switch after each round, we get even better figures.</p>
<pre>$ java -cp target/classes/ Prime -y 1 -b 0 -n 100
1) 2
2) 3
. . .
98) 521
99) 523
100) 541
[2, 3, 5, 7, ...,521, 523, 541]
Elapsed time: 7.467 secs</pre>
<p>Now, look at the messages stats below. Much better numbers, although not as good as Erlang.</p>
<table style="border-collapse: collapse; width: 191pt; text-align: right;" border="0" cellspacing="0" cellpadding="0" width="252"><col style="width: 41pt;" width="54"></col> <col style="width: 32pt;" width="42"></col> <col style="width: 44pt;" width="58"></col> <col style="width: 37pt;" span="2" width="49"></col></p>
<tbody>
<tr style="height: 15pt;" height="20">
<td class="xl66" style="height: 15pt; width: 41pt;" width="54" height="20"><strong>Thread</strong></td>
<td class="xl67" style="width: 32pt;" width="42"><strong>Min</strong></td>
<td class="xl67" style="width: 44pt;" width="58"><strong>Average</strong></td>
<td class="xl67" style="width: 37pt;" width="49"><strong>Max</strong></td>
<td class="xl67" style="width: 37pt;" width="49"><strong>Count</strong></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">1-2</td>
<td align="right">821</td>
<td align="right">299267</td>
<td align="right">448928</td>
<td align="right">347981</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">2-3</td>
<td align="right">0</td>
<td align="right">7028</td>
<td align="right">28651</td>
<td align="right">173982</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">3-5</td>
<td align="right">0</td>
<td align="right">2650</td>
<td align="right">9117</td>
<td align="right">115988</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">4-7</td>
<td align="right">0</td>
<td align="right">706</td>
<td align="right">5871</td>
<td align="right">92790</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">5-11</td>
<td align="right">0</td>
<td align="right">223</td>
<td align="right">5229</td>
<td align="right">78868</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">6-13</td>
<td align="right">0</td>
<td align="right">220</td>
<td align="right">4942</td>
<td align="right">71698</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">7-17</td>
<td align="right">0</td>
<td align="right">210</td>
<td align="right">4919</td>
<td align="right">66181</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">8-19</td>
<td align="right">0</td>
<td align="right">200</td>
<td align="right">4747</td>
<td align="right">62289</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">9-23</td>
<td align="right">0</td>
<td align="right">195</td>
<td align="right">4680</td>
<td align="right">59010</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">. . .<span> </span></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">95-499</td>
<td align="right">0</td>
<td align="right">4319</td>
<td align="right">6752</td>
<td align="right">28060</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">96-503</td>
<td align="right">0</td>
<td align="right">44</td>
<td align="right">604</td>
<td align="right">28034</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">97-509</td>
<td align="right">0</td>
<td align="right">7412</td>
<td align="right">20373</td>
<td align="right">28007</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">98-521</td>
<td align="right">11657</td>
<td align="right">19766</td>
<td align="right">27877</td>
<td align="right">16222</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">99-523</td>
<td align="right">0</td>
<td align="right">15582</td>
<td align="right">16218</td>
<td align="right">26</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">100-541</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">25</td>
</tr>
</tbody>
</table>
<p>Is there anything else we can do? Yes, we can change the message sending semantics into a blocked (synchronous) implementation. I took the liberty to realize synchronous message passing in the Java program. You can find the sources at the end of this blog post. Now, running it without yield, but with a max length of each message queue of 100 gives this output.</p>
<pre>jens@spooky:~/workspace/PrimeJava$ java -cp target/classes/ Prime -y 0 -b 100 -n 100
1) 2
2) 3
3) 5
. . .
98) 521
99) 523
100) 541
[2, 3, 5, 7, 11, ..., 523, 541]
Elapsed time: 0.455 secs</pre>
<p>Yiiiha, Java rocks!. Looking at the message stats below shows something of a déjà-vu. Where have I seen numbers like this before? Hmm, let&#8217;s see. Aha, now I remember; when running the Erlang version.</p>
<table style="border-collapse: collapse; width: 166pt; text-align: right;" border="0" cellspacing="0" cellpadding="0" width="220"><col style="width: 41pt;" width="54"></col> <col style="width: 23pt;" width="31"></col> <col style="width: 44pt;" width="58"></col> <col style="width: 25pt;" width="33"></col> <col style="width: 33pt;" width="44"></col></p>
<tbody>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt; width: 41pt;" width="54" height="20"><strong>Thread</strong></td>
<td style="width: 23pt;" width="31"><strong>Min</strong></td>
<td style="width: 44pt;" width="58"><strong>Average</strong></td>
<td style="width: 25pt;" width="33"><strong>Max</strong></td>
<td style="width: 33pt;" width="44"><strong>Count</strong></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">1-2</td>
<td align="right">0</td>
<td align="right">89</td>
<td align="right">100</td>
<td align="right">15244</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">2-3</td>
<td align="right">0</td>
<td align="right">87</td>
<td align="right">100</td>
<td align="right">7523</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">3-5</td>
<td align="right">0</td>
<td align="right">89</td>
<td align="right">100</td>
<td align="right">4917</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">4-7</td>
<td align="right">0</td>
<td align="right">92</td>
<td align="right">100</td>
<td align="right">3835</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">5-11</td>
<td align="right">0</td>
<td align="right">94</td>
<td align="right">99</td>
<td align="right">3188</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">6-13</td>
<td align="right">36</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">2800</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">7-17</td>
<td align="right">0</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">2485</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">8-19</td>
<td align="right">0</td>
<td align="right">2</td>
<td align="right">99</td>
<td align="right">2339</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">9-23</td>
<td align="right">0</td>
<td align="right">2</td>
<td align="right">95</td>
<td align="right">2216</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">. . .</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">96-503</td>
<td align="right">0</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">414</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">97-509</td>
<td align="right">0</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">314</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">98-521</td>
<td align="right">0</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">214</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">99-523</td>
<td align="right">0</td>
<td align="right">99</td>
<td align="right">100</td>
<td align="right">114</td>
</tr>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt;" height="20">100-541</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">113</td>
</tr>
</tbody>
</table>
<p>OK, time to get serious again. I became curious about how the performance varies with the settings of the yield-factor (y) and the bound-buffer factor (b). Here is a table showing the elapsed time of 1000 sieve threads, as a function of some values of y and b.</p>
<table style="border-collapse: collapse; width: 144pt; text-align: right;" border="0" cellspacing="0" cellpadding="0" width="192"><col style="width: 48pt;" span="3" width="64"></col></p>
<tbody>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt; width: 48pt;" width="64" height="20"><strong>y</strong></td>
<td style="width: 48pt;" width="64"><strong>b</strong></td>
<td style="width: 48pt;" width="64"><strong>Seconds</strong></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">1000</td>
<td align="right">43.007</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">500</td>
<td align="right">28.778</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">100</td>
<td align="right">13.315</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">50</td>
<td align="right">9.167</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">10</td>
<td align="right">8.941</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">5</td>
<td align="right">8.614</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">0</td>
<td align="right">1</td>
<td align="right">6.028</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20"></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right"><span style="color: #ff0000;"><strong>1</strong></span></td>
<td align="right"><span style="color: #ff0000;"><strong>100</strong></span></td>
<td align="right"><span style="color: #ff0000;"><strong>93.844</strong></span></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">1</td>
<td align="right">10</td>
<td align="right">14.071</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right"><span style="color: #0000ff;"><strong>1</strong></span></td>
<td align="right"><span style="color: #0000ff;"><strong>1</strong></span></td>
<td align="right"><span style="color: #0000ff;"><strong>4.779</strong></span></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20"></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">10</td>
<td align="right">100</td>
<td align="right">50.055</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">10</td>
<td align="right">10</td>
<td align="right">8.056</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">10</td>
<td align="right">1</td>
<td align="right">8.351</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20"></td>
<td></td>
<td></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">100</td>
<td align="right">100</td>
<td align="right">51.479</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">100</td>
<td align="right">10</td>
<td align="right">8.655</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20" align="right">100</td>
<td align="right">1</td>
<td align="right">8.439</td>
</tr>
</tbody>
</table>
<p>It&#8217;s quite stunning to see that the elapsed time ranges from 93 seconds down to 4, just by changing how often the thread switches and capping the message queue length. In this case, we can see that the buffer-length contributes most and we can draw the conclusion that synchronous sending with buffer length 1 performes best. This is often namned <em>rendezvous</em>.</p>
<p>After running the series above using the Java version, I switched back to the Erlang version for comparison. Here are two runs with 1000 and 10,000 threads. Additional comments are superfluous.</p>
<pre>$ erl -pa target/beams/ -noshell -run prime exe 1000 no
Elapsed time 2.213 secs
$ erl -pa target/beams/ -noshell -run prime exe 10000 no
Elapsed time 211.147 secs</pre>
<p>The Java version still has a long way to go, when it comes to the number of threads. Above 1000 threads it starts to struggle. Running with 5000 threads takes 350 seconds and with 7500 threads it takes 852 seconds.</p>
<p>Some other day I will re-implement the program in C++ using pthreads and compare with both the Java and Erlang versions. Perhaps that will happen when I am teaching <em>realtime systems programming in C++ on Linux</em> in September for Ericsson in Gothenburg. You bet, I will be using the prime number pipeline as an exercise there too.</p>
<h2>Source Code</h2>
<ul>
<li><a href="http://lib.ribomation.com/svn/repo/blog-demo/PrimeNumbers/">SVN project directory</a></li>
<li><a href="http://lib.ribomation.com/svn/repo/blog-demo/PrimeNumbers/src/erlang/">Erlang sources</a></li>
<li><a href="http://lib.ribomation.com/svn/repo/blog-demo/PrimeNumbers/src/java/">Java sources</a></li>
</ul>
<h2>Final words</h2>
<p>This Erlang version is part of the exercises for a course in Erlang Basics I have been developing during the last couple of weeks. My Erlang course is marketed by <a title="Informator in Sweden" href="http://informator.se/" target="_blank">Informator</a> in Sweden and for a start intended for Ericsson. If you are interested in attending the course, please don’t hesitate to contact <a title="Informator in Sweden" href="http://informator.se/" target="_blank">Informator</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/08/06/generating-prime-numbers-with-erlang-and-java/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The critical section problem in Erlang</title>
		<link>http://blog.ribomation.com/2009/07/31/the-critical-section-problem-in-erlang/</link>
		<comments>http://blog.ribomation.com/2009/07/31/the-critical-section-problem-in-erlang/#comments</comments>
		<pubDate>Fri, 31 Jul 2009 12:10:32 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Erlang]]></category>

		<category><![CDATA[Concurrency]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=295</guid>
		<description><![CDATA[The programming language Erlang is based on micro-threads and asynchronous message passing. There is a (naive) belief that critical section problems cannot arise in languages based solely on message passing. The justification for this stand-point is the absence of mutex synchronization primitives, which is absolutely essential in shared-data based concurrent languages. As we will shortly [...]]]></description>
			<content:encoded><![CDATA[<p>The programming language Erlang is based on micro-threads and asynchronous message passing. There is a (naive) belief that critical section problems cannot arise in languages based solely on message passing. The justification for this stand-point is the absence of mutex synchronization primitives, which is absolutely essential in shared-data based concurrent languages. As we will shortly see, it&#8217;s more about the design of the data operations than what means of thread synchronization is used. But first&#8230;</p>
<h2>A Little Bit of Theory</h2>
<h3>Critical Section</h3>
<p>A <em>critical section</em> referrers to the code section executed to operate on shared data. Shared data is some state that can be accesses by several threads concurrently. The conditions required for a critical section problem to occur are</p>
<ol>
<li>A non-atomic mutating operation. That means an operation consisting of the primitives READ/MODIFY/WRITE and they are not executed as one single indivisable operation.</li>
<li>Concurrent threads performing the operation.</li>
<li>Interruption of the threads somewhere within the operation. That means, one thread currently performing the operation is suspended and another starts and completes the operation, before the first thread are allowed to proceed.</li>
</ol>
<h3>Mutex Synchronization</h3>
<p>In order to solve the problem (above) one has to violate at least of the conditions. The standard way of doing that is the realization of so called <strong>mut</strong>ual <strong>ex</strong>clusive access to the code section. This is normally solved using some form of lock. Java has a keyword synchronized, which behind the scenes uses POSIX mutex_lock()/unlock() on POSIX compliant systems such as Linux.</p>
<h2>The Demo Problem</h2>
<p>Consider a back account with multiple updaters performing depositions and withdrawals (yes, this is a classical ;-)</p>
<p>We start the system with 1 account of balance 0, U updaters which all performs 2N updates. First they deposit 100 (<em>choose your currency here</em>) N times and then withdraws 100 N times. The resulting balance should of-course be 0.</p>
<h2>Erlang Implementation</h2>
<h3>Account</h3>
<p>Let&#8217;s start with the Erlang implementation of the account. The account is represented as a thread (process in Erlang&#8217;s parlance).The create function starts a new thread which executes the account body function. The body waits for any of a set of messages. A message is sent using rendezvous (blocking/synchronous) realized using the functions send/2, recv/0 and reply/2.</p>
<pre>account_create() -&gt;
    {account, spawn(?MODULE, account_body, [0])}.

account_body(Balance) -&gt;
    case recv() of
        {From, done} -&gt;
            reply(Balance, From),
            done;
        {From, get} -&gt;
            reply(Balance, From),
            account_body(Balance);
        {From, {set, Value}} -&gt;
            BalanceNew = Value,
            reply(BalanceNew, From),
            account_body(BalanceNew);
        _ -&gt;
            account_body(Balance)
    end.

account_get(Account)           -&gt; send(get, Account).
account_set(Account, Value)    -&gt; send({set,Value}, Account).
account_destroy(Account)       -&gt; send(done, Account).</pre>
<h3>Updater</h3>
<p>An updater performs all of its operations and then terminates, notifying the bank about its &#8216;departure&#8217;.</p>
<pre>updater_create(Id, Account, NumUpdates, RunMode) -&gt;
    {updater, Id, spawn(?MODULE, updater_body, [Id, Account, NumUpdates, RunMode])}.

updater_body(Id, Account, NumUpdates, RunMode) -&gt;
    io:format("Updater-~w: started~n", [Id]),
    repeat(NumUpdates, fun() -&gt; account_update(Account, +100, RunMode) end),
    repeat(NumUpdates, fun() -&gt; account_update(Account, -100, RunMode) end),
    bank ! {updater, Id},
    io:format("Updater-~w: terminated~n", [Id]).

account_update(Account, Value, unsafe) -&gt;
    Balance    = account_get(Account),  %READ
    BalanceNew = Balance + Value,       %MODIFY
    account_set(Account, BalanceNew);   %WRITE</pre>
<p>The updater body uses a helper function repeat/2 that takes a positive number and a closure as arguments. The closure performs one function call account_update/3, which is the key to this blog post. The  last parameter is the mode of operation. As you can see, currently I only show you the unsafe mode. First it calls get/1 to READ the balance value, then it MODIFY the value and finally it WRITE the value back using set/2, which sends the new balance value to the account thread. Both get/1 and set/2 are rendezvous functions. One might say that a rendezvous creates a mutex operation.</p>
<h3>Helpers</h3>
<p>Let&#8217;s quickly show the helper functions, to get them out of the picture.</p>
<pre>send(Msg, {_,To}) -&gt;
    To ! {msg, self(), Msg},
    receive
        {reply, To, Result} -&gt; Result
    end.

recv() -&gt;
    receive
        {msg, From, Msg} -&gt; {From, Msg}
    end.

reply(Msg, To) -&gt;
    To ! {reply, self(), Msg}.

repeat(0, _Task) -&gt;
    ok;
repeat(N, Task) when N &gt; 0 -&gt;
    Task(),
    repeat(N-1, Task).</pre>
<h3>Bank</h3>
<p>Finally, here is the main function of the bank, that setups the system, runs it and tear it down again.</p>
<pre>bank(NumThreads, NumUpdates, RunMode) -&gt;
    io:format("Running the bank in ~w mode, with ~w updaters, performing 2*~w updates each~n",
              [RunMode, NumThreads, NumUpdates]),
    register(bank, self()),
    Account  = account_create(),
    Updaters = updater_create_all(NumThreads, Account, NumUpdates, RunMode),
    updater_wait_all(Updaters),
    Balance  = account_destroy(Account),
    unregister(bank),
    io:format("Final balance = ~w~n", [Balance]).

updater_create_all(NumThreads, Account, NumUpdates, RunMode) -&gt;
    [updater_create(Id, Account, NumUpdates, RunMode) || Id &lt;- lists:seq(1, NumThreads)].

updater_wait_all([]) -&gt;
    ok;
updater_wait_all(Updaters) -&gt;
    receive
        {updater, Id} -&gt;
            updater_wait_all( lists:keydelete(Id, 2, Updaters) )
    end.</pre>
<p>As you can see, the bank first creates the (single) account (object) and then all the updater (threads). The updaters are created using list comprehension, which is sort of a for-loop for functional languages. To the right, it first generates a list of integers (1..N) which is then used as a loop variable for the expression to the left which creates a new updater for each value of Id. After that, the bank waits for all updaters to finish. This is performed using the Erlang equivalent of a join-loop. It waits for a <em>{updater,Id}</em> message, removes it from the list of updaters and breaks the loop when the list is empty. The last task the bank performs before it closes, is destroying the account and reading its final balance value. This value is then printed to the console.</p>
<p>The bank module exports two public functions, run/3 and exe/1. The former performs some type checking and than invokes bank/3. The latter is used as the entry point when invoking the program from the console. I do not show them here, but you can find the complete code last in this post.</p>
<h2>Execution</h2>
<p>Time for the fun part; running the bank. Below you can find a couple of runs with the same parameter settings.</p>
<h3>Unsafe Mode</h3>
<pre>$ erl -noshell -pa target/beams -run bank exe 5 10000 unsafe
Running the bank in unsafe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-1: terminated
Updater-2: terminated
Updater-4: terminated
Updater-5: terminated
Updater-3: terminated
Final balance = -907300
$ erl -noshell -pa target/beams -run bank exe 5 10000 unsafe
Running the bank in unsafe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-4: terminated
Updater-3: terminated
Updater-2: terminated
Updater-5: terminated
Updater-1: terminated
Final balance = 343800
$ erl -noshell -pa target/beams -run bank exe 5 10000 unsafe
Running the bank in unsafe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-5: terminated
Updater-4: terminated
Updater-3: terminated
Updater-1: terminated
Updater-2: terminated
Final balance = 436800
$</pre>
<p>Pretty interesting, hu? Why is this happening? To understand this fully, we must return back to the theory at the top of this blog post. We can see that condition 1 is satisfied, because we perform the READ/MODIFY/WRITE operation in separate steps. Conditions 2 is trivially satisfied as well. How about number 3?</p>
<blockquote>
<h4>A few words about scheduling</h4>
<p>Erlang threads are scheduled using what is referred to as <em>runtime driven cooperative scheduling</em>. Cooperative scheduling means that some party (the user or the  runtime system) switch threads at (hopefully) well-chosen points in the execution. The opposite is <em>interrupt-driven preemptive scheduling</em>, where a thread switch literally happens as a &#8220;bolt from a clear sky&#8221;. Very close to this form of scheduling is multi-core/cpu execution, which shows the same characteristics.This is main reason for introducing atomic locks in computer systems. A language based on cooperative scheduling, such as Erlang, can choose wisely where to switch threads.</p>
<p>In a language based on interrupt-driven scheduling, a thread is allowed to run for at most a fixed time period. There is a clock interrupt that fires at equiv-distant time steps. There is no such thing in Erlang. Instead a thread is allowed to invoke functions a certain amount of times. (To be more precise, N number of reductions, where N typically is 1000-2000).</p></blockquote>
<p>Because the Erlang system has no understanding about the <em>meaning</em> of our account_update/3 function, it can (and does) switch the updater thread anywhere between each function/reduction within account_update/3, as soon as the thread as used up its current share of reductions.</p>
<h3>Safe Mode</h3>
<p>Now, when we understand why the problem arises we can move ahead and fix it. There is no such thing as a mutex lock in Erlang (although you can implement a thread type that acts as one), so we have to stick to the (obvious) solution of moving the READ/MODIFY/WRITE logic into the target thread. The account thread receives a message and performs one operation fully, before it moves on and serves the next message. This is our mutex. Below I show the missing code snippets.</p>
<pre>account_update(Account, Value, safe) -&gt;
    account_update(Account, Value).

account_update(Account, Value) -&gt; send({update,Value}, Account).

account_body(Balance) -&gt;
    case recv() of
        %. . .
        {From, {update, Value}} -&gt;
            BalanceNew = Balance + Value,
            reply(BalanceNew, From),
            account_body(BalanceNew);
        %. . .
    end.</pre>
<p>The &#8217;safe&#8217; version of account_update/3 invokes a new method (account_update/2) which sends the update mesage along with the value to the account thread. Within the account object/thread it now performs the operation in an atomic way, because nothing can interrupt its sequence of operations. Even if the account thread is suspended because it runs out of reduction ticks, no new operations will be started until the account resumes and completes the begun update operation. Nuff talk, let&#8217;s see it in action.</p>
<pre>$ erl -noshell -pa target/beams -run bank exe 5 10000 safe
Running the bank in safe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-3: terminated
Updater-2: terminated
Updater-5: terminated
Updater-1: terminated
Updater-4: terminated
Final balance = 0
$ erl -noshell -pa target/beams -run bank exe 5 10000 safe
Running the bank in safe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-1: terminated
Updater-2: terminated
Updater-5: terminated
Updater-4: terminated
Updater-3: terminated
Final balance = 0
$ erl -noshell -pa target/beams -run bank exe 5 10000 safe
Running the bank in safe mode, with 5 updaters, performing 2*10000 updates each
Updater-1: started
Updater-2: started
Updater-3: started
Updater-4: started
Updater-5: started
Updater-4: terminated
Updater-1: terminated
Updater-3: terminated
Updater-5: terminated
Updater-2: terminated
Final balance = 0
$</pre>
<p>Well, this is not a proof. But even running with hundreds of updaters doing millions of updates we will end up with the final balance = 0.</p>
<pre>$ erl -noshell -pa target/beams -run bank exe 100 1000000 safe
Running the bank in safe mode, with 100 updaters, performing 2*1000000 updates each
Updater-1: started
Updater-2: started
...
Updater-99: started
Updater-100: started
Updater-7: terminated
Updater-29: terminated
Updater-90: terminated
...
Updater-16: terminated
Final balance = 0
$</pre>
<h2>Source Code</h2>
<p>You will find a link to the source code below.</p>
<ul>
<li><a title="bank.erl" href="http://lib.ribomation.com/svn/repo/erlang/demo/bank.erl">bank.erl</a></li>
</ul>
<p><strong>Compile</strong> it at the command line with</p>
<pre>$ erlc bank.erl</pre>
<p>or start the Erlang shell and compile/run it there</p>
<pre>$ erl
1&gt; c(bank).</pre>
<p><strong>Run</strong> it from the command line with</p>
<pre>erl -noshell -run bank exe 10 1000 unsafe</pre>
<p>Where 10 updaters are started doing 2*1000 updates each all in &#8216;unsafe&#8217; mode. Or, run it inside the Erlang shell with</p>
<pre>2&gt; bank:run(10, 1000, unsafe).</pre>
<h2>Final words</h2>
<p>This Erlang demo program is part of the course ware for a course in Erlang Basics I have been developing during the last couple of weeks. My Erlang course is marketed by <a title="Informator in Sweden" href="http://informator.se/" target="_blank">Informator</a> in Sweden and for a start intended for Ericsson.</p>
<p>If you are interested in attending the course, please don&#8217;t hesitate to contact <a title="Informator in Sweden" href="http://informator.se/" target="_blank">Informator</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/07/31/the-critical-section-problem-in-erlang/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The ups and downs of Erlang</title>
		<link>http://blog.ribomation.com/2009/06/28/the-ups-and-downs-of-erlang/</link>
		<comments>http://blog.ribomation.com/2009/06/28/the-ups-and-downs-of-erlang/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 16:47:16 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=283</guid>
		<description><![CDATA[I just finished reading the paper A History of Erlang by its inventor Joe Armstrong. It&#8217;s really a fascinating story and I can really recommend reading Joe&#8217;s own words regarding the invention and development of the language.
Back in the late 80&#8217;s and beginning of the 90s I spent some time with Joe and the other [...]]]></description>
			<content:encoded><![CDATA[<p>I just finished reading the paper <a title="A History of Erlang" href="http://www.cs.chalmers.se/Cs/Grundutb/Kurser/ppxt/HT2007/general/languages/armstrong-erlang_history.pdf" target="_blank">A History of Erlang by its inventor Joe Armstrong</a>. It&#8217;s really a fascinating story and I can really recommend reading Joe&#8217;s own words regarding the invention and development of the language.</p>
<p>Back in the late 80&#8217;s and beginning of the 90s I spent some time with Joe and the other guys around Erlang. I wasn&#8217;t an Erlang advocate myself, rather the oppsite and we had several debates regarding object-orientation versus process-orientation. I belonged to the C++ camp. Anyway it was fun and I became interested in the language.</p>
<p>At this time I had just started as an assistant professor teaching real-time systems programming at Royal Inst of Technology (KTH). At first, I was looking at Ada as the teaching language to use. However, the compiler license alone exceeded my course budget. Instead I found Concurrent C, which was a hybrid languge provided a superset of Ada&#8217;s message passing mechanism on top of ordinary C. As a companion to Concurrent C, I selected Erlang, which allowed me to illustrate both different solutions but also common design patterns in the field of concurrent programming. At this time when I started with academic education in Erlang I was the first in the world ;-) Well, enough talk about me.</p>
<p>What I really would like to draw to your attention is the organizational environment of the Erlang team. Erlang started as a research project in concurrent language design using logic programming languages as the basis. Prolog was the primary choice, however it was rather a rapid implementation language for various design ideas. In the beginning of the 90s, Ericsson was involved in a large project intended to be the future and replacement of AXE-10, which was the major revenue machine since the 70s. The project was named AXE-N and it focused on C++ and object-orientation from the language point of view. In this context, a semi-functional and concurrent language as Erlang, was simply as plugging a square into a round hole. So Erlang was sort of <em>persona non-grata</em>. During this time period nobody outside the Erlang team cared about the language and they were free to do almost anything they wanted, such as building up a user base outside Ericsson.</p>
<p>However, AXE-N had a lot of wrong premisses and soon things started to crack. I was a supervisor for several MSc thesis projects at the time, and acquired some technical insights, which convinced me that this couldn&#8217;t end happily. In 1995, AXE-N project finally collapsed and a lot of money had been wasted. One immediate conclusion was that it must be something wrong with C++ and it became banned. The aftermath of that ban can still be felt here and there within Ericsson.</p>
<p>Now, Erlang became reconsidered and selected as the primary language for the resurrected AXE-N project. One consequence was that Erlang now was considered a company assest and the external user base just an unconvenience. On the flip side was the team got heavily funded and they could grow the team several times the original size. It was during these years the Erlang library OTP was formed. In many respects, this was a fruitful time period of Erlang.</p>
<p>However, nothing lasts forever. In 1998, the halcyon days was over. Well, the year started with great achievement. They demonstrated a GPRS system at the GSM World Congress and at CeBIT. But some fractions within Ericsson didn&#8217;t like the idea of a symbolic, functional and concurrent language. During spring 1998, they had mobilized enough organizational power to issue an &#8216;anathema&#8217; of Erlang.</p>
<p>This couldn&#8217;t and cannot be described without using the word &#8216;catastrophe&#8217;. The team was devastated and became disillusioned. People started to drop off. During the fall of that year a plan took form of resistance. Step one of the plan was to convince the organization that Erlang could be released as open source.</p>
<p>On 2 December 1998, Erlang was announced to be open source. A few days after, the whole Erlang team resigned and went to the newly created company Bluetail.</p>
<p>Bluetail, was initially a great success. But they couldn&#8217;t sustain the <em>dot gone</em> crash. Bluetail was first acquired by Alteon Web Systems and six days later that company was acquired by Nortel Networks. One of the major competitors of Ericsson. Shortly after, Nortel became a victim of the telco crash and most of the work force of former Bluetail was fired.</p>
<p>Since these turbulent days, Erlang has slowly raised from the ashes primarily as an open source project. Recently it has gained a lot of attention when people realized that there are some impressive Erlang applications out there. Such as the chat system of Facebook, the SimpleDB of Amazon WebServices (AWS), several financial systems such as Kreditor. A good overview of the state of the art usage of Erlang is the recent <a title="Erlang Factory" href="http://www.erlang-factory.com/conference/London2009/talks" target="_blank">London conference</a>. The master himself (Joe) gave a talk about <a title="Erlang by Joe Armstrong" href="http://www.erlang-factory.com/conference/London2009/speakers/joearmstrong" target="_blank">Erlang in retrospect</a>.</p>
<p>In summary, the life of Erlang has been a real roller-coaster. Now let&#8217;s go back in time to the early years of Erlang. At the same time Erlang was cooking in the lab of Ericsson (Ellemtel in Älvsjö, south of Stockholm), another language was cooking outside Standford University. Its name was -at that time- Oak. Oak was from the beginning supported by its hosting company. However, it didn&#8217;t reached its objective and was terminated in 1994. During the termination party one member demonstrated a demo of a web browser that could load Oak programs dynamically and make the &#8220;dead&#8221; web page alive. This was a turning point and the project resurrected to investigate how to best utilize the new program form called applet. The language changed name to -I&#8217;m convinced you&#8217;ve already guessed it- Java. The rest is what is frequently called &#8216;history&#8217;.</p>
<p>Now, compare these two languages. They were created more or less at the same time. Erlang had a head start. Both are dynamic. Both has built-in support for concurrency, although comming from different angles. Both are designed with fault-tolerance in mind. Both has support for dynamic code replacement.</p>
<p>Erlang failed to reach the masses and Java succeeded. One might argue that the world wasn&#8217;t ready for functional programming in the mid-90s and the step from C++ to Java was a very smooth step to take. This is indeed a fair standpoint.</p>
<p>On the other hand, Java was all the time treated as a loving child by its hosting company (Sun), but Erlang as an unwanted child by Ericsson. I&#8217;m convinced this is the key explanation why we are not programming E2EE applications today. What a pity.</p>
<p>A final word; you might wonder where comes my recent interest in Erlang from. The reason is I&#8217;m about to start develop a course in Basic Erlang for Informator intended for Ericsson. After 20 years, the loop is closed.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/06/28/the-ups-and-downs-of-erlang/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Introscope extensions</title>
		<link>http://blog.ribomation.com/2009/06/26/introscope-extensions/</link>
		<comments>http://blog.ribomation.com/2009/06/26/introscope-extensions/#comments</comments>
		<pubDate>Fri, 26 Jun 2009 13:48:06 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Introscope]]></category>

		<category><![CDATA[RiboUtils]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=279</guid>
		<description><![CDATA[Back in January 2005 I joined an existing San Francisco based company named Wily Technology. This was the beginning of a few years of hectic traveling, hacking and trouble-shooting. Meaning I traveled around in Europe, mostly UK and Germany, working at customer sites (some very large banks) helping them with performance and problem analysis of [...]]]></description>
			<content:encoded><![CDATA[<p>Back in January 2005 I joined an existing San Francisco based company named Wily Technology. This was the beginning of a few years of hectic traveling, hacking and trouble-shooting. Meaning I traveled around in Europe, mostly UK and Germany, working at customer sites (some very large banks) helping them with performance and problem analysis of large Java EE systems.</p>
<p>The tool Wily provided was named Introscope and was the first tool in its market segment when it started in 1999 and was the market leader all the time. One of my key missions was developing (hacking) numerous extensions for Introscope based on customer requests or my own observation of what I though the customers (or we professional consultants) needed.</p>
<p>As part of my re-launch of Ribomation as an independent consultant I have partnered with CA-Wily to partly do what I once did for Wily. Wily Technology was later acquired by CA. During this spring I have helped a governmental institution in Northen Sweden with a roll-out of Introscope as a monitoring solution for their Java systems.</p>
<p>One specific task was to enable alert integration with Tivoli. Back at the Wily era, I wrote an alert action extension for OpenView integration. In this case, I decided to make the extension more general and versatile, ant not tied to any specific SMC tool. The end-result is now released as open source and can be found here: <a title="SMC AlertAction" href="http://lib.ribomation.com/doc/iscopext/SystemsManagementConsoleAlertAction/">SMC AlertAction</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/06/26/introscope-extensions/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New organization of RiboUtils</title>
		<link>http://blog.ribomation.com/2009/06/26/new-organization-of-riboutils/</link>
		<comments>http://blog.ribomation.com/2009/06/26/new-organization-of-riboutils/#comments</comments>
		<pubDate>Fri, 26 Jun 2009 08:39:13 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[RiboUils]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=277</guid>
		<description><![CDATA[When re-launched Ribomation in April this year I hastely re-organized the web site as well, moving this blog into blog.ribomation.com and setting up the new &#8216;corporate&#8217; site using Drupal. Something I (intentionally) left for a later time was making a new home for RiboUtils, my over the years collection of small helper classes and tools.
Now [...]]]></description>
			<content:encoded><![CDATA[<p>When re-launched Ribomation in April this year I hastely re-organized the web site as well, moving this blog into blog.ribomation.com and setting up the new &#8216;corporate&#8217; site using Drupal. Something I (intentionally) left for a later time was making a new home for RiboUtils, my over the years collection of small helper classes and tools.</p>
<p>Now have I started to take care of its new home. From now on you can find all RiboUtils at <a title="lib.ribomation.com" href="http://lib.ribomation.com">lib.ribomation.com</a>. The starting page is extremely lame, but it show the links to the directory of the maven generated docs, the maven repo and the subversion repo.</p>
<p>What remains to do, is regenerating all maven docs updating the page links and import the sources into subversion. This is something I will do gradually, hrm&#8230;, some rainy day.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/06/26/new-organization-of-riboutils/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Video from my Cloud Computing seminar</title>
		<link>http://blog.ribomation.com/2009/05/15/video-from-my-cloud-computing-seminar/</link>
		<comments>http://blog.ribomation.com/2009/05/15/video-from-my-cloud-computing-seminar/#comments</comments>
		<pubDate>Fri, 15 May 2009 09:14:30 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Speeches]]></category>

		<category><![CDATA[Elastic Compute Cloud]]></category>

		<category><![CDATA[hadoop]]></category>

		<category><![CDATA[Video]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=274</guid>
		<description><![CDATA[This week I gave the same seminar regarding &#8220;What is Cloud Computing&#8221; in both Stockholm and Göteborg, here in Sweden.
You can watch the video from the Stockholm event. The speech language is in Swedish and the length is around one and a half hour. The video format is Adobe Flash, so you need a proper [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">This week I gave the same seminar regarding &#8220;What is Cloud Computing&#8221; in both Stockholm and Göteborg, here in Sweden.</p>
<p style="text-align: left;">You can watch the video from the Stockholm event. The speech language is in Swedish and the length is around one and a half hour. The video format is Adobe Flash, so you need a proper flash-plugin.</p>
<div class="mceTemp mceIEcenter" style="text-align: left;">
<dl class="wp-caption aligncenter" style="width: 276px;">
<dt class="wp-caption-dt"><a href="http://video.ribomation.com/cloud-computing-20090512/" target="_blank"><img style="border: 0pt none;" title="Cloud Computing Seminar - 12 May 2009 - Stockholm/Sweden" src="http://ribomation.s3.amazonaws.com/video/vad-ar-cloud-computing-12-maj-cover.jpg" alt="Cloud Computing Seminar - 12 May 2009 - Stockholm/Sweden" width="266" height="321" /></a></dt>
<dd class="wp-caption-dd">Cloud Computing Seminar - 12 May 2009 - Stockholm/Sweden</dd>
</dl>
</div>
<ul style="text-align: left;">
<li><a title="Cloud Computing -  12 May 2009" href="http://video.ribomation.com/cloud-computing-20090512/" target="_blank">Watch the video (requires Adobe Flash plugin)</a></li>
<li><a title="Cloud Computing Slides" href="http://video.ribomation.com/cloud-computing-20090512/vad-ar-cloud-computing-12-maj-slides.pdf" target="_blank">Read the presentation slides (PDF)</a></li>
<li><a title="Cloud Computing i praktiken, 3 dgr" href="http://informator.se/Product.aspx?ArticleNr=T2919" target="_blank">Register for the course &#8220;Cloud Computing i praktiken, 3 dgr&#8221;</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/05/15/video-from-my-cloud-computing-seminar/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Comparison of decompress ways in Hadoop</title>
		<link>http://blog.ribomation.com/2009/05/07/comparison-of-decompress-ways-in-hadoop/</link>
		<comments>http://blog.ribomation.com/2009/05/07/comparison-of-decompress-ways-in-hadoop/#comments</comments>
		<pubDate>Wed, 06 May 2009 22:28:21 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[gzip]]></category>

		<category><![CDATA[hadoop]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=267</guid>
		<description><![CDATA[I have recently made some programming using Hadoop, which is a framework for massive data processing over many numbers of servers. Hadoop reads input data from (large) files and performs MapReduce data reductions.
One method of reading is input is decompressing GZIP:ed files. Java has built-in support for reading gzipped stream using GZIPInputStream. However, Hadoop ships [...]]]></description>
			<content:encoded><![CDATA[<p>I have recently made some programming using <a title="Hadoop" href="http://hadoop.apache.org/core/docs/r0.20.0/index.html" target="_blank">Hadoop</a>, which is a framework for massive data processing over many numbers of servers. Hadoop reads input data from (large) files and performs <a title="MapReduce" href="http://en.wikipedia.org/wiki/Mapreduce" target="_blank">MapReduce</a> data reductions.</p>
<p>One method of reading is input is decompressing GZIP:ed files. Java has built-in support for reading gzipped stream using <a title="GZIPInputStream" href="http://java.sun.com/javase/6/docs/api/java/util/zip/GZIPInputStream.html" target="_blank">GZIPInputStream</a>. However, Hadoop ships with its own implementation that uses native libraries for efficiency.</p>
<p>I was curious about how much faster the native <em>Hadoop</em> variant was compared with the <em>Vanilla</em> version, so I wrote a small test. The result turned out to be a surprise:</p>
<pre>May 6, 2009 10:56:47 PM org.apache.hadoop.util.NativeCodeLoader &lt;clinit&gt;
INFO: Loaded the native-hadoop library
May 6, 2009 10:56:47 PM org.apache.hadoop.io.compress.zlib.ZlibFactory &lt;clinit&gt;
INFO: Successfully loaded &amp; initialized native-zlib library
May 6, 2009 10:56:47 PM org.apache.hadoop.io.compress.CodecPool getDecompressor
INFO: Got brand-new decompressor
Time of Hadoop  decompressor running 'small' job = 0:00:01.684 (1.684 ms/file)
Time of Hadoop  decompressor running 'large' job = 0:00:10.074 (1007.400 ms/file)
Time of Vanilla decompressor running 'small' job = 0:00:01.340 (1.340 ms/file)
Time of Vanilla decompressor running 'large' job = 0:00:10.094 (1009.400 ms/file)
Hadoop vs. Vanilla [small]: 125.67%
Hadoop vs. Vanilla [large]: 99.80%</pre>
<p>For small GZ files (KB), the native version was slower and for moderately sized files (MB) the difference was negligible.</p>
<p>I&#8217;m running the test on a 1.67GHz dual core laptop with 2GB RAM and Ubuntu 9.04 64-bit. The &#8216;java.library.path&#8217; points to the &#8216;hadoop/lib/native/Linux-amd64-64&#8242; directory, which is needed so the JVM can pick up the correct library.</p>
<p>If you want to replicate the test, I have enclosed the test class below</p>
<pre>package com.ribomation.weatherstats.computeTemperatures;

import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.hadoop.io.compress.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;

import java.io.InputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.List;

/**
 * Compares the built-in Java GZip uncompress with Hadoop's ditto.
 * &lt;p/&gt;
 * User: jens
 * Date: May 6, 2009  9:13:32 PM
 */
public class UncompressingComparativeTest {
    private String  sampleSmallFile = "/sample-file-KB.gz";
    private String  sampleLargeFile = "/sample-file-MB.gz";
    private int     numRunsSmall    = 1000;
    private int     numRunsLarge    = 10;

    @Test
    public void test_run() throws IOException {
        UncompressStreamCreator hadoop  = new HadoopUncompressStreamCreator();
        UncompressStreamCreator vanilla = new VanillaUncompressStreamCreator();

        long hadoopSmall = runTest(hadoop, sampleSmallFile, numRunsSmall, "small");
        long hadoopLarge = runTest(hadoop, sampleLargeFile, numRunsLarge, "large");

        long vanillaSmall = runTest(vanilla, sampleSmallFile, numRunsSmall, "small");
        long vanillaLarge = runTest(vanilla, sampleLargeFile, numRunsLarge, "large");

        System.out.printf("Hadoop vs. Vanilla [small]: %.2f%% %n", 100.0 * hadoopSmall / vanillaSmall);
        System.out.printf("Hadoop vs. Vanilla [large]: %.2f%% %n", 100.0 * hadoopLarge / vanillaLarge);
    }

    private long runTest(UncompressStreamCreator c, String file, int numRuns, String type) throws IOException {
        StopWatch   sw  = new StopWatch();
        int         cnt = 0;

        sw.start();
        for (int k=0; k&lt;numRuns; ++k) {
            List&lt;String&gt; lines = runUncompress(c, file);
            assertThat(lines, notNullValue());
            cnt++;
        }
        sw.stop();

        assertThat(cnt, is(numRuns));
        System.out.printf("Time of %s decompressor running '%s' job = %s (%.3f ms/file)%n", c.name(), type, sw, sw.getTime() / (double)numRuns);

        return sw.getTime();
    }

    private List&lt;String&gt; runUncompress(UncompressStreamCreator c, String file) throws IOException {
        InputStream                 is = this.getClass().getResourceAsStream(file);
        assertThat(is, notNullValue());

        List&lt;String&gt; lines;
        try {
            lines = IOUtils.readLines( c.wrap(is) );
        } finally {
            c.dispose();
        }

        return lines;
    }

    static interface UncompressStreamCreator {
        InputStream     wrap(InputStream is) throws IOException;
        void            dispose();
        String          name();
    }

    static class HadoopUncompressStreamCreator implements UncompressStreamCreator {
        private CompressionCodec        codec;
        private Decompressor            decompressor;
        private CompressionInputStream  in;

        public HadoopUncompressStreamCreator() {
            CompressionCodecFactory     f = new CompressionCodecFactory(new Configuration());
            codec = f.getCodec(new Path("foo.gz"));
        }

        public InputStream wrap(InputStream is) throws IOException {
            decompressor = CodecPool.getDecompressor(codec);
            in           = codec.createInputStream(is, decompressor);
            return in;
        }

        public void dispose() {
            IOUtils.closeQuietly(in);
            CodecPool.returnDecompressor(decompressor);
        }

        public String name() {
            return "Hadoop ";
        }
    }

    static class VanillaUncompressStreamCreator implements UncompressStreamCreator {
        private InputStream in;

        public InputStream wrap(InputStream is) throws IOException {
            in = new GZIPInputStream(is);
            return in;
        }

        public void dispose() {
            IOUtils.closeQuietly(in);
        }

        public String name() {
            return "Vanilla";
        }
    }
}</pre>
<p>Libraries used (excl Hadoop):</p>
<ul>
<li>Commons <a title="Commons Lang" href="http://commons.apache.org/lang/" target="_blank">Lang</a> and <a title="Commons IO" href="http://commons.apache.org/io/" target="_blank">IO</a></li>
<li><a title="Mockito" href="http://mockito.org/" target="_blank">Mockito</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/05/07/comparison-of-decompress-ways-in-hadoop/feed/</wfw:commentRss>
		</item>
		<item>
		<title>I&#8217;m (re-)launching Ribomation</title>
		<link>http://blog.ribomation.com/2009/04/05/im-re-launching-ribomation/</link>
		<comments>http://blog.ribomation.com/2009/04/05/im-re-launching-ribomation/#comments</comments>
		<pubDate>Sun, 05 Apr 2009 19:44:04 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Blog]]></category>

		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Ribomation]]></category>

		<guid isPermaLink="false">http://blog.ribomation.com/?p=264</guid>
		<description><![CDATA[During the 90s I was running my own company Ribomation, devoted to training (and consulting) in advanced software development areas. In the beginning it was mostly C, C++, OOAD and threads programming in Linux. Towards the end of the 90s, it was Java only - all sorts of Java related topics. When the dot-com morphed [...]]]></description>
			<content:encoded><![CDATA[<p>During the 90s I was running my own company Ribomation, devoted to training (and consulting) in advanced software development areas. In the beginning it was mostly C, C++, OOAD and threads programming in Linux. Towards the end of the 90s, it was Java only - all sorts of Java related topics. When the dot-com morphed into the dot-gone, I terminated the business and spend some years abroad.</p>
<p>Almost ten years later it is time to start the company engine again and steer Ribomation out at the ocean. As always I will focus on emerging and disruptive technologies. Cloud Computing (CC) is definitely of that kind. CC will change the way we design and develop applications.</p>
<p>There are three use cases for CC:</p>
<ol>
<li>Extra server(s)</li>
<li>Elastic (scalable) applications</li>
<li>Massive data computation</li>
</ol>
<p>If you need some extra capacity, for example testing server, number 1 above apply. If you need to design applications that can scale to 100.000s of users, number 2 apply. And, if you need to process large amount of data, number 3 applies.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/04/05/im-re-launching-ribomation/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using TMI instead of Actors</title>
		<link>http://blog.ribomation.com/2009/04/03/using-tmi-instead-of-actors/</link>
		<comments>http://blog.ribomation.com/2009/04/03/using-tmi-instead-of-actors/#comments</comments>
		<pubDate>Fri, 03 Apr 2009 16:10:08 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Actors]]></category>

		<category><![CDATA[Concurrency]]></category>

		<category><![CDATA[ThreadMessageInvocation]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=228</guid>
		<description><![CDATA[Here in Sweden the spring has finally arrived and one of the duties I have to do is switching from winter to summer tires on my car. I did that this morning and while waiting in the garage I was reading the two articles about Actor concurrency in JavaWorld. The first article described the actor [...]]]></description>
			<content:encoded><![CDATA[<p>Here in Sweden the spring has finally arrived and one of the duties I have to do is switching from winter to summer tires on my car. I did that this morning and while waiting in the garage I was reading the two articles about Actor concurrency in JavaWorld. The <a href="http://www.javaworld.com/javaworld/jw-02-2009/jw-02-actor-concurrency1.html" target="_blank">first article</a> described the actor semantics and how it was realized in the Erlang programming language and the <a href="http://www.javaworld.com/javaworld/jw-03-2009/jw-03-actor-concurrency2.html" target="_blank">second article</a> described various ways to realize actors on top of the JVM, such as Scala, Groovy and Java it self.</p>
<p>I wasn&#8217;t aware of the multitude of actors implementations in Java, as the second article describe. The author <a href="http://tech.puredanger.com/2009/03/27/cuckoo-for-concurrency/" target="_blank">Alex Miller</a> implemented the same problem (Rock-Paper-Scissors) for each actor realization and compared the code and effort. This was interesting reading indeed.</p>
<h2>Thread Method Invocation (TMI)</h2>
<p>Many years ago, back in 2002 to be exact, I implemented a library for <a href="http://www.ribomation.com/riboutils/threadmessagequeue/" target="_blank">thread method invocation (TMI) in Java</a>. The idea was to provide various message passing techniques to Java, ranging from simple mailboxing to non-deterministic rendezvous. The library is essentially different implementation of message queues.</p>
<p style="text-align: center;"><a href="/riboutils/threadmessagequeue/" target="_blank"><img class="aligncenter" style="border: 0pt none;" title="Message Queue Classes" src="/riboutils/threadmessagequeue/article/Towards-Ada-style-thread-communication-in-Java-filer/image016.gif" alt="" width="423" height="196" /></a></p>
<p>Together with the library I wrote a (long) <a href="http://www.ribomation.com/riboutils/threadmessagequeue/article/Towards-Ada-style-thread-communication-in-Java.html" target="_blank">tutorial </a>that started from the very beginning with motivation of why synchronized and wait/notify/notifyAll are needed and then step-by-step moved up in the abstraction level via different forms of message passing, ending in non-determinsitic rendezvous, inspired by the Ada programming language. The article was submitted to JavaWorld, but was declined. After that I was busy with so many other things that the idea and the libray went into limbo. Perhaps it might resurrect nowadays.</p>
<p>After having read the second article with its various Rock-Paper-Scissors implementations, I couldn&#8217;t resist the temptation to do my own implementation of Rock-Paper-Scissors using TMI. The rest of this post describes my implementation.</p>
<p>Before I continue, let&#8217;s state first that TMI is not an actors model. It is close in spirit, becuase it&#8217;s a message passing model, but do not honor the value passing semantics. You can pass what ever object you want as a sender argument or as a response object (rendezvous). Still I consider TMI be a very useful concurrency model and simplifies designing thread based Java programs a lot.</p>
<h2>Rock-Paper-Scissors using TMI</h2>
<p>The main class is simple and straight forward, let&#8217;s show it first. It creates two players and a coordinator and kicks the latter to start the game. The program runs for a specified number of seconds.</p>
<pre>public class RockPaperScissorsUsingTMI {
    public static final String ROCK     = "rock";
    public static final String PAPER    = "paper";
    public static final String SCISSORS = "scissors";

    public static void main(String[] args) throws InterruptedException {
        int     runIntervalInSeconds = 20;
        if (args.length &gt; 0) runIntervalInSeconds = Integer.parseInt( args[0] );

        Player          p1 = new Player(1);
        Player          p2 = new Player(2);
        Coordinator     c  = new Coordinator(p1, p2);

        c.start(); p1.start(); p2.start();
        c.startPlay();

        Thread.sleep(runIntervalInSeconds * 1000);
    }
}</pre>
<p>Here is a sample output of running the program.</p>
<pre>&gt;java -jar RockPaperScissorsUsingTMI-1.0.jar 15
   0) Player-1: scissors -&gt; paper
   1) Player-1: scissors -&gt; paper
   2) Player-1: scissors -&gt; paper
   3) Player-1: rock -&gt; scissors
   4) Player-2: scissors -&gt; paper
   5) Player-2: rock -&gt; scissors
   6)      TIE: scissors
   7)      TIE: scissors
   8 ) Player-2: rock -&gt; scissors
   9) Player-2: scissors -&gt; paper
  10) Player-2: rock -&gt; scissors
  11) Player-1: rock -&gt; scissors
  12) Player-2: rock -&gt; scissors
  13) Player-1: scissors -&gt; paper
  14) Player-2: rock -&gt; scissors
  15)      TIE: paper
  16) Player-1: rock -&gt; scissors
  17) Player-2: paper -&gt; rock
  18)      TIE: rock
&gt;</pre>
<h3>The Player</h3>
<p>The player class below is simple, but illustrates the TMI realization. In this case I have chosen to be close to the actors model and are using an unbounded message queue. The interesting methods are play() and receive() which shows the &#8217;sender&#8217; side and the &#8216;receiver&#8217; side of a message queue. The sender invokes play(), which inserts a message into the queue. Because the queue is unbouded, this is not a blocking call. It&#8217;s easy to change the queue to a rendezvous queue, which results in the sender are blocked until the receiver puts a reply. Inside the run() method, a player recieves the coordinator. The player is blocked as long as the input queue is empty. Then it waits for a random amout of time and performs a move. It responds back to the coordinator using itself as argument.</p>
<pre>public class Player extends Thread {
    private static final List&lt;String&gt;   moves = Arrays.asList(ROCK, PAPER, SCISSORS);
    private static final Random         r = new Random();
    private MessageQueue                playMsgs = new UnboundedMessageQueue();
    private String                      move;

    public Player(int id) {
        super("Player-"+id);
        setDaemon(true);
    }

    public void run() {
        try {
            while (true) {
                Coordinator c = receive();
                delay( r.nextInt(1000) );
                move = makeMove();
                c.throwResult(this);
            }
        } catch (InterruptedException e) {System.out.println(getName()+" Interrupted");}
    }

    public void     play(Coordinator master) {
        try {
            playMsgs.put(master);
        } catch (InterruptedException e) { }
    }
    private Coordinator     receive() {
        try {
            return (Coordinator) playMsgs.get();
        } catch (InterruptedException e) {return null;}
    }

    private String    makeMove() {
        return moves.get( r.nextInt(moves.size()) );
    }
    public String getMove() {
        return move;
    }
    protected Player setMove(String move) {
        this.move = move;
        return this;
    }

    private void delay(int numMilliSecs) {
        try {
            sleep(10 + numMilliSecs);
        } catch (InterruptedException e) { }
    }
}</pre>
<h3>The Coordinator</h3>
<p>The coordinator is slightly more complex, due to its responsibilities. It waits for a start message, then ask each player to play and receives the throw messages in either order. It then evalutes who won this round. The concurrency part is not very complicated. It has two unbouded queues, one for each message type. And for each message type it has a public sender method (startPlay/throwResult) and a private receive method (receiveStart/receiveThrow). The Permutation class is just a helper for computing or winner.</p>
<pre>public class Coordinator extends Thread {
    private MessageQueue    startMsgs = new UnboundedMessageQueue(),
                            throwMsgs = new UnboundedMessageQueue();
    private Player          player1, player2;

    public Coordinator(Player player1, Player player2) {
        super("Coordinator");
        this.player1 = player1;
        this.player2 = player2;
        setDaemon(true);
    }

    public void run() {
        try {
            for (int count = 0; true; count++) {
                receiveStart();

                player1.play(this);
                player2.play(this);

                Player  first  = recieveThrow(),
                        second = recieveThrow();

                if (isTie(first, second)) {
                    System.out.printf("%4d) %8s: %s%n", count, "TIE", first.getMove());
                } else if (isWinning(first, second)) {
                    System.out.printf("%4d) %8s: %s -&gt; %s%n",
                            count, first.getName(), first.getMove(), second.getMove());
                } else {
                    System.out.printf("%4d) %8s: %s -&gt; %s%n",
                            count, second.getName(), second.getMove(), first.getMove());
                }

                this.startPlay();
            }
        } catch (InterruptedException e) {System.out.println(getName()+" Interrupted");}
    }

    public void     startPlay() throws InterruptedException {
        startMsgs.put(this);
    }
    private void    receiveStart() throws InterruptedException {
        startMsgs.get();
    }

    public void     throwResult(Player p) throws InterruptedException {
        throwMsgs.put(p);
    }
    private Player  recieveThrow() throws InterruptedException {
        return (Player) throwMsgs.get();
    }

    protected boolean isWinning(Player first, Player second) {
        Permutation permutation = new Permutation(first, second);
        return  permutation.dominates(ROCK    , SCISSORS) ||
                permutation.dominates(PAPER   , ROCK)     ||
                permutation.dominates(SCISSORS, PAPER);
    }

    protected boolean isTie(Player first, Player second) {
        return new Permutation(first, second).tie();
    }

    private static class Permutation {
        private Player  first, second;

        private Permutation(Player first, Player second) {
            this.first = first;
            this.second = second;
        }
        public boolean dominates(String m1, String m2) {
            return first.getMove().equals(m1) &amp;&amp; second.getMove().equals(m2);
        }
        public boolean tie() {
            return first.getMove().equals( second.getMove() );
        }
    }
}</pre>
<h2>Source code</h2>
<p>My application is developed using Maven, which means it very easy to download and unpack the sources and then type</p>
<pre>mvn package
java -jar target\RockPaperScissorsUsingTMI-1.0.jar 60</pre>
<h2>Links</h2>
<ul>
<li><a href="http://blog.ribomation.com/wp-content/uploads/2009/04/rockpaperscissorsusingtmi-10-src.zip">Source code</a></li>
<li><a href="http://blog.ribomation.com/wp-content/uploads/2009/04/rockpaperscissorsusingtmi-10.jar">Compiled JAR file</a></li>
<li><a href="http://blog.ribomation.com/riboutils/threadmessagequeue/" target="_blank">Thread MessageQueue library</a></li>
<li><a href="http://blog.ribomation.com/riboutils/threadmessagequeue/article/Towards-Ada-style-thread-communication-in-Java.html" target="_blank">Towards Ada Style Thread Communication in Java</a></li>
<li><a href="http://www.javaworld.com/javaworld/jw-02-2009/jw-02-actor-concurrency1.html" target="_blank">Understanding actor concurrency, Part 1: Actors in Erlang</a></li>
<li><a href="http://www.javaworld.com/javaworld/jw-03-2009/jw-03-actor-concurrency2.html" target="_blank">Understanding actor concurrency, Part 2: Actors on the JVM</a></li>
<li><a href="http://tech.puredanger.com/2009/03/27/cuckoo-for-concurrency/" target="_blank">Cuckoo for Concurrency</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/04/03/using-tmi-instead-of-actors/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Scala seems to be fun</title>
		<link>http://blog.ribomation.com/2009/01/28/scala-seems-to-be-fun/</link>
		<comments>http://blog.ribomation.com/2009/01/28/scala-seems-to-be-fun/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 21:49:51 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[jfokus]]></category>

		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=218</guid>
		<description><![CDATA[The second day of Jfokus was an ordinary conference day, with separate tracks and many talks to choose between.
JavaFX
The key note talk at the beginning described JavaFX, SUNs new &#8220;SilverLight and Flash&#8221; killer. The demo showing how to flip through a book with very realistic behaviour, was impressive. On the other hand I&#8217;m not convinced [...]]]></description>
			<content:encoded><![CDATA[<p>The second day of <a title="JFokus" href="http://www.jfokus.se/jfokus/" target="_blank">Jfokus</a> was an ordinary conference day, with separate tracks and many talks to choose between.</p>
<h2>JavaFX</h2>
<p>The key note talk at the beginning described JavaFX, SUNs new &#8220;SilverLight and Flash&#8221; killer. The demo showing how to flip through a book with very realistic behaviour, was impressive. On the other hand I&#8217;m not convinced SUN is gonna make it. MS is pushing out SilverLight in each Windows Update and SUN simply have not that capability to &#8220;pre-load&#8221; desktop browsers with the appropriate plugin. Remember the applet war ten years ago. Don&#8217;t get me wrong - I like JavaFX, however I&#8217;m pessimistic. Anybody still remembering JINI?</p>
<h2>Capuchin</h2>
<p>The second talk I attended was Ericsson&#8217;s new JavaME+Flash/light environment. I&#8217;m even more pessimistic about this new tool. It might be a bright piece of technology - I cannot really judge without getting my hands on it. However, will it ever be supported by other vendors? Will it be open source? How many of Ericssons own phone models will have it? There are way too many questions, before one starts to invest time and money on a new (isolated) platform.</p>
<h2>Groovy</h2>
<p>After lunch it started to be fun. First there was a talk about Groovy support in JetBrains&#8217; <a title="Intellij IDEA" href="http://www.jetbrains.com/idea/index.html" target="_blank">IntellijIDEA</a>. I have been using IDEA since the beginning of 2002 and usually uses the latest version all the time. For me personally there wasn&#8217;t anything new, becuase I have done some Groovy and Grails hacks using IDEA already. But the presentation was fun and entertaining and hopefully it inspired some in the audience to embark the Groovy way.</p>
<h2>JPA 2.0</h2>
<p>I realized that EJB3 / JPA still is not my cup of tea. Either I prefer something more high-level, like Grails or something more low-level, like Spring&#8217;s JDBC-Template.</p>
<h2>Puke</h2>
<p>A fun role playing of the importance of thinking and not following, when it comes to productive software development. A standpoint I fully support.</p>
<h2>JRockit</h2>
<p>Some interesting optimization techniques for the JRockit JVM. However, why did they start to compete with SUN in the first place?</p>
<h2>Java++</h2>
<p>Ola Bini is always fun to see on stage. He outlined the future of Java as a system implementation language and new dynamic languages on top of the JVM, such as Groovy, Scala, JRuby and others. I fully agree. Java has over the years become a dinosaur and it&#8217;s time to move on. Sort of, the same evolution as for 15-20 years ago when C faded away for C++.</p>
<h2>Scala</h2>
<p>My best experience of the day was Jonas Bonér talking about Scala. I have been curious about Scala a while now, but haven&#8217;t really reached above the threshold of actually reading and playing around with it. This has now changed. I&#8217;m a Groovy advocate, but will over this year make room for Scala as well. I doubt Scala is ready for prime time yet - not because any technical limitations, rather because of commercial aspects. But the day will come and I will be ready that day.</p>
<p>Scala seems to be a multi-paradigm language; static typing but allowing dynamic type constructs, object oriented programming, functional language programming and actors based concurrent programming. I really like the latter. As far as I understand, the support for message passing is inspired by the Erlang programming language. Back in the beginning of the 90&#8217;s, as did some hacks in Erlang, like a simulator for a small phone exchange with support for connecting it to a real PBX exchange (MD110). This was part of my teaching course in real-time systems programming, for Royal Inst of Technology in Stockholm. Besides of Erlang, I used Concurrent C++ as well in the course. Those were the days.</p>
<p>I have never liked the path taken by the current support of concurrency in Java. Doug Lea&#8217;s library, which now is the java.util.concurrent package, is simply the wrong way to go. Not because the library is bad - it is not. But, the users are . . . I mean, it is inherently difficult to design concurrent programs right. As soon it starts to be a little more complex, than a bunch of threads doing some asynchronous work. Message passing is the right way to realize concurrent programs. It is a pity, my implementation of thread method invocation from 2002 never got any attention. Well, that&#8217;s life. If you are interested, you can find the article <a title="TMI" href="http://www.ribomation.com/riboutils/threadmessagequeue/article/Towards-Ada-style-thread-communication-in-Java.html" target="_blank">here</a>.</p>
<h2>Summary</h2>
<p>The first presentation about WebSockets and the last presentation about Scala, was my personal highlights of the 2009 JFokus conference.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/01/28/scala-seems-to-be-fun/feed/</wfw:commentRss>
		</item>
		<item>
		<title>WebSockets is the way forward of pure web applications</title>
		<link>http://blog.ribomation.com/2009/01/28/websockets-is-the-way-forward-of-pure-web-applications/</link>
		<comments>http://blog.ribomation.com/2009/01/28/websockets-is-the-way-forward-of-pure-web-applications/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 22:43:28 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[Web Development]]></category>

		<category><![CDATA[html 5]]></category>

		<category><![CDATA[jfokus]]></category>

		<category><![CDATA[web 2.0]]></category>

		<category><![CDATA[websockets]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=215</guid>
		<description><![CDATA[Today I attended the first day of the two-day JFokus conference in central Stockholm. In just three years it has become one of the major Java events in the Scandinavian region. The first day was composed of two half-day sessions. I decided to go for websockets before lunch and performance tuning after lunch.
The first session [...]]]></description>
			<content:encoded><![CDATA[<p>Today I attended the first day of the <a title="JFokus 2009" href="http://www.jfokus.se/jfokus/" target="_blank">two-day JFokus conference in central Stockholm</a>. In just three years it has become one of the major Java events in the Scandinavian region. The first day was composed of two half-day sessions. I decided to go for websockets before lunch and performance tuning after lunch.</p>
<p>The first session regarding the part of the upcoming <a title="HTML 5" href="http://dev.w3.org/html5/spec/Overview.html" target="_blank">HTML 5 specification</a>, called <a title="WebSockets" href="http://www.kaazing.org/confluence/display/KAAZING/What+is+an+HTML+5+WebSocket" target="_blank">WebSockets </a>and <a title="Server Side Evets" href="http://www.kaazing.org/confluence/display/KAAZING/What+are+HTML+5+Server-sent+Events" target="_blank">Server Side Events</a>, was really, really interesting. Everybody, that have tried various ways of pushing data from the server to the web clients, know how difficult it is.</p>
<p>For some period of time, people used fat clients (like JavaSwing@WebStart) to connect to the server and then keeping a full-duplex bi-directional socket stream open. However, as more and more internet threats have emerged security guys tend to block all incoming ports except 80 and 443 for applications to use - reasoning like HTTP is decent protocol and well-understood and the web servers (like Apache) are very robust as well. That have put a burden on us developers to invent protocol tranformers, typically performed by some servlet, used to act as gateways between some back-end system and the front-end browser. Everybody, that have tried this knows how intricate it quickly gets. Why, cannot the browser subscribe directly to a JMS topic and react on incoming messages?</p>
<p>This is exact the kind of question, people behind the WebSockets upcoming standard have been asking and decided to provide an answer for.</p>
<p>A web socket creates a bi-directional HTTP tunnel and within, it can transport application level protocols such as <a title="XMPP Jabber" href="http://en.wikipedia.org/wiki/Xmpp" target="_blank">XMPP</a>, <a title="STOMP" href="http://en.wikipedia.org/wiki/Streaming_Text_Orientated_Messaging_Protocol" target="_blank">STOMP</a>, <a title="IMAP" href="http://en.wikipedia.org/wiki/Imap" target="_blank">IMAP</a>/<a title="SMTP" href="http://en.wikipedia.org/wiki/Smtp" target="_blank">SMTP</a> and many more. From an internet technology point of view, this is the best thing happened since the the invention of sliced-bread.</p>
<p>The second session, after lunch, on the other hand was a little bit disappointing. It was presented by Kirk Pepperdine of <a title="Java Performance Tuning" href="http://www.javaperformancetuning.com/" target="_blank">JavaPerformanceTuning</a>. However, he had many problems with the both the presentation device (not his fault) and the demoes (his fault). My impression was that he wasn&#8217;t really well-prepared. Having a background myself, in both training (10+ years) and performance tuning (2+ years), I must say this was below par. Never ever run a live demo without tripple-checking everything and keep some screen-shots up the sleeves, if running into disasters (shit happens indeed).</p>
<p>The first session was presented by <a title="Jonas Jacobi" href="http://www.jroller.com/jonasjacobi/" target="_blank">Jonas Jacobi</a> of <a title="Kaazing - company" href="http://www.kaazing.com/" target="_blank">Kaazing</a>, which seems to have been heavily involved in the realization of the new standard. The point is, there are no browsers yet supporting HTML 5 or WebSockets. Kaazing provides an <a title="Kaazing - community" href="http://www.kaazing.org/confluence/display/KAAZING/Home" target="_blank">open-source emulation layer </a>that fully implements the standard that can be used in the meantime. I&#8217;m really looking forward to get some time playing around with this new exiting technology.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2009/01/28/websockets-is-the-way-forward-of-pure-web-applications/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to jump into the Cloud</title>
		<link>http://blog.ribomation.com/2008/12/12/how-to-jump-into-the-cloud/</link>
		<comments>http://blog.ribomation.com/2008/12/12/how-to-jump-into-the-cloud/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 12:47:04 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[EC2]]></category>

		<category><![CDATA[Elastic Compute Cloud]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=185</guid>
		<description><![CDATA[Cloud computing is a general term for a public accessible virtualization system.
Virtualization + DataCenter + PublicAccess = CloudComputing
Although there are more than one provider and others to follow, Amazon (AWS) has pioneered the field and I will refer to AWS only when describing hands-on procedures.
Sign Up
The first thing to do is to create an AWS [...]]]></description>
			<content:encoded><![CDATA[<p>Cloud computing is a general term for a public accessible virtualization system.</p>
<p style="padding-left: 30px;"><em>Virtualization + DataCenter + PublicAccess = CloudComputing</em></p>
<p>Although there are more than one provider and others to follow, Amazon (AWS) has pioneered the field and I will refer to AWS only when describing hands-on procedures.</p>
<h2>Sign Up</h2>
<p>The <em>first </em>thing to do is to create an <a title="AWS Account Page - From there you can create a new account" href="http://aws.amazon.com/account/" target="_blank">AWS account and register a credit card</a> - yes it&#8217;s not free, although not expensive either. <a title="Price table of EC2" href="http://aws.amazon.com/ec2/#pricing" target="_blank">The pricing</a> starts at USD 0.10 per hour for the smallest machine type, plus some extra for storage and bandwidth. For a single lightly loaded server it adds up to USD 2.5-3 per day.</p>
<p>You should also sign up for <a title="EC2" href="http://aws.amazon.com/ec2/" target="_blank">EC2 </a>and <a title="S3" href="http://aws.amazon.com/s3/" target="_blank">S3</a>, which is just a single click on a button.</p>
<p align="center">
<h2>Get the Keys</h2>
<p>The <em>second </em>thing to do, is saving the ACCESS and SECRECT keys of your account to a text file, because you will need these character sequences from time to time.</p>
<p style="text-align: center;"><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/access-and-secret-keys.png"><img class="aligncenter size-medium wp-image-187" title="access-and-secret-keys" src="http://blog.ribomation.com/wp-content/uploads/2008/12/access-and-secret-keys-300x138.png" alt="" width="300" height="138" /></a></p>
<p>The <em>following </em>task is to generate a cryptographic key pair. Most convenient is letting AWS do it for you, but you can also upload you own public certificate. AWS only stores the certificate part. That means, after AWS has generated your key pair, there is a download button on the result page. Use that button to download your private key, because it is your only chance to get a working key pair. Ensure you download and store both the key and the certificate.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/x509-certificate.png"><img class="aligncenter size-medium wp-image-188" title="x509-certificate" src="http://blog.ribomation.com/wp-content/uploads/2008/12/x509-certificate-300x116.png" alt="" width="300" height="116" /></a></p>
<h2>Get the Tools</h2>
<p>Now when you have signed up you need the tools to start interacting with AWS and EC2. The <em>fourth </em>task to do is to download and install the <a title="AWS EC2 API Tools" href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=351&amp;categoryID=88" target="_blank">AWS EC2 API Tools</a> plus a very handy <a title="ElasticFox" href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=609&amp;categoryID=88" target="_blank">plugin to Firefox</a>.</p>
<h3>AWS/EC2 API Tools</h3>
<p>This set of command line tools are implemented in Java, so in case you don&#8217;t have a decent <a title="Java Downloads" href="http://java.sun.com/javase/downloads/index.jsp" target="_blank">JDK/JRE</a> already installed, now is the time to fix that.</p>
<p>You need to set four environment variables in order for the tools to work. These are</p>
<ul>
<li> <tt>EC2_HOME</tt></li>
<li> <tt>EC2_CERT</tt></li>
<li> <tt>EC2_PRIVATE_KEY</tt></li>
<li> <tt>PATH</tt></li>
</ul>
<p>The last (PATH) should point to the bin directory of EC2_HOME. The cert and key variables should point to the PEM files you downloaded during the key pair task above. Now test the command line tools</p>
<pre>ec2-describe-images --help
ec2-describe-images --verbose
ec2-describe-images --owner amazon</pre>
<p>The first line shows the built-in help and the second how to see what SOAP data are interchanged. Every command responds to these options. The third line shows how to filter out the machine images provided by Amazon. In addition to Amazon, there are plenty of third-party images available. My personal preference is to use <a title="Ubuntu AMIs" href="http://alestic.com/" target="_blank">Ubuntu images created by Eric Hammond</a>.</p>
<h3>ElasticFox</h3>
<p>Besides of using the AWS EC2 API command line tools, there are many others available implemented in Perl, Ruby, C# and more. However, my clear favorite is not a command line tool, rather a GUI. <a title="Elastic Fox - EC2 plugin for FireFox" href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=609&amp;categoryID=88" target="_blank">Elastic Fox </a>is a plug-in to FireFox and provides you with a very convenient access to EC2. This plug-in is so valuable that I am using it all the time, instead of the command line tools</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/elasticfox.png"><img class="aligncenter size-medium wp-image-191" title="elasticfox" src="http://blog.ribomation.com/wp-content/uploads/2008/12/elasticfox-300x154.png" alt="" width="300" height="154" /></a></p>
<h2>Prepare before launch</h2>
<p>Before you can launch your first AMI (Amazon Machine Image), you need fixing three additional things.</p>
<ol>
<li>Generate an EC2 logon key pair</li>
<li>A SSH client for Linux/Unix AMIs. For a Windows AMI, will use the built-in Remote Desktop client to logon via RDP.</li>
<li>Create a security group (AWS-EC2 firewall rule) enabling access to SSH (port 22) or RDP (port 3389).</li>
</ol>
<p>The EC2 logon key pair is different from the key pair you created in step three. The logon keys are used for SSH access and to encrypt/decrypt the Windows Administrator password. In contrast to the first key pair, you can create as many logon key pairs you like and use them for different purposes. Every key pair (or cert) is referred to by its name. Ensure you save the private key part to a PEM file on your own computer, because you will need that key for the SSH logon.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/key-pair.png"><img class="aligncenter size-medium wp-image-200" title="key-pair" src="http://blog.ribomation.com/wp-content/uploads/2008/12/key-pair-300x142.png" alt="" width="300" height="142" /></a></p>
<p>You need a remote access client, which for a Linux (Unix) machine will be SSH. If you are running Linux at your desktop, you probably already have ssh installed. If you are running Windows at your desktop, you need a SSH client like <a title="PuTTY" href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html" target="_blank">PuTTY </a>or install an environment like <a title="CygWin" href="http://www.cygwin.com/" target="_blank">CygWin</a>. If you are going for PuTTY, install the full distribution or more exact PuTTY and PuTTYgen. You need the latter to convert your EC2 logon private key from PEM to PuTTY&#8217;s own format PPK (PuTTY Private Key).</p>
<p>By default, there are no ports opened into your running machine instances, which means you cannot logon unless you open an appropriate port. You do that by creating a security group (firewall rule). Use ElasticFox to create a new firewall rule (web), which permits access to port 22 (SSH) and 80 (HTTP) for all IP numbers (0.0.0.0/0). The funny zeroes denotes an IP number group (CIDR). <a title="CIDR" href="http://en.wikipedia.org/wiki/CIDR" target="_blank">You can study that topic at WikiPedia</a>.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/security-group.png"><img class="aligncenter size-medium wp-image-195" title="security-group" src="http://blog.ribomation.com/wp-content/uploads/2008/12/security-group-300x76.png" alt="" width="300" height="76" /></a></p>
<h2>Launch a virtual server</h2>
<p>Now is the time to lauch the first virtual server. Choose, for example, the Ubuntu 8.10 server 32bit, provided by Eric Hammond.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/ubuntu-ami.png"><img class="aligncenter size-medium wp-image-204" title="ubuntu-ami" src="http://blog.ribomation.com/wp-content/uploads/2008/12/ubuntu-ami-300x76.png" alt="" width="300" height="76" /></a></p>
<p>Right click and choose &#8220;Launch&#8230;&#8221;</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/launch-ubuntu.png"><img class="aligncenter size-medium wp-image-205" title="launch-ubuntu" src="http://blog.ribomation.com/wp-content/uploads/2008/12/launch-ubuntu-266x300.png" alt="" width="266" height="300" /></a></p>
<p>Check that you are using your logon key, your firewall rule that at least open port 22 and the type is the smallest in only one instance. You will now see that the machine instance is booting (pending).</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-pending.png"><img class="aligncenter size-medium wp-image-206" title="instance-pending" src="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-pending-300x58.png" alt="" width="300" height="58" /></a></p>
<p>Click the refresh button, until you see the instance is running. When that happens, you will see that the instance now has a public IP and DNS name.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-running.png"><img class="aligncenter size-medium wp-image-207" title="instance-running" src="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-running-300x45.png" alt="" width="300" height="45" /></a></p>
<h2>Logon to the instance</h2>
<p>Use SSH to logon to the instance. If you are using PuTTY, you need to convert the PEM formatted private key into PuTTYs own key format PPK. Use PuTTYgen for that task. Load the PEM key and save as a private key. Ensure you give it the same base file name (differing only in the file extension), so ElasticFox can create file path to the key. Review the tools settings .</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/puttygen.png"><img class="aligncenter size-medium wp-image-209" title="puttygen" src="http://blog.ribomation.com/wp-content/uploads/2008/12/puttygen-300x72.png" alt="" width="300" height="72" /></a></p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/pem-and-ppk-keys.png"><img class="aligncenter size-medium wp-image-212" title="pem-and-ppk-keys" src="http://blog.ribomation.com/wp-content/uploads/2008/12/pem-and-ppk-keys-300x39.png" alt="" width="300" height="39" /></a></p>
<p>You can use ElasticFox to launch your SSH client directly. Just right click on the instance and choose &#8220;Connect &#8230;&#8221;. If PuTTY complains of not finding your key, double-check key template settings in the Tools setting of ElasticFox. If everything goes well you should be logged on to your own server in the cloud.</p>
<p><a href="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-logged-on.png"><img class="aligncenter size-medium wp-image-210" title="instance-logged-on" src="http://blog.ribomation.com/wp-content/uploads/2008/12/instance-logged-on-300x187.png" alt="" width="300" height="187" /></a></p>
<p>When your are done. Don&#8217;t forget to shutdown your instance again. Remember, AWS is affordable but not gratis.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2008/12/12/how-to-jump-into-the-cloud/feed/</wfw:commentRss>
		</item>
		<item>
		<title>What&#8217;s in the cloud?</title>
		<link>http://blog.ribomation.com/2008/12/09/whats-in-the-cloud/</link>
		<comments>http://blog.ribomation.com/2008/12/09/whats-in-the-cloud/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 22:30:13 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Amazon WebServices]]></category>

		<category><![CDATA[EC2]]></category>

		<category><![CDATA[Elastic Compute Cloud]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=175</guid>
		<description><![CDATA[Nowadays, there are many services provided by Amazon WebServices (from now on referred to as AWS). Names and acronyms such as S3, EC2, SQS, FPS, SimpleDB, CloudFront, EBS, EIA are swirling around. I intend not to describe all of these, rather I will concentrate on the second acronym; EC2 (Elastic Compute Cloud) and its two [...]]]></description>
			<content:encoded><![CDATA[<p>Nowadays, there are many services provided by <a title="AWS" href="http://aws.amazon.com/products/" target="_blank">Amazon WebService</a>s (from now on referred to as AWS). Names and acronyms such as S3, EC2, SQS, FPS, SimpleDB, CloudFront, EBS, EIA are swirling around. I intend not to describe all of these, rather I will concentrate on the second acronym; EC2 (Elastic Compute Cloud) and its two companions EBS (Elastic Block Storage) and EIA (Elastic IP Address). These components (EC2/EBS/EIA + S3) together forms a compelling platform for building new dynamic applications running in the cloud.</p>
<p>EC2 provides you with one or more virtual computers. You can choose from many <a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=171" target="_blank">pre-built images</a> or roll your own installation - either <a href="http://docs.amazonwebservices.com/AWSEC2/2008-05-05/DeveloperGuide/index.html?ami-via-loopback.html" target="_blank">from scratch</a> or by <a href="http://docs.amazonwebservices.com/AWSEC2/2008-05-05/DeveloperGuide/index.html?ami-from-existing-image.html" target="_blank">modifying an existing image</a>. Most of the images runs Linux (<a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=208">Fedora and Ubuntu</a>), some <a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=204">OpenSolaris</a> and recently there are <a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=209">Windows</a> images as well. In AWS terminology you launch an AMI (Amazon Machine Image) giving you a machine instance.</p>
<p>The storage model in the AWS cloud is different from common sense, i.e., concrete computers. In the cloud, there are several storage types.</p>
<ul>
<li>Fixed</li>
<li>Ephemeral</li>
<li>Persistent</li>
<li>Permanent</li>
</ul>
<p>Fixed storage is the AMI. Every time you launch an instance based on a specific AMI-ID, you get back the same storage content, which is the operating system plus the installed applications.</p>
<p>During the life time of a machine instance it has access to a file system. However, as soon as the instance terminates all data is lost and the ephemeral storage reclaimed. This indeed, is very different from physical hardware, where a server crash (most of the time) means you can reboot and re-read the data at the harddrive.</p>
<p>Clearly, one need to put business data somewhere else. Until recently, the only choice was S3 which was one of the first services of AWS. S3 is a howngrown distributed storage system, which can store unmodifiable blobs. Although, S3 serves it purpose it does not lend itself for finegrained read/write accesses. A while ago, AWS introduced EBS, which is a virtual harddrive. You allocate a drive of size between 1-1000 GB and attache it to a running machine instance. Within the instance the drive pops up as a new disk. The same procedure applies as for a physical disk, you have to format it (e.g. Ext3 or NTFS) and mount it. If the machine instance terminates the data on the virtual disk remains and can quickly be attached to another machine instance, which this time sees an initialized non-empty disk.</p>
<p>There is a non-zero probability that the virtual disk might fail/terminate, therefor a backup strategy is still needed. It&#8217;s very easy to take a snapshot of an EBS and automatically store the image in S3. Later on, it&#8217;s possible to (re-)create another EBS based on a saved snapshot in S3. In other words, this is a convenient recovery.</p>
<p>When a machine instance boots, it receives a dynamic IP number and a DNS name (for example: ec2-75-101-207-168.compute-1.amazonaws.com). It&#8217;s an understatement to point out that dynamic IP and host name complicates accessibility in the cloud. The solutions available have been to rely on a non-cloud based front-end listening on a public static IP address with a well-defined DNS name or Dynamic DNS services, such as <a title="DynDNS" href="http://www.dyndns.com/services/dns/dyndns/" target="_blank">DynDNS</a>.</p>
<p>Recently, AWS introduced allocatable IP addresses (EIA). You allocate an EIA and assigns it to a running machine instance. If the instance goes down, it&#8217;s very easy to lauch a new instance and (re-)allocate the IP to the new recovered server. With a static IP address, it&#8217;s possible to let a DNS service refer to the cloud service using an understandable hostname.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2008/12/09/whats-in-the-cloud/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Into the Cloud</title>
		<link>http://blog.ribomation.com/2008/12/05/into-the-cloud/</link>
		<comments>http://blog.ribomation.com/2008/12/05/into-the-cloud/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 22:31:11 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Cloud Computing]]></category>

		<category><![CDATA[Amazon WebServices]]></category>

		<category><![CDATA[AWS]]></category>

		<category><![CDATA[EC2]]></category>

		<category><![CDATA[Elastic Compute Cloud]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=160</guid>
		<description><![CDATA[I have previously investigated virtualization. A few years ago I used VMware WorkStation to run Fedora and Ubuntu on top WindowsXP. And before last summer, I used WMWS for a customer project running a deskop Ubuntu and two server Ubuntus (one with Oracle and the other as the project server). This autumn I discovered KVM [...]]]></description>
			<content:encoded><![CDATA[<p>I have previously investigated virtualization. A few years ago I used VMware WorkStation to run Fedora and Ubuntu on top WindowsXP. And before last summer, I used WMWS for a customer project running a deskop Ubuntu and two server Ubuntus (one with Oracle and the other as the project server). This autumn I discovered <a title="KVM @ Ubuntu" href="http://www.ribomation.com/2008/09/23/virtualization-ubuntu/" target="_blank">KVM @ Ubuntu</a>.</p>
<p>During this year I have been &#8220;kicking the tires&#8221; of the next logical step of virtualization; from personal/organizational virtualization into global cloud computing. The prime player of this new technology area is Amazon - the online book company. Other players, such as Google and Microsoft, are expected to follow.</p>
<p>The concept is simple: use an (open source) virtualization technique (<a title="Xen" href="http://www.xen.org/" target="_blank">Xen</a>, <a title="Xen" href="http://en.wikipedia.org/wiki/Xen" target="_blank">@WikiPedia</a>), apply it to a global collection of data centres, define a simple pricing model and tell it to the developer community. The result on the other hand is far from simple - indeed it is a revolution. Why? Because it changes our perception of how to design a system architecture.</p>
<p>When I started with computers, which - by the way wasn&#8217;t that long after the Jurassic period - both processing power and memory space were scarce resources. Over time these restrictions of the mind has gradually dissolved, leading to the war-cry &#8216;<em>memory is cheap, so let&#8217;s waste it</em>&#8216;. Today, nobody would be embarrassed of a 4GB foot print application. However, we still design a system architecture in terms of a few heavy weight nodes, say 2 or 4 nodes in a cluster of WAS/WLS/JBOSS app servers plus at least one DB server.</p>
<p>This has two consequences; either we buy too much hardware wasting money or we buy too little hardware leading to unacceptable response times and crashes. The right amount of hardware is not possible to achieve, because the system load varies over time.</p>
<p>With virtualization in general and a global cloud computing supplier as Amazon in particular we have relaxed the last bit of the system design restraints, leading to the contemporary war-cry &#8216;<em>servers are cheap, so let&#8217;s waste it</em>&#8216;.</p>
<p>With cloud computing we have instant access to an unbounded number of computing resources, whenever we need it. (I hope you don&#8217;t take me literary when I&#8217;m using the term &#8216;unbounded&#8217;. I simply mean many more than you uses today).</p>
<p>From the system design point of view the interesting topic is: <em>which factors of my architecture will change when I run my application over a dynamic number of servers, all with ephemeral storage?</em></p>
<p>I intend to describe <a title="AWS" href="http://aws.amazon.com/products/" target="_blank">Amazon Web Services (AWS)</a> and its cloud computing service <a title="EC2" href="http://aws.amazon.com/ec2/" target="_blank">EC2 (Elastic Compute Cloud)</a> from a practical point of view, in a series of blog posts. This was the first, introductory post.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2008/12/05/into-the-cloud/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New job</title>
		<link>http://blog.ribomation.com/2008/11/28/new-job/</link>
		<comments>http://blog.ribomation.com/2008/11/28/new-job/#comments</comments>
		<pubDate>Fri, 28 Nov 2008 19:21:51 +0000</pubDate>
		<dc:creator>jens</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.ribomation.com/?p=151</guid>
		<description><![CDATA[Next week (1st December) I&#8217;m switching to a new job for Connecta, which is a consultancy company in central Stockholm. My role will be to lead and build up the Java knowledge of a team in the area of Enterprise Java.
]]></description>
			<content:encoded><![CDATA[<p>Next week (1st December) I&#8217;m switching to a new job for Connecta, which is a consultancy company in central Stockholm. My role will be to lead and build up the Java knowledge of a team in the area of Enterprise Java.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ribomation.com/2008/11/28/new-job/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
