<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D08MSXg8eSp7ImA9WhJXFEQ.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593</id><updated>2012-08-09T00:04:48.671-07:00</updated><category term="ruby" /><category term="node.js" /><category term="Mocks" /><category term="barcamp" /><category term="couchdb" /><category term="jetlang" /><category term="Intro" /><category term="javascript" /><category term="clojure" /><category term="XP" /><category term="redis" /><category term="Selenium" /><category term="Thoughts" /><category term="CI" /><category term="software transactional memory" /><category term="Feedback" /><category term="chrome-watir" /><category term="Testing" /><category term="TDD" /><category term="Git" /><category term="metrics" /><category term="python" /><category term="DSL" /><category term="jwatir" /><category term="nosql" /><category term="performance" /><category term="code" /><category term="mechanize" /><category term="eventlet" /><category term="Design Patterns" /><category term="schnell" /><category term="event driven" /><category term="lean" /><category term="visualization" /><category term="Continuous Integration" /><category term="Google Reader" /><category term="personal" /><category term="rrd" /><category term="ChromeWatir" /><category term="REST" /><category term="carrer" /><category term="eventmachine" /><category term="programming" /><category term="Experiments" /><category term="Principles" /><category term="stm" /><category term="pylot" /><category term="webdriver" /><category term="concurrency" /><category term="rrd-rb" /><category term="API" /><category term="Refactoring" /><category term="google chrome" /><category term="rapa" /><category term="Open Source" /><category term="meta programming" /><category term="reactive programming" /><category term="multiverse" /><category term="Agile" /><category term="dns" /><category term="round robin database" /><category term="functional programming" /><category term="ActiveResource" /><category term="coding" /><category term="Process" /><category term="watir" /><category term="jruby" /><category term="schnell-jruby" /><category term="em-couchdb" /><category term="eventedio" /><category term="ATDD" /><title>#dev-test-ops</title><subtitle type="html">Thoughts on craftsmanship, languages, testing, Agile, code, watir..........</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://developer-in-test.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>78</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Developer-in-test" /><feedburner:info uri="developer-in-test" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CkEHR3s5eSp7ImA9WhVXEE4.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-5569170110532849368</id><published>2012-04-09T21:00:00.002-07:00</published><updated>2012-04-09T21:03:56.521-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-09T21:03:56.521-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="chrome-watir" /><category scheme="http://www.blogger.com/atom/ns#" term="watir" /><category scheme="http://www.blogger.com/atom/ns#" term="ChromeWatir" /><category scheme="http://www.blogger.com/atom/ns#" term="google chrome" /><title>Future of ChromeWatir</title><content type="html">I am reviving this blog again and as a first post I wanna write about future of Chromewatir, a work I did sometime back. ChromeWatir started when Watir had no support for Chrome browsers but since then the work on watir-webdriver has invalidated much of need for this and Jarib has done excellent work moving forward.&lt;br /&gt;&lt;br /&gt;I still get queries about ChromeWatir in this blog or through email after reading the blog. Please use watir-webdriver instead as it is continuously maintained and solidly built and I am discontinuing ChromeWatir.&lt;br /&gt;&lt;br /&gt;And now for something completely different....&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/Ka51I4tOrpI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/5569170110532849368/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=5569170110532849368" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5569170110532849368?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5569170110532849368?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/Ka51I4tOrpI/future-of-chromewatir.html" title="Future of ChromeWatir" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2012/04/future-of-chromewatir.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUFSXgzfSp7ImA9WxFbEE0.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-9008719222055722031</id><published>2010-06-27T02:58:00.000-07:00</published><updated>2010-07-01T09:03:38.685-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-01T09:03:38.685-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software transactional memory" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="stm" /><category scheme="http://www.blogger.com/atom/ns#" term="multiverse" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>Introducing Multiverse Software Transactional Memory for JRuby</title><content type="html">I haven't written for quite sometime. I have been busy working on one of areas I really love, Concurrency. People who have followed me for sometime in twitter or heard my talk in Rubyconf about Concurrency Paradigms with &lt;a href="http://harikrishnan83.wordpress.com"&gt;Hari&lt;/a&gt; would have understood this. Recently I have been exploring alternate forms of concurrency other than the normal locks, mutex and conditional variable ones. &lt;br /&gt;&lt;br /&gt;I love the message passing concurrency for its simplicity in removing the concept of shared memory (Still doesn't mean we will not have state dependence :). But there are at times when we need shared state and safe access to it. This problem of strategy for accessing a shared state among multiple threads of execution has been already solved in database world. Transactions gives a really good answer for this. Currently I am working on using Multiverse STM in JRuby (As earlier I had used Clojure). This time it is a complete Software Transactional Memory with support for atomic (transactional), retry (blocking) and orElse (choice) primitives. Multiverse is the transactional Memory on JVM and is the one behind Akka's STM. It uses TL2 algorithms (which has global version clock and commit time locking) as well as flexible to accommodate other algorithms. &lt;br /&gt;&lt;br /&gt;Check out the code in multiverse git repo git://git.codehaus.org/multiverse.git. There is a nice implementation of Dijkstra's Dining Philosopher's problem in it using atomic and retry...&lt;br /&gt;&lt;br /&gt;Let me know your thoughts. Look out for more posts on the internals of the STM :)&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/DHo2ODJf5i4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/9008719222055722031/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=9008719222055722031" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/9008719222055722031?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/9008719222055722031?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/DHo2ODJf5i4/introducing-multiverse-software.html" title="Introducing Multiverse Software Transactional Memory for JRuby" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/06/introducing-multiverse-software.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQAQn46eSp7ImA9WxFXFEs.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-1749965725345696209</id><published>2010-05-21T08:05:00.000-07:00</published><updated>2010-05-21T10:35:43.011-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-21T10:35:43.011-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CI" /><category scheme="http://www.blogger.com/atom/ns#" term="XP" /><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><category scheme="http://www.blogger.com/atom/ns#" term="Continuous Integration" /><title>Continuous Integration - Stop lying to me</title><content type="html">Here is the point. If your Continuous Integration build isn't validating the system as it will be deployed in production from end user perspective, it is not telling you the truth. &lt;br /&gt;&lt;br /&gt;If the continuous integration build is green but your packaging or deployment is broken, it is still lying.&lt;br /&gt;If the continuous integration build is green but your production configuration has broken, it is still lying.&lt;br /&gt;If the continuous integration build is green but you find 20 days later after deployment that the assumption you made about session has started creating problems with load balance, it has lied big time to you. &lt;br /&gt;If the continuous integration build is green but if the functional tests run against a deployment optimized to make it work and different from production, it is still lying. &lt;br /&gt;&lt;br /&gt;The above points illustrate that a lot of teams consider running unit tests and functional tests on a utopian or development environment mirrored build environment. This is equivalent to running the tests before you check in from your pairing station. The result is not completely useless. CI is still telling you the valuable information that the code you wrote has not broken anything. &lt;br /&gt;&lt;br /&gt;But if you don't have anything in the CI build which validates the code and assumptions you have made, against the production mirroring environment from the point of view of end user we will be missing very important piece of information. It basically means even though the CI build is green the team only has a false confidence that the system they are building will work as intended from the end users point of view (Both from functional point as well as deployment point). &lt;br /&gt;&lt;br /&gt;CI build should be end to end. They should run unit tests as a developer does. Should deploy to a production mirroring environment which validates packaging, deployment scripts and configuration and run functional and load tests against that so that we get a realistic understanding. &lt;br /&gt;&lt;br /&gt;I also understand this is a challenging activity. But unfortunately on the other hand the price we pay for not having this infrastructure in place is actually heavy as we won't have our assumptions validated in time and need to resort to hacky methods when we come to understand that the decisions we made don't work in the real world as well as we expected.&lt;br /&gt;&lt;br /&gt;oh.. And important point. When you check in code on the build server side don't update but always recreate the code from scratch. That way it is easy to find if we have tests passing because of stale assemblies lying around even if we have accidentally deleted them :)&lt;br /&gt;&lt;br /&gt;What is the ultimate nirvana of this approach? Continuous Deployment. The best way to understand that things work as we have expected to put deploy them to production. And if we make it a non event it is the best kind of test we can ever have. Continuous deployment is a much bigger subject and may need another blog post for discussion.  &lt;br /&gt;&lt;br /&gt;Let me know your thoughts and experience about this.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/62uMHApxkxY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/1749965725345696209/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=1749965725345696209" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1749965725345696209?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1749965725345696209?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/62uMHApxkxY/continuous-integration-stop-lying-to-me.html" title="Continuous Integration - Stop lying to me" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/05/continuous-integration-stop-lying-to-me.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cFRnozeCp7ImA9WxFQFkU.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-9062721670862779619</id><published>2010-05-12T08:38:00.000-07:00</published><updated>2010-05-12T09:16:57.480-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-12T09:16:57.480-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="webdriver" /><category scheme="http://www.blogger.com/atom/ns#" term="Open Source" /><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="Selenium" /><title>Dang!! I should have looked before I lept</title><content type="html">Old saying but mostly true (Mostly not always.. :). Let me be first clear up my opinion about Selenium. It may have been successful in a lot of project, it is now backbone for companies like Saucelab, it may be one of the first successful open source project. But still in my  opinion Selenium is one big hack. I mean both its api and internals... (No flame wars.. I mean nothing wrong. Just saying it is not soundly structured). And when ever I see problems with selenium (as in my current project) my thought process goes like this... How can I make this better and the first thing come to mind is let's replace with Webdriver. Unfortunately my current project is already running for long time before I joined so no chance of Watir in it :(. &lt;br /&gt;&lt;br /&gt;The reason I am writing this is to share my experience of this journey I undertook to replace a test code base which relied on Selenium with Webdriver. Webdriver in my opinion is one of the sound code bases I have seen equivalent to Watir. They have nice design, good abstractions, solid internals and it is fun to work with the API. Coming to my current code base... It follows the pattern of lots of test code base I have seen before.. Abstraction from application using page objects but none to the underlying driver. This may be because most of the time it is not natural to change the test driver in a project. But here we are with the need.. To make functional tests stabler and faster. Without abstraction with underlying driver the driver code would have leaked through out the test framework. Lesson - Remember test or production, properly abstract from third party stuff. &lt;br /&gt;&lt;br /&gt;I started with building a adapter layer (Webdriver backed Selenium) between test cdeand Webdriver as we wanted to keep the test code constant. Things went pretty smooth for simple stuff. Lots of strategies, webdriver functions are simpler. But then I started hitting some road blocks. Most of this is not because Webdriver is lacking but because Webdriver and Selenium are two different things. Sometimes there is no direct equivalent. Or we have to bend a lot to find an equivalent. Also the reference implementation I was using was in Java which again posed some problems as I had to build a similar functionality in C#. Although we can jokingly say that change all the starting lower case in java to upper case will make it C# in a lot of cases there is not direct equivalent again... Lots of reading, lots of research and making mistakes and correcting them are the way to solution. (Lesson - It will not be just an adapter as we say when we start....)&lt;br /&gt;&lt;br /&gt;Also another problem and a major one I hit was CSS selector. There is no css selector implementation for InternetExplorer in Webdriver. I probably may have missed out the documentation somewhere but looking at the code base we had css selectors everywhere (Lesson - Research your current landscape before jumping into a solution). I don't have a direct solution in had but as we needed this I used Ian Bicking's Css_to_Xpath python code called from C# using DLR (Because I had used this css_to_xpath before and found it to be reliable. Didn't want to pull some sample C# code from internet and patch things up). Not a great solution but it seems tow work fine till now except for really complex css selectors (I will rant on css and xpath later). So had to hunt down and convert some css selectors to xpath.&lt;br /&gt;&lt;br /&gt;I had learnt lot more lessons doing this conversion than I am putting here. Good news is I have convinced people to open source this WebDriverBacked *adapter* so other's can use it directly :)&lt;br /&gt;&lt;br /&gt;Also it is important to remember that at times we should just say "screw it.. I am gonna do this". Just take the risk and work with it. I am in the final phase of this work and things seem to go relatively smooth. Now that I am back on the testing side for sometime I will write a lot about tests. Next one coming will probably be about Css selector (A spicy one :)..&lt;br /&gt;&lt;br /&gt;I will update this post with the repo url once the adapter has been open sourced. Please let me know your thoughts with comments.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/84G8YKiGNR4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/9062721670862779619/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=9062721670862779619" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/9062721670862779619?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/9062721670862779619?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/84G8YKiGNR4/dang-i-should-have-looked-before-i-lept.html" title="Dang!! I should have looked before I lept" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/05/dang-i-should-have-looked-before-i-lept.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMBR3syeCp7ImA9WxBUEE0.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-7681684023867039413</id><published>2010-02-23T22:22:00.000-08:00</published><updated>2010-02-24T02:14:16.590-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-24T02:14:16.590-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="event driven" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="reactive programming" /><title>Simple Reactive Programming in Ruby</title><content type="html">Reactive Programming is an interesting programming paradigm based on propogation of changes, data flows. A programming model based on side effects, I think this is especially useful when we need to control the state of one entity based on what goes on in outside itself. For example take the equation&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;x = 1; y = 3&lt;br /&gt;z = x + y&lt;br /&gt;puts z #&lt;= z = 4&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since z depends on x and y, what will happen when we update value of x or y. z remains same as 4 because z is already computed and stored using the values of x and y. Now if the values of x and y changes z will still remain the same. &lt;br /&gt;&lt;br /&gt;But what if you want z to get adjusted depending upon x and y. This is more common problem in everyday programming than we think. Imagine you have to update the GUI based on what is changing in underlying model (MVC?) or take an example of spreadsheet where changing a value in a cell recalculates some other cell based on a formula. &lt;br /&gt;&lt;br /&gt;Here is a very simple example of Reactive Programming in Ruby using &lt;a href="http://phrogz.net/RubyLibs/rdoc/files/EventTarget_rb.html"&gt;EventTarget&lt;/a&gt;.&lt;br /&gt;Here in this example value of z is x + 2. We evaluate z by setting an initial value for x and then later we change value of x and observe the value of z changed as well. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;require 'EventTarget'&lt;br /&gt;&lt;br /&gt;module Rx&lt;br /&gt;  class Change&lt;br /&gt;    attr_accessor :old, :new&lt;br /&gt;  end&lt;br /&gt;  class ObservableValue&lt;br /&gt;    include EventTarget&lt;br /&gt;    def initialize(value, on_change)&lt;br /&gt;      add_event_listener(:change, &amp;on_change)&lt;br /&gt;      self.value = value&lt;br /&gt;    end&lt;br /&gt;    def value=( v )&lt;br /&gt;       change = Change.new&lt;br /&gt;       change.old = @value&lt;br /&gt;       change.new = v&lt;br /&gt;       @value = v&lt;br /&gt;       evt = Event.new( :change, change )&lt;br /&gt;       dispatch_event( evt )&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if $0 == __FILE__&lt;br /&gt;  z = 0&lt;br /&gt;  on_change = Proc.new {|e| z = e.change.new + 2}&lt;br /&gt;  x = Rx::ObservableValue.new(3, on_change)&lt;br /&gt;  puts "Initial value of z is #{z}" #&lt;= z=5&lt;br /&gt;  x.value = 5&lt;br /&gt;  puts "Current value of z is #{z}" # &lt;= z=7&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is a very simple and contrived example of Reactive programming but I hope this illustrates the point. The concept is way more powerful and is (Functional Reactive Programming) available in a lot of functional languages like Haskell. Take a look at Reactive Framework in .Net and Javascript, Traits, Trellis in Python or Cells in Common Lisp for more understanding of how Reactive Programming works.&lt;br /&gt;&lt;br /&gt;Let me know your thoughts and happy hacking :)&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/6E0zkESOGFA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/7681684023867039413/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=7681684023867039413" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7681684023867039413?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7681684023867039413?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/6E0zkESOGFA/simple-reactive-programming-in-ruby.html" title="Simple Reactive Programming in Ruby" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/02/simple-reactive-programming-in-ruby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QHQ3k5cSp7ImA9WxBVFUU.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-6718429815107090807</id><published>2010-02-19T03:35:00.000-08:00</published><updated>2010-02-19T05:15:32.729-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-19T05:15:32.729-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software transactional memory" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="stm" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>Software Transactional Memory in JRuby - Redux with Cloby</title><content type="html">After I wrote about using Clojure's Software Transactional Memory infrastructure in JRuby in my previous post. &lt;a href="http://twitter.com/headius"&gt;@headius&lt;/a&gt; has written an awesome wrapper &lt;a href="http://github.com/headius/cloby/"&gt;Cloby&lt;/a&gt; in Java to use Clojure STM in JRuby and writing Ruby objects which can be used as Clojure Refs.&lt;br /&gt;&lt;br /&gt;Here is an example code of using a Ruby object in STM. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;require 'clojure'&lt;br /&gt; &lt;br /&gt;class MyClojureObj &lt; Clojure::Object&lt;br /&gt;  def initialize&lt;br /&gt;    dosync { @foo = 'foo' }&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  attr_accessor :foo&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;obj = MyClojureObj.new&lt;br /&gt;puts "obj.foo = " + obj.foo&lt;br /&gt; &lt;br /&gt;begin&lt;br /&gt;  puts "Setting obj.foo to 'bar'"&lt;br /&gt;  obj.foo = 'bar'&lt;br /&gt;rescue ConcurrencyError&lt;br /&gt;  puts "Oops, need a transaction"&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;puts "Trying again with a transaction"&lt;br /&gt;dosync { obj.foo = 'bar' }&lt;br /&gt;puts "Success"&lt;br /&gt; &lt;br /&gt;puts "obj.foo = " + obj.foo&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some pretty good abstractions of using dosync and Refs in STM. So how do we use it?&lt;br /&gt;Clone the code from http://github.com/headius/cloby/blob/. Build ClojureLibrary.jar with clojure and jruby.jar. Keep ClojureLibrary.jar and clojure.jar in classpath. &lt;br /&gt;And here is the bridge I wrote between your awesome code using STM and ClojureLibrary.jar&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;#!/usr/bin/env jruby&lt;br /&gt;&lt;br /&gt;require "java"&lt;br /&gt;require "ClojureLibrary.jar"&lt;br /&gt;require "clojure-1.0.0.jar"&lt;br /&gt;include_class "org.jruby.clojure.ClojureLibrary"&lt;br /&gt;&lt;br /&gt;clj_lib = ClojureLibrary.new&lt;br /&gt;clj_lib.load(JRuby.runtime, true)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now its pretty easy to use Clojure's STM. No raw usage of LockingTransactions or Refs. Enjoy Cloby... :)&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/SorcQ0lK1Xs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/6718429815107090807/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=6718429815107090807" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6718429815107090807?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6718429815107090807?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/SorcQ0lK1Xs/software-transactional-memory-in-jruby.html" title="Software Transactional Memory in JRuby - Redux with Cloby" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/02/software-transactional-memory-in-jruby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QERnw8cSp7ImA9WxBVFU0.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-7109620716656321526</id><published>2010-02-18T06:14:00.000-08:00</published><updated>2010-02-18T07:01:47.279-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-18T07:01:47.279-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="stm" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>#Concurrency - Software Transactional Memory in JRuby with Clojure</title><content type="html">Still playing with JRuby and concurrency... For me JRuby is one of the best implementations of Ruby VM. It has this amazing property of taking the most boring Java projects and turning them into something exciting. Not that clojure is boring but on the other hand it is one of the most wonderful languages I have worked with. Being a big fan of Lisp Clojure is a dream come true. &lt;br /&gt;&lt;br /&gt;This post is about my exploration with JRuby and Clojure more in terms of how to use the Clojure's STM infrastructure. Whenever I find an interesting Java library the first thing I do is to import it into JRuby and play with it for sometime. After working with Clojure I wanted to use its STM in Ruby and finally found time to do it. The code is really crude as it explores very basic functionality of STM. May be as I keep working I will try to build something around this and who knows it can end up as a library for JRuby :)...&lt;br /&gt;&lt;br /&gt;Instead of defining STMs myself - Here it is from Wikipedia..&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;In computer science, software transactional memory (STM) is a concurrency control mechanism analogous to database transactions for controlling access to shared memory in concurrent computing. It functions as an alternative to lock-based synchronization. A transaction in this context is a piece of code that executes a series of reads and writes to shared memory. These reads and writes logically occur at a single instant in time; intermediate states are not visible to other (successful) transactions.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;As most of you know the problem is with sharing the state.. In this example my_account  balance. Imagine when two different threads of execution trying to update the value at the same time. Disastrous results may ensue. So the typical approach is locking of the shared resource. Problem with locking is it effectively limits concurrency as well is too hard to get it right. So we have started looking for other models of concurrency. Actors, Dataflow and STMs are some of the popular form. As you see in the example let's say there is a shared resource. If we need to update it we can't update it in a separate context. We need to run this as a part of transaction and as database transactions it is all or nothing. &lt;br /&gt;&lt;br /&gt;In Clojure's term a ref can be updated only inside the context of a transaction. Else it will throw IllegalStateException. As well the ref getting updated will not be visible to outside work till the end of the transaction. The transactions are composable which is difficult in cases of threads and locks. Also as the example shows   STM is a form of optimistic concurrency. Everyone can update the shared resource but whoever finishes first and commits wins. Others fail because the state now is different from what they started with and they can try.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 90%;"&gt;&lt;br /&gt;&lt;div id="snipplr_embed_28547" class="snipplr_embed"&gt;&lt;a href="http://snipplr.com/view/28547/clojure-stm-in-jruby/"&gt;Code snippet - Clojure STM in JRuby&lt;/a&gt; on Snipplr&lt;/div&gt;&lt;script type="text/javascript" src="http://snipplr.com/js/embed.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://snipplr.com/json/28547"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code is almost self explanatory and simple. Using clojure STM is pretty simple and straightforward. And this will help us to effectively manage concurrent access of shared resource by multiple threads. &lt;br /&gt;&lt;br /&gt;Let me know your thoughts...&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/evtjShaNn7E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/7109620716656321526/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=7109620716656321526" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7109620716656321526?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7109620716656321526?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/evtjShaNn7E/concurrency-software-transactional.html" title="#Concurrency - Software Transactional Memory in JRuby with Clojure" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/02/concurrency-software-transactional.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcDQHs6fSp7ImA9WxBVE0w.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-2224965802677670943</id><published>2010-02-16T00:09:00.000-08:00</published><updated>2010-02-16T02:44:31.515-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-16T02:44:31.515-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="jetlang" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>JRuby + Jetlang =&gt; Awesome Message Passing Concurrency</title><content type="html">It has been quiet sometime since I played around with JRuby.. The last I seriously worked on JRuby was during schnell-jruby age :). And now that celerity has taken the main stage I was back in MRI land for a long time. I recently got a chance to return to JRuby land and play with it for sometime.&lt;br /&gt;&lt;br /&gt;Interested in concurrency I tried to work on Software Transactional Memory in JRuby with Akka... But as things didn't go great I was searching for something else interesting to work on and I found Jetlang. Jetlang has been in my interest list of sometime but I never got a chance to work with Java. &lt;br /&gt;&lt;br /&gt;Jetlang is based on message passing concurrency. It has the concept of fibers which are independent threads of execution and channels which are conduits attached to fibers. We can pass messages to a fiber through channels and when a message is passed into a channel to a fiber the on receive callback is called with the corresponding parameters.. &lt;br /&gt;&lt;br /&gt;Following are two examples illustrating the use of fibers and channels for message passing concurrency. The last one is the popular ping pong example used for illustrating message passing across fibers :). &lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 90%;"&gt;&lt;br /&gt;&lt;div id="snipplr_embed_28363" class="snipplr_embed"&gt;&lt;a href="http://snipplr.com/view/28363/jruby-jetlang-example/"&gt;Code snippet - JRuby Jetlang Example&lt;/a&gt; on Snipplr&lt;/div&gt;&lt;script type="text/javascript" src="http://snipplr.com/js/embed.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://snipplr.com/json/28363"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 90%;"&gt;&lt;br /&gt;&lt;div id="snipplr_embed_28364" class="snipplr_embed"&gt;&lt;a href="http://snipplr.com/view/28364/jruby-jetlang-pingpong-example/"&gt;Code snippet - JRuby Jetlang Pingpong Example&lt;/a&gt; on Snipplr&lt;/div&gt;&lt;script type="text/javascript" src="http://snipplr.com/js/embed.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://snipplr.com/json/28364"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Writing code in Erlang and using Jetlang based message passing concurrency has made me think that... Can Actors (and Message passing fibers) be considered as ideal representations of objects? Isn't this how we want object oriented systems to behave?&lt;br /&gt;Let me know your thoughts...&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/J5_OvquaPvA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/2224965802677670943/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=2224965802677670943" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2224965802677670943?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2224965802677670943?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/J5_OvquaPvA/jruby-jetlang-awesome-message-passing.html" title="JRuby + Jetlang =&gt; Awesome Message Passing Concurrency" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/02/jruby-jetlang-awesome-message-passing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIFQ30yeip7ImA9WxBXFUU.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-67925511156055361</id><published>2010-01-18T02:14:00.000-08:00</published><updated>2010-01-27T00:55:12.392-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-27T00:55:12.392-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Design Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>Are we stuck in a Bratty Programming Model?</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_fSsd65KlPiM/S1Wz22dLccI/AAAAAAAAAVg/BTkir65GbGM/s1600-h/brat.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://2.bp.blogspot.com/_fSsd65KlPiM/S1Wz22dLccI/AAAAAAAAAVg/BTkir65GbGM/s320/brat.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5428442680777208258" /&gt;&lt;/a&gt;&lt;br /&gt;This is more of an essay or more of my thoughts than a blog post. So brace yourself to read some lengthy writing :).&lt;br /&gt;&lt;br /&gt;Warning - Thoughts are evolving and so may not be complete as you think. If you can help it to move in the right direction, I welcome you.&lt;br /&gt;&lt;br /&gt;Ever had your day spoiled by a kid who demands what he needs and doesn't budge until you give it to him (cries, pleads, rolls on the floor and on extreme cases punches and kicks :). The problem with him is he won't let you do anything else till he gets what he wants. But how does it relate to programming? I think most of our programs behave in the same way as the bratty kid.&lt;br /&gt;&lt;br /&gt;Let's take a problem - Say we are working on some ticket reservation app. The need is - Given a ticket id, get the reservation info, do some processing on that and then go on to do some other important stuff.&lt;br /&gt;&lt;br /&gt;Expressing the above spec in ruby:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;reservation = remote_service.get_reservation_info(ticket_id)&lt;br /&gt;process_ticket(reservation)&lt;br /&gt;#Program wishes to continue to do some other important stuff.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The above code is simple and we have all written this code at some point in time. But there seems to be a problem with the piece of code. It demands for some information from a remote service and doesn't move from there until it gets what it demands. Also it doesn't let rest of the code to execute as well until its demands are met. It is not just for service calls.. Think of using the same mode for network calls, database access, file system operations, long running computations. All of them can become bratty and stop your program from moving forward.&lt;br /&gt;&lt;br /&gt;Are programs supposed to behave like this? Is this a better method of writing code? For simple code of not much serious use, the above model is acceptable. But when we start moving to systems which need to grow in scale this programming model is not sustainable.&lt;br /&gt;&lt;br /&gt;Programs are supposed to be magnanimous in nature. A line of code should behave in a way that if it is not able to get something for moving forward, should move out of the line to let others execute and wait for its input. How would that actually work out in  code?&lt;br /&gt;&lt;br /&gt;Now lets jump into code which can give a hint of how to solve this. Below is the same ruby code written in a different way.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;remote_service.get_reservation_info(ticket_id).addCallback {|reservation| process_ticket(reservation)} # I will get the input when it is available and process it&lt;br /&gt;# other lines of code executing when above code waits for reservation info...&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So the above lines of code does the same as above semantically. But the difference between the two is in this piece of code the retrieving of reservation information and processing it doesn't seem to block the program from moving forward. I know just adding a callback doesn't solve the problem. There must be an underlying infrastructure to handle this. And this is where event loops come in. But I think you get the idea of what I am trying to say.&lt;br /&gt;&lt;br /&gt;Event loops are a bigger subject of discussion. But we have been using them most of the times. Take GUI programming as example. &lt;br /&gt;&lt;br /&gt;The I/O or more importantly programing models we have been using till now have predominantly been focusing being imperative (Do this step, get the result, then do that and continue...) but I think it's time we understand that this model can't help us long. If we need our programs to scale or even be reasonable we need to move from bratty to a magnanimous programming model. Blocking other's from moving because we still need something is not a very scalable model both in real life and programming :).&lt;br /&gt;&lt;br /&gt;This is my rant of current programming models. There may be better ways to do things and if you know any please let me know. A lot of this essay is inspired by node.js work done by &lt;a href="http://github.com/ry"&gt;Ryan Dhal&lt;/a&gt; and EventMachine which made non bratty programming so much easier for me to handle.&lt;br /&gt;&lt;br /&gt;P.S. Using event loops has a different set of constraints like new way of thinking (inverted control), different way of exception handling as well using different frameworks which we may not be familiar with.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/mlXBHPgvEX8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/67925511156055361/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=67925511156055361" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/67925511156055361?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/67925511156055361?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/mlXBHPgvEX8/are-we-stuck-in-bratty-programming.html" title="Are we stuck in a Bratty Programming Model?" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_fSsd65KlPiM/S1Wz22dLccI/AAAAAAAAAVg/BTkir65GbGM/s72-c/brat.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/01/are-we-stuck-in-bratty-programming.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYHQXY8fyp7ImA9WxBQFkk.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-8255867728972838751</id><published>2010-01-16T04:35:00.001-08:00</published><updated>2010-01-16T05:05:30.877-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-16T05:05:30.877-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="dns" /><category scheme="http://www.blogger.com/atom/ns#" term="Experiments" /><category scheme="http://www.blogger.com/atom/ns#" term="eventmachine" /><category scheme="http://www.blogger.com/atom/ns#" term="eventedio" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>DNS lookup Experiment in Ruby - Blocking and NonBlocking Modes</title><content type="html">Normal DNS lookup in Ruby (Blocking Mode)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;resolv&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;hosts&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;%w[&lt;/span&gt;&lt;span class="string"&gt;www.yahoo.com www.google.com twitter.com github.com&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;hosts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Getting address for &lt;span class="expr"&gt;#{host}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="constant"&gt;Resolv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getaddress&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;finish&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Time take to finish &lt;span class="expr"&gt;#{finish - start}&lt;/span&gt; seconds&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Execution Result - &lt;br /&gt;&lt;br /&gt;"Getting address for www.yahoo.com"&lt;br /&gt;"69.147.76.15"&lt;br /&gt;"Getting address for www.google.com"&lt;br /&gt;"209.85.231.104"&lt;br /&gt;"Getting address for twitter.com"&lt;br /&gt;"168.143.171.84"&lt;br /&gt;"Getting address for github.com"&lt;br /&gt;"207.97.227.239"&lt;br /&gt;"Time take to finish 40.313232 seconds"&lt;br /&gt;&lt;br /&gt;Non Blocking DNS Lookup in Ruby (Using EventMachine Deferrable)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;resolv&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;eventmachine&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Dns&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;EM&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Deferrable&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;resolve_hostname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;hostname&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;ip&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Resolv&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getaddress&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;hostname&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;set_deferred_status&lt;/span&gt; &lt;span class="symbol"&gt;:succeeded&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;ip&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;Exception&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;ex&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;set_deferred_status&lt;/span&gt; &lt;span class="symbol"&gt;:failed&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;EventMachine&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Requesting DNS info for yahoo&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns0&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dns&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns0&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;callback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For yahoo &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns0&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;errback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For yahoo &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;dns0&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;resolve_hostname&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;www.yahoo.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Requesting DNS info for google&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns1&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dns&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;callback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For google &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;errback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For google &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;dns1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;resolve_hostname&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;www.google.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Requesting DNS info for twitter&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns2&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dns&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;callback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For twitter &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;errback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For twitter &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;dns2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;resolve_hostname&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;twitter.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Requesting DNS info for github&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns3&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Dns&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns3&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;callback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For github &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;dns3&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;errback&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;For github &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="ident"&gt;dns3&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;resolve_hostname&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;github.com&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;;&lt;/span&gt; &lt;span class="constant"&gt;EM&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stop&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;finish&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time take for querying &lt;span class="expr"&gt;#{finish - start}&lt;/span&gt; seconds&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Execution Result -&lt;br /&gt;&lt;br /&gt;"Requesting DNS info for yahoo"&lt;br /&gt;"Requesting DNS info for google"&lt;br /&gt;"Requesting DNS info for twitter"&lt;br /&gt;"Requesting DNS info for github"&lt;br /&gt;"For google 209.85.231.99"&lt;br /&gt;"For yahoo 69.147.76.15"&lt;br /&gt;"For github 207.97.227.239"&lt;br /&gt;"For twitter 128.121.146.100"&lt;br /&gt;"Time take for querying 20.311271 seconds"&lt;br /&gt;&lt;br /&gt;The results are obvious :). You can see the difference between the blocking and non blocking modes and the effect they may have on your systems. I am also planning to write a DNS library based on NeverBlock which uses Fibers as a way to do non blocking concurrency.&lt;br /&gt;&lt;br /&gt;EventMachine is an excellent piece of software which gives a lot of functionality to do things asynchronously. Especially the Deferrable pattern is an awesome way to do long running jobs or calculations and still not block the whole world from running. I have been exploring EventMachine for sometime since I started writing &lt;a href="http://github.com/saivenkat/em-couchdb"&gt;em-couchdb&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;The code is written in a simplified way and may not be of direct use to production but hope it reflects the principles of value of doing things in non blocking way.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/Q-HgWrrB7Tc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/8255867728972838751/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=8255867728972838751" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8255867728972838751?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8255867728972838751?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/Q-HgWrrB7Tc/dns-lookup-in-ruby-blocking-and.html" title="DNS lookup Experiment in Ruby - Blocking and NonBlocking Modes" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/01/dns-lookup-in-ruby-blocking-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UDSXo_eCp7ImA9WxBQE0Q.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-8671605422117594034</id><published>2010-01-13T02:33:00.000-08:00</published><updated>2010-01-13T08:14:38.440-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-13T08:14:38.440-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="webdriver" /><category scheme="http://www.blogger.com/atom/ns#" term="watir" /><title>ChromeWatir + Watir-WebDriver Update [Important]</title><content type="html">Interesting development in Watir world but not a completely unanticipated one. I started playing around with using WebDriver as platform for Watir in the form of FireDriver and ChromeWatir. &lt;br /&gt;&lt;br /&gt;Yesterday Jarib has released a Watir abstraction on top of WebDriver. I am planning to move the effort of working on ChromeDriver to Watir-WebDriver which has ChromeDriver in it.&lt;br /&gt;&lt;br /&gt;Installation of Watir-WebDriver&lt;br /&gt;&lt;br /&gt;&gt; sudo gem install selenium-webdriver&lt;br /&gt;&gt; git clone git://github.com/saivenkat/watir-webdriver.git&lt;br /&gt;&lt;br /&gt;Example code in watir-webdriver (ChromeDriver)&lt;br /&gt;&lt;br /&gt;require "watir-webdriver"&lt;br /&gt;browser = Watir::Browser.new(:chrome)&lt;br /&gt;browser.goto "http://www.google.com"&lt;br /&gt;browser.text_field(:name, "q").set "Watir"&lt;br /&gt;browser.button(:name, "btnG").click&lt;br /&gt;&lt;br /&gt;The code is same as Watir except the driver changes internally. &lt;br /&gt;The repo is in &lt;a href="http://github.com/saivenkat/watir-webdriver"&gt;http://github.com/saivenkat/watir-webdriver&lt;/a&gt;. Feel free to fork and enjoy...&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/dck23R_99DU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/8671605422117594034/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=8671605422117594034" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8671605422117594034?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8671605422117594034?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/dck23R_99DU/chromewatir-watir-webdriver-update.html" title="ChromeWatir + Watir-WebDriver Update [Important]" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/01/chromewatir-watir-webdriver-update.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0AGSXo8fCp7ImA9WxBQE08.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-5284550719501033457</id><published>2010-01-12T09:53:00.000-08:00</published><updated>2010-01-12T11:48:48.474-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-12T11:48:48.474-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="metrics" /><category scheme="http://www.blogger.com/atom/ns#" term="lean" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><title>What is your favorite code metric?</title><content type="html">You don't need to run any build or external tool to get this. It is always there when you code and changes actively as your code evolves. What would it be?&lt;br /&gt;&lt;br /&gt;My most favorite is obviously "Line Numbers". &lt;br /&gt;&lt;br /&gt;Line numbers are available in all IDEs but mostly not actively used as a code metric during coding. Switch them on and notice them actively when you code, they tend to have an interesting effect. Probably the classes and functions will be shorter, less bloated and concise. Based on personal experience :)&lt;br /&gt;&lt;br /&gt;What is your simple metric to improve code?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_fSsd65KlPiM/S0zRqq5ZP6I/AAAAAAAAAVU/2jGxHyHaljU/s1600-h/Screenshot-couch_example.rb+(~-CodeRepo-em-couchdb-example)+-+GVIM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 229px;" src="http://2.bp.blogspot.com/_fSsd65KlPiM/S0zRqq5ZP6I/AAAAAAAAAVU/2jGxHyHaljU/s320/Screenshot-couch_example.rb+(~-CodeRepo-em-couchdb-example)+-+GVIM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5425942182074335138" /&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/6BbrCJKwMws" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/5284550719501033457/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=5284550719501033457" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5284550719501033457?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5284550719501033457?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/6BbrCJKwMws/what-is-your-favorite-code-metric.html" title="What is your favorite code metric?" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_fSsd65KlPiM/S0zRqq5ZP6I/AAAAAAAAAVU/2jGxHyHaljU/s72-c/Screenshot-couch_example.rb+(~-CodeRepo-em-couchdb-example)+-+GVIM.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2010/01/what-is-your-favorite-code-metric.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08HR3g-cCp7ImA9WxBRE0w.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-6544259969630298542</id><published>2009-12-30T10:35:00.000-08:00</published><updated>2009-12-31T19:17:16.658-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-31T19:17:16.658-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="eventmachine" /><category scheme="http://www.blogger.com/atom/ns#" term="eventedio" /><category scheme="http://www.blogger.com/atom/ns#" term="Open Source" /><category scheme="http://www.blogger.com/atom/ns#" term="couchdb" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="em-couchdb" /><title>EventMachine Client for CouchDB (em-couchdb)</title><content type="html">I have been crazy about NoSql databases for sometime. CouchDB is one of my favorite apart from redis :). I was looking for clients for CouchDB in Ruby and found most to be using Net/Http and blocking in nature. So I began my quest of writing an asynchronous non blocking awesome EventMachine based CouchDB client inspired by EventMachine::Redis client. &lt;br /&gt;&lt;br /&gt;Here is a sample code to enjoy... It creates a database, saves a document inside it, reads the doc, deletes it and then deletes the database.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/266277.js?file=em-couchdb-sample.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The current version supports database manipulation like creation and deletion and document manipulation. &lt;br /&gt;&lt;br /&gt;Looks cool for the code I wrote in a day but still there are things to improve (a lot). One thing is the CPS style. Because the code is asynchronous and the EventMachine reactor loop will take control once the code starts to run we need to explicitly pass callbacks to actions. This can be fixed as it was done in EM::Redis using callcc to make the passing implicit. &lt;br /&gt;&lt;br /&gt;Please feel free to fork and contribute and happy hacking :).&lt;br /&gt;&lt;br /&gt;The code is available at http://github.com/saivenkat/em-couchdb&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/A7dBJCrnHNE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/6544259969630298542/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=6544259969630298542" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6544259969630298542?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6544259969630298542?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/A7dBJCrnHNE/eventmachine-client-for-couchdb.html" title="EventMachine Client for CouchDB (em-couchdb)" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/12/eventmachine-client-for-couchdb.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcMSH06eSp7ImA9WxBTFEg.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-4121790466505338866</id><published>2009-12-10T06:40:00.000-08:00</published><updated>2009-12-10T06:58:09.311-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-10T06:58:09.311-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="eventedio" /><category scheme="http://www.blogger.com/atom/ns#" term="node.js" /><category scheme="http://www.blogger.com/atom/ns#" term="redis" /><title>Simple (Or not so simple) Node.js Redis Client</title><content type="html">I love node.js. For some reason I am fascinated by V8 javascript engine and its performance. I am also a big fan of Event driven I/O frameworks like twisted or EventMachine, Javascript and nosql databases of which redis is one of the stars. For those who are not familiar with terminology Google them :). &lt;br /&gt;&lt;br /&gt;Here is a small redis client I wrote in node.js. All it can do is to see if a key can exist or not :). &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/253358.js?file=redis-node.js"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/6KEnOT5umBQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/4121790466505338866/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=4121790466505338866" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/4121790466505338866?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/4121790466505338866?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/6KEnOT5umBQ/simple-not-so-simple-nodejs-redis.html" title="Simple (Or not so simple) Node.js Redis Client" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/12/simple-not-so-simple-nodejs-redis.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YNRHoycCp7ImA9WxBTE0U.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-3215770452839638370</id><published>2009-12-09T11:46:00.000-08:00</published><updated>2009-12-09T12:06:35.498-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-09T12:06:35.498-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><title>What good is the feedback for?</title><content type="html">What good is the feedback for if I am not going to use it to correct things? What good is a QA for sitting across my desk providing feedback if I am going to ignore it and continue what I am doing? What good is a showcase for if I am going to ignore my client's suggestions? What good is TDD for if I am not going to use it to evolve the design? I have heard a lot of people say the Agile is about short continuous feedback but the question comes back to why? Why we need feedback? Is feedback alone enough? Getting feedback is a way, part of the activity we are doing, not the end. &lt;br /&gt;&lt;br /&gt;All these questions made me think about what it means to Agile? I always consider software development to be more of an exploration activity. We explore ways to do things better and along the way we learn new ways and also make a few mistakes. Working over the years my definition of Agile has evolved and my current one seems to be "Agile is a method which helps to reduce the assumptions we hold as fast as possible and make things concrete". When we work on a project we have base our work on a few assumptions or understanding of what needs to be done. They may be assumptions of what client is expecting, or assumptions about a design being evolutionary... But holding on to those assumptions and thinking that we are going down the right path is a way to disaster. &lt;br /&gt;&lt;br /&gt;So how is Agile special in reducing the assumptions when compared to waterfall? Both help in that aspect of getting feedback except for Agile gives quick ways to correct our actions or find the right way. Waterfall delays it to the point where sometimes the cost of correction is too high. &lt;br /&gt;&lt;br /&gt;Working closely with the client helps in making our understanding better or reducing the assumptions we make, TDD does the same for design, Continuous Integration and deployment helps us to reduce the assumptions we have on production environment. The examples are numerous but I hope you get the point. &lt;br /&gt;&lt;br /&gt;So for me Agile is about reducing the assumptions and making things concrete so that we can continue working with confidence.&lt;br /&gt;&lt;br /&gt;Let me know your thoughts.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/MnHrzuu0o6w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/3215770452839638370/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=3215770452839638370" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/3215770452839638370?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/3215770452839638370?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/MnHrzuu0o6w/what-good-is-feedback-for.html" title="What good is the feedback for?" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/12/what-good-is-feedback-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcDQHk-fyp7ImA9WxNaGEQ.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-7800133783107891507</id><published>2009-12-03T19:09:00.001-08:00</published><updated>2009-12-03T19:41:11.757-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-03T19:41:11.757-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Design Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>Curious case of object initialization in python</title><content type="html">While working on writing some Async code for CouchDb connector using Tornado webclient I used the code of AyncHTTPClient as a doc. Reading the code I found an interesting piece of initialization method. This may not be anything new for a lot of python people but for me I found this pattern interesting. I had used python long time back while it was in 2.5.x time and I came back to it recently to work on UNICEF project. So my knowledge of python may not be as sharp as knife :)&lt;br /&gt;&lt;br /&gt;So lets jump into the code directly. The initialization method as I remember in python is __init__. For those unfamiliar with python __init__ is the first method called when an object is initialized. Or in other words a constructor. Similar to ruby's init method. Pretty simple right?&lt;br /&gt;&lt;br /&gt;But checkout the __new__ method. A simple example of usage of __new__ method for singleton pattern in python.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/248802.js?file=single.py"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;So how is __new__ method different from __init__? As seen from example __new__ gives a complete control of the object I construct. So when initializing the object the order of calling is &lt;br /&gt;1. You try to create an object --&gt; 2. __new__ called if available to create an instance --&gt; 3. object initialized using __init__. Also __new__ can return an instance of the class you are creating. __init__ only does the job of initializing it and does not return anything. &lt;br /&gt;&lt;br /&gt;I know a lot of you may know about this already. But I wanted to share what I understood. Let me know if you think there is a better explanation or I have goofed up something.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/-4Ct6vjsz9Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/7800133783107891507/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=7800133783107891507" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7800133783107891507?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/7800133783107891507?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/-4Ct6vjsz9Y/curious-case-of-object-initialization.html" title="Curious case of object initialization in python" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/12/curious-case-of-object-initialization.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MCRHwyeip7ImA9WxNaGEs.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-8603745724086965852</id><published>2009-12-03T09:27:00.000-08:00</published><updated>2009-12-03T09:31:05.292-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-03T09:31:05.292-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="couchdb" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="eventlet" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>Eventlet based CouchDB connector</title><content type="html">This is an attempt to write a nonblocking CouchDB API based on Eventlet. Eventlet is a wonderful python library written by Second Life people based on coroutine based nonblocking I/O. I also tried using AsyncHTTPClient provided by Tornado framework released by FriendFeed people but liked the eventlet version more. So here goes... This API may grow to be a full fledged one in future. &lt;br /&gt;&lt;br /&gt;Also look out a Ruby non blocking one based on NeverBlock :)&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/248347.js?file=event_couchdb.py"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/TNtFTLQ2TbE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/8603745724086965852/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=8603745724086965852" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8603745724086965852?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/8603745724086965852?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/TNtFTLQ2TbE/eventlet-based-couchdb-connector.html" title="Eventlet based CouchDB connector" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>5</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/12/eventlet-based-couchdb-connector.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEEQ3oycSp7ImA9WxNbEEw.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-2115399024005463490</id><published>2009-11-11T13:21:00.000-08:00</published><updated>2009-11-12T00:13:22.499-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-12T00:13:22.499-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="visualization" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="watir" /><title>Code Swarm Visualization of Watir Project</title><content type="html">Presenting the code swarm visualization of &lt;a href="http://www.watir.com"&gt;Watir&lt;/a&gt; project. For those who don't know what is &lt;a href="http://github.com/rictic/code_swarm"&gt;code swarm&lt;/a&gt;, it is an experiment in organic software visualization or what ever that means :). For me it meant visualization of activities on a code repo or project. So here is the one for Watir project. If you wanna watch it in Hi-def go over to Vimeo and take a look. Its pretty awesome...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="300"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=7567626&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=7567626&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;&lt;a href="http://vimeo.com/7567626"&gt;Code Swarm visualization of Watir project&lt;/a&gt; from &lt;a href="http://vimeo.com/user2273835"&gt;saivenkat&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/l9teeOKru28" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/2115399024005463490/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=2115399024005463490" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2115399024005463490?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2115399024005463490?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/l9teeOKru28/code-swarm-visualization-of-watir.html" title="Code Swarm Visualization of Watir Project" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/11/code-swarm-visualization-of-watir.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YBQH06cCp7ImA9WxNUFU8.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-1418611833443655156</id><published>2009-11-06T07:54:00.000-08:00</published><updated>2009-11-06T08:32:31.318-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-06T08:32:31.318-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Git" /><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><title>Git - Branch Per Feature Experiment</title><content type="html">I am sure others are using Git like this before but these are my thoughts I collected over sometime using Git. I have been using Git for over a year now but mostly for my Watir projects where I haven't had a big chance to work with branches other than master till now. My current project has given me an opportunity to use Git in a different perspective. I have been observing that I almost never use master but always am in some branch working and constantly merging with master. And the branch I work on is something related to the feature I am working at that point of time or exploring.&lt;br /&gt;To illustrate the point better, I thought a picture will illustrate the point better :).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_fSsd65KlPiM/SvRM5Po9cwI/AAAAAAAAAUY/K_Ue0Xb-4t0/s1600-h/git-branch.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://4.bp.blogspot.com/_fSsd65KlPiM/SvRM5Po9cwI/AAAAAAAAAUY/K_Ue0Xb-4t0/s320/git-branch.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5401026399458652930" /&gt;&lt;/a&gt;&lt;br /&gt;As you see in the picture I am currently working on tagging feature but there seems to be other features as branches there. I am exploring the option of text search and well as bookmarking a search for projects. So if I want to work on some other feature I switch the branch and work. Once the feature I am working on is done I switch to master, merge the feature with main branch, pull from remote repo, fix any merge conflicts and commit the feature to master before pushing it to remote repo. Then the branch gets deleted. If any work needs to be done on the feature the branch is recreated.&lt;br /&gt;&lt;br /&gt;This seems to be my work pattern for the past few months. Using branch per feature importantly helps in keeping concerns of different features separate while working on them. As well working on a project where spiking is important creating branches for spikes seems to be a good option for me. Sometimes when I want some parts of the spike may be just a commit cherry picking also helps me a lot. Most of this seems easy and possible now because the cost of branching and merging is less in Git. The same approach will be painful in VCS like svn.&lt;br /&gt;&lt;br /&gt;This is just sharing of my experience. I am exploring better ways to use Git. Let me know if you have found good ways of using Git or similar DVCS.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/IOnGYWAl7So" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/1418611833443655156/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=1418611833443655156" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1418611833443655156?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1418611833443655156?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/IOnGYWAl7So/git-branch-per-feature-experiment.html" title="Git - Branch Per Feature Experiment" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_fSsd65KlPiM/SvRM5Po9cwI/AAAAAAAAAUY/K_Ue0Xb-4t0/s72-c/git-branch.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/11/git-branch-per-feature-experiment.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cAQHwzeip7ImA9WxNVFEU.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-2738657816257055024</id><published>2009-10-25T06:55:00.000-07:00</published><updated>2009-10-25T07:30:41.282-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-25T07:30:41.282-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Infinite lists in python</title><content type="html">My first post from Uganda :)&lt;br /&gt;&lt;br /&gt;As I am working in Django now I think I will post more on python. I had worked on python before but that was long time back and mostly on system admin stuff. So working on python now for developing web based applications and getting to understand things like object orientation, functional programming, TDD, Ruby and more I think it has changed my way of working with python a lot.&lt;br /&gt;&lt;br /&gt;This post is mostly about creating infinite lists in python. Infinite lists are an example of lazy evaluation mostly rooted in functional programming. The idea is we don't construct elements of list but what we do is give a way to construct the next element of the list and let it construct the list when we need (we still need to stop construction of elements depending on some condition). Infinite lists are also rightly called streams. In python, it is easy to use develop infinite lists using generator as shown in the examples below.&lt;br /&gt;&lt;br /&gt;Examples of infinite list in python&lt;br /&gt;&lt;br /&gt;Increment Example - &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/218062.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Fibonacci Example -&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/218065.js"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/RQzeYW3aMkc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/2738657816257055024/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=2738657816257055024" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2738657816257055024?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/2738657816257055024?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/RQzeYW3aMkc/infinite-lists-in-python.html" title="Infinite lists in python" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/10/infinite-lists-in-python.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYMQHg-eip7ImA9WxNWEEg.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-6496081574646692822</id><published>2009-10-08T20:14:00.000-07:00</published><updated>2009-10-08T20:16:21.652-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-08T20:16:21.652-07:00</app:edited><title>A simple PingPong example based on Erlang</title><content type="html">This is a test for Github's gist script embed in my blog :).&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/205209.js"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/BXY9FyULiIw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/6496081574646692822/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=6496081574646692822" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6496081574646692822?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/6496081574646692822?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/BXY9FyULiIw/simple-pingpong-example-based-on-erlang.html" title="A simple PingPong example based on Erlang" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/10/simple-pingpong-example-based-on-erlang.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcDRnY4cSp7ImA9WxNQGUQ.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-5222114726456583071</id><published>2009-09-26T11:38:00.000-07:00</published><updated>2009-09-26T12:24:37.839-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-26T12:24:37.839-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><category scheme="http://www.blogger.com/atom/ns#" term="Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="Open Source" /><category scheme="http://www.blogger.com/atom/ns#" term="pylot" /><title>Setup script and shell command for Pylot</title><content type="html">I gave a talk at PyCon India on "Testing Web Applications using Python" which featured my favourite toolkit Windmill, WebDriver, Twill and Pylot. Think Pylot impressed the audience (Great work by &lt;a href="http://twitter.com/cgoldberg"&gt;Corey Goldberg&lt;/a&gt; :) and they started trying it out immediately. Unfortunately before figuring out that they have to download it from Pylot website, I think a vast majority of them searched at PyPi and tried using easy_install. As a result one of the questions I got was unavailability of any installation medium for Pylot. Seizing the chance for me to learn how to create a setup.py based installer I jumped on the task of creating an installer for Pylot. Also to make the usage of the tool easier I have added a command line command pylot which works the same way as using python run.py to run pylot tests.&lt;br /&gt;&lt;br /&gt;So how to use this? Pretty simple. I have changed the directory structure a bit (Hope Corey doesn't get pissed off :). The pylot directory remains same except there will be a parent directly with setup.py. You can run the set up command as usual "sudo python setup.py install" (Yes mostly you may need to do sudo depending on where your python dist-packages are). Once you do this you will get pylot-runner into path and add pylot to the packages. Now you should be able to run any pylot test case with a pylot-runner. All the commandline options hold same as before "pylot-runner --agent=377 --xmlfile=awesome_website_tests.xml".  Your results will be created in the same folder as where the xml test case is.&lt;br /&gt;&lt;br /&gt;This is my first script of setup.py. Let me know if there are better ways to do this stuff. Also I will convert the installer into an egg based one but it will take few days for me to do it.&lt;br /&gt;&lt;br /&gt;Gotcha - I have created, installed and tested this on my linux system and it works amazing. So I haven't added anything specific to windows which includes the recorder. I may do this along with converting this installer to egg but it may take sometime. The wxpython Gui gets bundled though. Only the recorder is left behind...&lt;br /&gt;&lt;br /&gt;Download for Pylot with setup script and shell command - &lt;a href="http://miscellaneous-downloads.googlecode.com/files/pylot_with_setup_and_command.tar.gz"&gt;http://miscellaneous-downloads.googlecode.com/files/pylot_with_setup_and_command.tar.gz&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/Pu5XZ2RjnOE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/5222114726456583071/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=5222114726456583071" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5222114726456583071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/5222114726456583071?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/Pu5XZ2RjnOE/setup-script-and-shell-command-for.html" title="Setup script and shell command for Pylot" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/09/setup-script-and-shell-command-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ABQH06eip7ImA9WxNQEkw.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-4831956242673901644</id><published>2009-09-17T10:45:00.000-07:00</published><updated>2009-09-17T11:22:31.312-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-17T11:22:31.312-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="Thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><title>Functional Test suite in C# or Java... Why?</title><content type="html">Every time I see a functional test suite being developed in a static language, I get to the same question. Why? I feel odd when I hear people that the development language is C# or Java and so the functional test suite testing the web application or REST interface also needs to be in the same language. I understand and accept the reason for unit test as TDD is a design activity and it is better to be in the same language. But functional tests? Why?&lt;br /&gt;&lt;br /&gt;I also feel sorry for people in the team who spend time mangling a static language to build test suites and framework to make the whole thing work. Also the slowness of the feedback cycle as most popular static languages are compiled and so functional test suite also needs to go through the same cycle.&lt;br /&gt;&lt;br /&gt;So here are my reasons to choose a cool funky dynamic language to write your application level test suite.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Easier development cycle. Typically dynamic languages have more essence to ceremony ratio. They are lightweight. They don't have the type noise which static languages have as we don't need that kind of information in our functional tests a lot. Also dynamic languages being less ceremonious is easier to pick up and start working.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No wastage in compiling time. Most of the dynamic languages (Actually all I know) are not compiled and so donot have that long compile cycle. Typically functional test suites don't run as an application and donot have the same considerations as them. For functional tests, the quicker they run better the feedback cycle.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Easier to build abstractions. It is easier to build abstractions like frameworks, DSLs or Fluent Interfaces in dynamic languages. Less noise, more essence and better abstractions :)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Better drivers and libraries - Almost all the drivers I know are in dynamic languages. Watir, Selenium, WebDriver (Use with JRuby or python :), Celerity. Also you have frameworks like Rspec, Cucumber and Robot framework already available to build your test suite better. You have HttpDrivers, XmlParsers, JSonParsers or whatever infrastructure or libraries you need are available as well.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Easier to experiment with. Dynamic languages are lightweight to work with. They also typically come with a REPL which is a good place to learn and experiment. If you want to know how to play with a REST based service, fire up the REPL. Import a Http library and start sending requests. &lt;/li&gt;&lt;li&gt;They have a great community to work with. Difficult to substantiate but I can challenge that Ruby and Python community are way ahead in catching up with new stuff than .Net or Java. Also if you see Github and find the major languages of open source projects hosted there :).&lt;/li&gt;&lt;/ul&gt;May be there are more reasons. If you can think of any add them to the comments to discuss.&lt;br /&gt;&lt;br /&gt;If you are a developer or a tester in a team (I don't differentiate between both of these roles :), do yourself and your team a favor. If your development itself is a dynamic language, you lucky dog :). Else choose a suitable language of choice to write functional or end to end tests. Don't get into the dogma of using the same language as development language.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/eMMWVd8VtNY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/4831956242673901644/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=4831956242673901644" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/4831956242673901644?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/4831956242673901644?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/eMMWVd8VtNY/functional-test-suite-in-c-or-java-why.html" title="Functional Test suite in C# or Java... Why?" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>5</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/09/functional-test-suite-in-c-or-java-why.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08HQHkyeyp7ImA9WxNSE00.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-3911419279091233271</id><published>2009-08-26T10:12:00.000-07:00</published><updated>2009-08-26T11:03:51.793-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-26T11:03:51.793-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="Feedback" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Configure your Visual Studio to run your tests automatically</title><content type="html">It all started after I saw Misko Hevery demonstrating this technique of running unit tests whenever he saves code in Eclipse at his Thoughtworks Geek Night talk and reading his blog post on &lt;a href="http://misko.hevery.com/2009/05/07/configure-your-ide-to-run-your-tests-automatically/"&gt;it&lt;/a&gt;. I am a big sucker of fast feedback and always felt that faster the feedback, better it is. This technique to run unit tests, I felt is a big step towards it (Also my patience is too short for me to go and run the tests by navigating through menus :). Being a compulsive TDD guy, unfortunately in a .Net project and so forced to use Visual Studio (I have nothing to complain about. Move along :) every day, I felt the need for this badly. And so began my quest...&lt;br /&gt;&lt;br /&gt;I was looking for a way to hook into the save event of Visual Studio to do something same as Misko's but couldn't find any till now. The next best thing for me is Post Build Event hook. Conveniently this is available in Visual Studio for every project to be configured in project properties. So on the test project properties  "Build Events" section, you can hook into the pre and post build events to run some shell scripts.&lt;br /&gt;&lt;br /&gt;Prerequisites - Have nunit-console.exe in path or better have it in your project as a dependency. I have it inside my project root folder inside bin\NUnit. To run tests using nunit-console you need to pass your test assembly path to that. Also check the build order in your solution. Typically it will be Main project -&gt; Unit Tests.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Choose the project properties of the project which contains unit tests in your solution.&lt;/li&gt;&lt;li&gt;In the Build Event section of project properties, choose Run the post build event list box to be "On successful build" as I want my tests to run only when build completes without error.&lt;/li&gt;&lt;li&gt;In the Post-build event command line text area it is possible to write any shell script which will execute once the build is done. So refer to the nunit-console.exe here with your target assembly path (Your test project assembly). Conveniently here you have macro's to refer the parameters you need, so the job gets easier.Check out the screenshot of my configuration in post build event.&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_fSsd65KlPiM/SpV0mS4xlNI/AAAAAAAAASc/O1VFFUCWVLY/s1600-h/visual_stdio_build_event.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 250px;" src="http://2.bp.blogspot.com/_fSsd65KlPiM/SpV0mS4xlNI/AAAAAAAAASc/O1VFFUCWVLY/s400/visual_stdio_build_event.JPG" alt="" id="BLOGGER_PHOTO_ID_5374329931590374610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Now it is time to try out the cool thing :D.&lt;/li&gt;&lt;li&gt;Every time I refactor or add code or tests you build the code by ctrl + shift + b, I can find the build run and after successful build unit tests being run as a part of build.&lt;/li&gt;&lt;li&gt;The cool thing is if the unit test fails, it is a build failure :). So I make a small refactoring I build it and with in seconds I can see if I have broken something and fix it or do a ctrl + z if needed...&lt;/li&gt;&lt;/ul&gt;Check out the output from the build and unit tests.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_fSsd65KlPiM/SpV2YmSVbcI/AAAAAAAAASk/aoApNGo0fJQ/s1600-h/vs_build.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_fSsd65KlPiM/SpV2YmSVbcI/AAAAAAAAASk/aoApNGo0fJQ/s400/vs_build.JPG" alt="" id="BLOGGER_PHOTO_ID_5374331895302942146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;My Red Green Refactor cycle has just got shorter :). I have done this in the simplest way I know and it works for me. Let me know if there is a better way to do this&lt;br /&gt;&lt;br /&gt;Also I have done this as a part of my yet to be open sourced project FluentAssertions. No spoilers now but more on this soon...&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/PccXhFpAog0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/3911419279091233271/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=3911419279091233271" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/3911419279091233271?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/3911419279091233271?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/PccXhFpAog0/configure-your-visual-studio-to-run.html" title="Configure your Visual Studio to run your tests automatically" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_fSsd65KlPiM/SpV0mS4xlNI/AAAAAAAAASc/O1VFFUCWVLY/s72-c/visual_stdio_build_event.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/08/configure-your-visual-studio-to-run.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MMQXY8eCp7ImA9WxNSEk8.&quot;"><id>tag:blogger.com,1999:blog-3714679715645688593.post-1699138500773943666</id><published>2009-08-25T09:54:00.000-07:00</published><updated>2009-08-25T10:31:20.870-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-25T10:31:20.870-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Refactoring" /><category scheme="http://www.blogger.com/atom/ns#" term="Git" /><category scheme="http://www.blogger.com/atom/ns#" term="Agile" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Using Git As A Tool to Help In Refactoring</title><content type="html">I am a big fan of Git. Initially started as a urge to use the cool GitHub. But later when I started to realize the potential of Git itself the simplicity and power of this VCS amazes me. &lt;br /&gt;&lt;br /&gt;As most of you know Git is a distributed version control system (VCS). For those who haven't used it or heard of it (Please come out of SVN dark ages :) please do a Google search and you will find a flood of links hitting you. What I am write speak here is about my typical usage of Git and how it helps me in day to day refactoring making it easier. &lt;br /&gt;&lt;br /&gt;I am firm believer of RGR (Red Green Refactor) cycle. But beyond that I do a lot of micro refactorings like renaming variables, classes, moving behavior, adding tests etc as I thinking more about what I have written and finding better ways to express my code. &lt;br /&gt;&lt;br /&gt;Now the problem when I used to use SVN is that I have only two choices. Either I pile up these small refactorings to commit in my local copy which I don't really like. Or commit each one individually and trigger the build for every small change I make. Also if I pile up and commit, at the time of commit how can I express my intentions of the commit I am making. I never like to put a comment in commit which blankly says "Refactoring and adding some tests.". &lt;br /&gt;&lt;br /&gt;So how did Git change the picture? Git as most of you know is a two stage repository VCS. One repository may in remote server (incase of Github it does or a SVN repo if you use Git SVN) and other repository in your local machine which is also a complete repo of your source code. You can treat your local repo as a main repo and commit in it as many times as you want. This gives me a great advantage. &lt;br /&gt;&lt;br /&gt;Every refactoring I do can be tested and committed to the repository (local one) individually. I can express my intent of the commit of every refactoring. When I feel substantial amount of work is done I can push to the remote repo and continue with my next item of work. Also when I push I can see it as a series of work I have done on a feature not as one bulky piece. Typically I have this code, refactor, test and commit cycle for every five to ten minutes when I use Git. This is one amazing advantage which I have when using Git. Similar feelings will be expressed by people who use Mercurial as well.&lt;br /&gt;&lt;br /&gt;Also as an added advantage when build is broken and someone is fixing it I can still commit to my local repo and continue working and push my changes later. But we should be cautious not to pile up too much in our local repo that we distance ourselves with the mainline code base.&lt;br /&gt;&lt;br /&gt;Similar thoughts on using Git and Github has been expressed by Mark Needham &lt;a href="http://www.markhneedham.com/blog/2009/08/24/rock-scissors-paper-tdd-as-if-you-meant-it/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Let me know if you have similar experience as this.&lt;img src="http://feeds.feedburner.com/~r/Developer-in-test/~4/TQn6Wo2bG3c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://developer-in-test.blogspot.com/feeds/1699138500773943666/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3714679715645688593&amp;postID=1699138500773943666" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1699138500773943666?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3714679715645688593/posts/default/1699138500773943666?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Developer-in-test/~3/TQn6Wo2bG3c/refactoring-and-git.html" title="Using Git As A Tool to Help In Refactoring" /><author><name>Sai Venkatakrishnan</name><uri>http://www.blogger.com/profile/14442693638745288134</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="27" src="http://1.bp.blogspot.com/_fSsd65KlPiM/SYAZKHZO_3I/AAAAAAAAALU/Wspf_SefPkM/S220/Sun-Wukong-Monkey-King.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://developer-in-test.blogspot.com/2009/08/refactoring-and-git.html</feedburner:origLink></entry></feed>
