<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>8th Light Blog</title>
    <link>http://blog.8thlight.com</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In the minds of the craftsmen...</description>
    <item>
      <title>Wake up and code!</title>
      <description>&lt;p&gt;The other day, I was with my team at an interview for an internship.  After we had asked the candidate some questions, he started to reciprocate, asking each one of us a little about our development past.  Every one of the developers stories went something like, I was at the wrong job, and had to get out.  The candidate listened carefully to each story, sat for a minute, then asked the obvious perfect question, &amp;#8220;What makes the right job?&amp;#8221;  &lt;/p&gt;

&lt;p&gt;I heard responses like &amp;#8220;Waking up in the morning and being excited to work, rather than counting the days until the weekend.&amp;#8221;  The reason this struck me as interesting was only when I reflected back to why I loved computers and programming in the beginning.  It was all about the problem.  I went to college, so I could join the CIA or some think tank which wrote software which monitored and defeated the enemies entire world.  About every developer I went to college with got into computer science with some similar grandiose notion.  Most of them were gamers that wanted to work on the next big game.  Yet today, I know no developer who works on games, and I don&amp;#8217;t work for a think tank.  I know lots of developers who are more than qualified to do it, but choose not to.  So, how does this relate to the right job question?&lt;/p&gt;

&lt;p&gt;The answers about the right job question had nothing to do with the problem set being solved either.  Nothing to do with WHAT applications were being written, but the culture and with whom they are being written.  I think this is because each problem set worth application development proposes unique and interesting problems for a developer to solve.  I have never been on a project which didn&amp;#8217;t constantly keep me on my toes as far as problems to be solved.  Even if the business domain is a bit bland, the development domain isn&amp;#8217;t.  I have seen developers to do lists get bigger and bigger from day one on a project, and never shrink.  This has nothing to do with laziness, quite the opposite, it has to do with an insatiable drive to make things better than they are.&lt;/p&gt;

&lt;p&gt;As a developer, my problem set isn&amp;#8217;t the business/science problems I am solving, even though that might be interesting in itself.  My problem set is development itself, the different patterns/practices I use to solve the world&amp;#8217;s [software] problems.  It is like many art forms where the beauty and creativity exists in the process of creation rather than the results.  I am sure you could have asked Pablo Picasso to paint something he didn&amp;#8217;t have any interest in, and he would have been passionate about it and done a wonderful job.  I suspect it is because the importance is in the painting process and the choices you make during each step.  How he chooses to depict the subject is more interesting more than the nature of the subject itself.  I find the same true in development.  The thought that goes into the different development choices I make on a daily basis is the part that drives me to love development. &lt;/p&gt;

&lt;p&gt;Having the right results is only part of the equation (an essential part though).  When I started my path as a developer craftsman, I learned the WHAT in applications is not as important as all the other variables.  I suspect some of the other members on my team would agree, based on their answers to the right job question.  Being part of a company that values the software for its own ends and spends the time and attention to do it right is a privilege to me.  To me, that is the definition of the right job.  I enjoy knowing my software will be used.  Everything I write is valuable to the company for its longevity and success.  It takes people who are similar in values for it to work, but it makes the work fun.  It makes me wake up before my alarm, rather than snoozing.&lt;/p&gt;</description>
      <pubDate>Fri, 09 May 2008 00:34:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c1da41df-47d9-4dec-825e-6dccf0a68e29</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/05/09/wake-up-and-code</link>
      <category>Coding</category>
      <category>Etiquette</category>
    </item>
    <item>
      <title>Chirb Presentation</title>
      <description>&lt;p&gt;I gave a Chirb presentation last night on RubyCocoa, which went reasonably well.  The slides, the working versions, are here.  Unfortunately the images do not show in Safari, so you may want to use Firefox.&lt;/p&gt;

&lt;iframe src="http://show.zoho.com/embed?USER=paytonrules&amp;DOC=ruby-cocoa-presentation-odp&amp;IFRAME=yes" height="335" width="450" name="ruby-cocoa-presentation-odp" scrolling=no frameBorder="0" style="border:1px solid #AABBCC"&gt;&lt;/iframe&gt;</description>
      <pubDate>Tue, 06 May 2008 13:55:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:d072203b-e2a9-44ea-b019-b12874f65b37</guid>
      <author>Eric</author>
      <link>http://blog.8thlight.com/articles/2008/05/06/chirb-presentation</link>
      <category>Coding</category>
      <category>Eric</category>
      <category>RubyCocoa</category>
    </item>
    <item>
      <title>Bowled Over by RubyCocoa</title>
      <description>&lt;p&gt;Last year I wrote a RubyCocoa tutorial that&amp;#8217;s been aggregated in a few places and referenced a couple times*.  By my standards it was an overwhelming response.  A few things have changed since then, most notably Mac has embraced Ruby.  It&amp;#8217;s installed with Leopard, RubyCocoa has been put on it as well, all of which is great news.  The drawback is that my tutorial has gone out of date, as XCode has changed too.  Guess I&amp;#8217;m gonna have to write a new one.&lt;/p&gt;

&lt;p&gt;Naturally my first thought was to update the original tutorial, with new pictures, but I&amp;#8217;ve got two problems with that.  One, it&amp;#8217;s boring.  Not for you - for me!  Large portions of it haven&amp;#8217;t changed aside from some differences in the screenshots and installation.  Why should I explain what Cocoa is again?  I just couldn&amp;#8217;t get motivated.  The second is that I have an issue with the way programming APIs are taught.  Why is it that developers, such as myself, who have embraced testing abandon it in example code?  This is especially true in GUI code, where often the simple examples have more complicated tests.  Unit testing is so important we should be able to teach APIs Test-First, and in that spirit we&amp;#8217;re going to a classic example of TDD using RubyCocoa.  This should teach you how to get up and running and well as make the tutorial a heck of a lot more interesting.  For me anyway.&lt;/p&gt;

&lt;h3&gt;Bowling&lt;/h3&gt;

&lt;p&gt;If you&amp;#8217;d like to see about 4000000 examples of the bowling game head over to Ron Jefferies website at xprogramming.com.  It&amp;#8217;s a typical example of solving an algorithmic problem using TDD, and often used as a &lt;em&gt;kata&lt;/em&gt; or practice session.  We&amp;#8217;ll do this following Uncle Bob&amp;#8217;s &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd"&gt;three rules of TDD&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are not allowed to write any production code unless it is to make a failing unit test pass.&lt;/li&gt;
&lt;li&gt;You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.&lt;/li&gt;
&lt;li&gt;You are not allowed to write any more production code than is sufficient to pass the one failing unit test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We&amp;#8217;ll use RSpec for this exercise.&lt;/p&gt;

&lt;h3&gt;Basics&lt;/h3&gt;

&lt;p&gt;If you aren&amp;#8217;t familiar with Cocoa at all, take a peek at the &amp;#8220;What the Heck is Cocoa&amp;#8221; section &lt;a href="http://blog.8thlight.com/articles/2007/08/13/rubycocoa-tutorial"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Installation&lt;/h3&gt;

&lt;p&gt;If we want to make an awesome bowling game using RubyCocoa we&amp;#8217;re going to need to install RubyCocoa.  This tutorial is assuming you&amp;#8217;re using Leopard, which means you have two steps.  The first is to install XCode from the disc that came with the operating system.  I&amp;#8217;m not going to explain that here, I assume you can open a disc and click an installation.  For adding RubyCocoa so we can write this slick Mac App you have three options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install from source.  A big part of the reason you haven&amp;#8217;t seen this doc earlier is because I&amp;#8217;ve repeatedly attempted to install from source, and failed miserably before getting it right.&lt;/li&gt;
&lt;li&gt;Install from the latest binary release.  That&amp;#8217;s found &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=44114"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Do absolutely nothing, say it again.  If you&amp;#8217;re on Leopard, it&amp;#8217;s already there for you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step three sounds tempting but there&amp;#8217;s a catch.  If you&amp;#8217;ve used MacPorts to update ruby, you may find that your Ruby and RubyCocoa installations don&amp;#8217;t match up.  See Verifying your installation below.  Because of this I highly recommend the &amp;#8220;do nothing&amp;#8221; choice if you can get away with it.  The latest Apple Software Update even updated the bridge, so you won&amp;#8217;t be very behind anyway.&lt;/p&gt;

&lt;p&gt;We also need RSpec as we&amp;#8217;ll be using it for our unit testing.&lt;/p&gt;

&lt;pre&gt;
sudo gem install rspec.
&lt;/pre&gt;

&lt;p&gt;The great thing about RSpec is it reads extremely well to the uninitiated, so I won&amp;#8217;t be explaining RSpec as I go.&lt;/p&gt;

&lt;h3&gt;Verifying your installation&lt;/h3&gt;

&lt;p&gt;After installing however you want to install, go to irb and type require &amp;#8216;osx/cocoa&amp;#8217;.  If you get true then your system is setup properly for rubycocoa development.  If not you may need to tweak some environment variables, or worse install from source.  I&amp;#8217;ll have a blog post on that soon.&lt;/p&gt;

&lt;h3&gt;Your first project&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;ll need to create a new RubyCocoa project.  Start up XCode and create a new Cocoa-Ruby project.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080419-f1t16a4p4hye8ixsuhqg1sqht3.jpg" alt="New Project"/&gt;&lt;/p&gt;

&lt;p&gt;Your screen will probably look different, unless you have the iPhone development kit installed too.  The important thing is that you select Cocoa-Ruby application.  Create the project with whatever name you like, as long as you call it bowling.  This will generate an application skeleton in XCode.  Let&amp;#8217;s create our super slick bowling game interface in Interface Builder.  Double Click Main Menu.nib in your XCode project file.  From there you should get windows like the following (I&amp;#8217;ve arranged them to fit the window better):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.8thlight.com/files/2008-03-22_interface_builder.gif" alt="Interface Builder" height="791" width="708"/&gt;&lt;/p&gt;

&lt;p&gt;Your Window won&amp;#8217;t be there yet.  In the Nib Document window, that&amp;#8217;s the one with MainMenu.nib on top, double-click the Window icon.  That Window represents your dialog box.  You can see it on the screen in the picture above.  Now select the Window icon again and hit Apple-Shift-I to bring up the Inspector for that window.  &lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.8thlight.com/files/2008-03-22_inspector_1.gif" alt="Inspector 1" height="408" width="287"/&gt;&lt;/p&gt;

&lt;p&gt;This shows the properties for the Window at the moment, but will change whenever you select a different object. Change the name of the window to bowling now.  Our bowling game is on the honor system.  You enter your score, press roll, and it tells you the running tally of your current score and your current frame.  This is a little different than the typical implementation, since those simply spit out a total score after all your rolls.  First you need a button so lets select a push button from the Library and drag it to the window.  The easiest thing to do is in the bottom spotlight window type Push Button and it will find that button for you.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080323-qtijsqatk77fyg6b21yp6ixwqc.jpg" alt="Library Push Button"/&gt;&lt;/p&gt;

&lt;p&gt;Drag the push button onto your window.  You can rename it to roll simply by double-clicking on the button and changing the text.  Let&amp;#8217;s make a dialog that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080323-ehsu81jggq3jbipst67ne7t7qn.jpg" alt="Bowling"/&gt;&lt;/p&gt;

&lt;p&gt;I admit not my best work as designs go, but the focus of this tutorial is test-driven GUI code not Interface Builder.  This dialog is made up of one Text Field and five Labels.  You should be able to search for them just like you did for the Push Button.  The important thing to remember is that there are four labels on the bottom.  Two for the headings (Score and Frame) and two for the actual totals (currently 0 and 0).  Congratulations we have our dialog box.  If you go back to the XCode view and click Build and Go you&amp;#8217;ll see the exact same view.  Of course nothing does&amp;#8230;anything.  That&amp;#8217;s why we need to write some code&amp;#8230;er tests.  Remember rule #1:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are not allowed to write any production code unless it is to make a failing unit test pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Normally at this point we&amp;#8217;d start making outlets, actions, and connections but we&amp;#8217;re not going to do that here.  The reason?  We don&amp;#8217;t have tests.  Have I said that enough yet?  To get up and running with RSpec it&amp;#8217;s really best to open up your project in something like Textmate but since this is a tutorial and I can&amp;#8217;t make you use my machine I&amp;#8217;m going to assume you&amp;#8217;ll be creating your files in XCode and running the specs with the terminal.  Given that we have a view I think it&amp;#8217;s safe to assume we&amp;#8217;ll have a controller.  Create a file called bowling_controller_spec.rb in the root of your project.  As a rule you&amp;#8217;ll want have a separate location for your specs, but this will work just fine for our project.  If you&amp;#8217;re using the XCode interface you can use the Ruby test case class, we&amp;#8217;ll be removing all the code anyway so it doesn&amp;#8217;t really matter, the important thing is to create the file.  Do not add it to the Bowling target, this isn&amp;#8217;t shipped as part of the product.  Our first spec is going to have well - nothing.  Remove any generated code in that spec and replace it with this:&lt;/p&gt;

&lt;pre&gt;
describe BowlingController do
end
&lt;/pre&gt;

&lt;p&gt;To run it you can use the terminal and type spec bowling_controller_spec in your Bowling directory.  You should see this:&lt;/p&gt;

&lt;pre&gt;
$ spec bowling_controller_spec.rb 
./bowling_controller_spec.rb:9: uninitialized constant BowlingController (NameError)
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/example_group_runner.rb:14:in `load'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/example_group_runner.rb:14:in `load_files'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/example_group_runner.rb:13:in `each'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/example_group_runner.rb:13:in `load_files'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/options.rb:85:in `run_examples'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/lib/spec/runner/command_line.rb:19:in `run'
    from /opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.3/bin/spec:4
    from /opt/local/bin/spec:16:in `load'
    from /opt/local/bin/spec:16
&lt;/pre&gt;

&lt;p&gt;Congrats!  You&amp;#8217;ve got a failing test.  What do we need to do to make that pass?  We need a controller of course.  Create a new class and call it BowlingController (bowling_controller.rb).  You need to use XCode this time and make sure you add it to the Bowling Target, otherwise it won&amp;#8217;t be executed later.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080419-pui9xxkb49q6mwnxa2ytg4c6q6.jpg" alt="New File"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080419-tpx7m99rfip6thf2iq814h49up.jpg" alt="New File"/&gt;&lt;/p&gt;

&lt;p&gt;The class should look like this:&lt;/p&gt;

&lt;pre&gt;
class BowlingController
end
&lt;/pre&gt;

&lt;p&gt;Run the test - we &amp;#8230;still don&amp;#8217;t pass.  We&amp;#8217;ll need to require that bowling controller in our spec.&lt;/p&gt;

&lt;pre&gt;
require 'bowling_controller'

describe BowlingController do
end
&lt;/pre&gt;

&lt;p&gt;Well man we&amp;#8217;re cooking with gas now.  What does a BowlingController do?  Well let&amp;#8217;s go over some Cocoa concepts.  In Cocoa objects have actions and outlets.  An action is a method in your object that can be triggered by another Cocoa object.  An outlet is a reference to another object that was instantiated by Cocoa.  Put more simply actions are methods, objects are things.  So let&amp;#8217;s look back at our glorious UI design.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080323-ehsu81jggq3jbipst67ne7t7qn.jpg" alt="Bowling"/&gt;&lt;/p&gt;

&lt;p&gt;Ahhhh.  I could look at it all day.  There is one action here, the pushing of the roll button.  There&amp;#8217;s three outlets: the score, the frame, and the number of pins.  Can you see the difference yet?  Since we&amp;#8217;re test driving the app we&amp;#8217;re going to start with the action.  First let&amp;#8217;s write a test.  Put this between the describe &amp;#8230; end block in your spec:&lt;/p&gt;

&lt;pre&gt;
before(:each) do
  @controller = BowlingController.new  
end

it "should roll a ball" do
  @controller.roll
end
&lt;/pre&gt;

&lt;p&gt;There&amp;#8217;s a couple things worth paying attention to here.  The before(:each) block will create the controller for each test.  I think it&amp;#8217;s a safe assumption we&amp;#8217;ll have more than one.  Second notice that our it block isn&amp;#8217;t a coherent test yet.  So why do we stop?  Because when we run that test it fails - roll is not a method.  That&amp;#8217;s enough to make us write some code to make the test pass.  These cycles should typically take less time than it does for me to explain them.  Now I know this seems stupid, and I almost certainly wouldn&amp;#8217;t write my tests at this granular a level if this wasn&amp;#8217;t an example, but when I write my tests this small a few things happen.  Firstly my code is almost always better.  The larger my tests the more room for error.  The second is my tests tell a story, which can be followed by the next guy through my code to see what I was doing.  Finally whenever I mess up (quite frequently) I can always go back with a couple undos.  Now quit you&amp;#8217;re whining and let&amp;#8217;s make the test pass.&lt;/p&gt;

&lt;pre&gt;
class BowlingController

  def roll

  end
end
&lt;/pre&gt;

&lt;p&gt;See that wasn&amp;#8217;t so hard.  Now let&amp;#8217;s make that test more useful.  When we roll a ball we get the value from the Text Field on the screen.  We use outlets to reference other Cocoa objects, so we&amp;#8217;ll need an outlet that references that Text Field.  Let&amp;#8217;s call it pins.  To get a value from a Text Field we can call one of many methods on the NSTextField class, in this case we know it is going to be an integer so let&amp;#8217;s use the intValue method.  This is demonstrated with a mock object, which is built into RSpec, and we&amp;#8217;ll be adding this to our test.&lt;/p&gt;

&lt;pre&gt;
it "should roll a ball and get the value from the pins outlet" do
  mock_text_field = mock('Pins')
  @controller.pins = mock_text_field

  mock_text_field.should_receive(:intValue).and_return(0)
  @controller.roll
end
&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;m using the same test I did before, only I&amp;#8217;ve extended it.  I&amp;#8217;ve said I should have a mock that receives the value intValue when the roll method has been called.  What I love about this test is that it explains just how data is retrieved from the pins outlet, in an executable way.  Now lets run it&amp;#8230;kaboom!  There&amp;#8217;s no pins= method.  Broke my own rule didn&amp;#8217;t I?  We don&amp;#8217;t have a method pins=, but we also know that mock object is going to fail.  That&amp;#8217;s two failures not one.  &lt;/p&gt;

&lt;pre&gt;
class BowlingController
  attr_accessor :pins

  def roll

  end
end
&lt;/pre&gt;

&lt;p&gt;Okay we&amp;#8217;ve got a new error: &amp;#8216;Pins&amp;#8217; expected :intValue with (any args) once, but received it 0 times.  This is great, let&amp;#8217;s call it and get it to pass.&lt;/p&gt;

&lt;pre&gt;
class BowlingController
  attr_accessor :pins

  def roll
    @pins.intValue
  end
end
&lt;/pre&gt;

&lt;p&gt;Okay we&amp;#8217;ve got a passing test, but do we have a useful controller?  I should say not.  None of this code is aware of Cocoa, and we can fake this out all day but at some point we have to make this accessor a true outlet.  The question is how do we make this object cocoa aware?&lt;/p&gt;

&lt;p&gt;A quick lesson on the Cocoa class hierarchy. The base class is NSObject, which is represented in RubyCocoa as OSX::NSObject.  In order to know about outlets, actions, and any grand Cocoa thing we&amp;#8217;ll need to make our class a Cocoa object.  So before continuing to make roll more useful, let&amp;#8217;s write a test for that.&lt;/p&gt;

&lt;pre&gt;
it "should be an OSX::NSObject" do
  @controller.is_a?(OSX::NSObject).should == true
end
&lt;/pre&gt;

&lt;p&gt;Run that spec and you get&amp;#8230;hmm, uninitialized constant OSX.  We&amp;#8217;re going to need to require the files because even though when you&amp;#8217;re running a RubyCocoa application everything is included for you we&amp;#8217;re running our tests independent of the application.  Require &amp;#8216;osx/cocoa&amp;#8217; at the top of bowling controller.  Ah here it is:&lt;/p&gt;

&lt;pre&gt;
'BowlingController should be an OSX::NSObject' FAILED
expected: true,
     got: false (using ==)
./bowling_controller_spec.rb:18:
&lt;/pre&gt;

&lt;p&gt;Make it inherit from OSX::NSObject and we&amp;#8217;re good to go.  See that?  We just made a Ruby object inherit from a Cocoa object.  Pretty cool eh?  Now about that accessor - pins.  I mentioned earlier that Cocoa uses outlets to communicate with the other objects in it&amp;#8217;s world.  An accessor may make our test pass, but it won&amp;#8217;t make our application work.  We need it to be an outlet, and there we&amp;#8217;ve got ourselves a problem.  You see outlets aren&amp;#8217;t really anything special at all from a programmatic perspective.  We wire those parts together in Interface Builder, save it to the Nib file, and when the Cocoa application starts up it figures out everything it needs to instantiate.  In fact in Objective-C they are declared with an empty macro, in RubyCocoa we use the command ib_outlets which just makes a writer attribute on the class.  So how do we test this?  Unfortunately, we don&amp;#8217;t, breaking rule #3.  You see we could write everything without the tags, but Interface Builder wouldn&amp;#8217;t magically find the attributes so we&amp;#8217;d have to add them manually.  Since tagging these objects as outlets doesn&amp;#8217;t actually change behavior you can grind your teeth to tiny nubs and change the pins to an outlet:&lt;/p&gt;

&lt;pre&gt;
class BowlingController &lt; OSX::NSObject
  ib_outlets :pins

  def roll
    @pins.intValue
  end
end
&lt;/pre&gt;

&lt;p&gt;We&amp;#8217;ve got one other issue here, roll isn&amp;#8217;t marked as an action.  In the same vein as ib_outlets we&amp;#8217;re going to mark this as an action with the ib_action delcaration.&lt;/p&gt;

&lt;pre&gt;
ib_action :roll
def roll
  @pins.intValue
end
&lt;/pre&gt;

&lt;p&gt;Also worth noting is that every Cocoa action has a sender, sent as a parameter, but I&amp;#8217;ve omitted that here as we won&amp;#8217;t be using it so it&amp;#8217;s not necessary.  The typical Cocoa style is to keep it in as a parameter, because standard Objective-C Cocoa needs it, but I don&amp;#8217;t understand why we need the clutter.  From this point forward we need to implement the rest of the controller.  This blog is getting exceedingly long, so I&amp;#8217;m going to just put the tests and the code, one at a time, until our controller is implemented.&lt;/p&gt;

&lt;p&gt;Note I&amp;#8217;ve added the mocks to the before(:each) because I&amp;#8217;ll need them more than once.&lt;/p&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
before(:each) do
  @controller = BowlingController.new
  @bowling = mock('Bowling')
  @text_field = mock('Pins')
  @text_field.stub!(:intValue).and_return(10)
  @controller.pins = @text_field
end

...

it "should have an outlet to a bowling object" do
  @controller.bowling = @bowling
end
&lt;/pre&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
class BowlingController &lt; OSX::NSObject
  ib_outlets :pins, :bowling
&lt;/pre&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
it "should send the pin value to the bowling object" do
  @bowling.should_receive(:roll).with(10)

  @controller.roll
end
&lt;/pre&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
ib_action :roll
def roll
  @bowling.roll(@pins.intValue)
end
&lt;/pre&gt;

&lt;p&gt;OOPS!  Better setup the bowling object in the before each.&lt;/p&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
before(:each) do
  @controller = BowlingController.new
  @bowling = mock('Bowling')
  @text_field = mock('Pins')
  @text_field.stub!(:intValue).and_return(10)
  @controller.pins = @text_field
  @controller.bowling = @bowling
  @bowling.stub!(:roll)
end
&lt;/pre&gt;

&lt;pre&gt;
it "should have an outlet to the score" do
  @score = mock('Score')
  @controller.score = @score
end
&lt;/pre&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
class BowlingController &lt; OSX::NSObject
  ib_outlets :pins, :bowling, :score
&lt;/pre&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
before(:each) do
  ...
  @bowling.stub!(:roll)
  @bowling.stub!(:score).and_return(100)
  @score = mock('Score')
  @controller.score = @score
  @score.stub!(:setIntValue)
end

...

it "should update the score with the new score from the roll" do
  @bowling.should_receive(:roll).ordered
  @bowling.should_receive(:score).ordered.and_return(100)
  @score.should_receive(:setIntValue).ordered.with(100)

  @controller.roll
end
&lt;/pre&gt;

&lt;p&gt;I want to pause and point out we&amp;#8217;ve got a new method here.  This is where our tests come in handy.  We can see just from looking at the tests that setIntValue and intValue are called on outlets to get and set values from them.  We&amp;#8217;re using mocks to demonstrate how we use that API, and by the way we&amp;#8217;re building our tests we can see our tests tell the story of how this controller was built.  You should also see I&amp;#8217;ve made a bowling
object, the Model in the MVC setup, that is also an outlet.  I&amp;#8217;ve done that because once we&amp;#8217;ve setup this controller and that object in Interface Builder, the Cocoa framework will properly handle the creation of the objects if they are outlets.  Back to the code&amp;#8230;.&lt;/p&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
ib_action :roll
def roll
  @bowling.roll(@pins.intValue)

  @score.setIntValue @bowling.score
end
&lt;/pre&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
it "should have an outlet to the frame" do
  @frame = mock('Frame')
  @controller.frame = @frame
end
&lt;/pre&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
class BowlingController &lt; OSX::NSObject
  ib_outlets :pins, :bowling, :score, :frame
&lt;/pre&gt;

&lt;h4&gt;test&lt;/h4&gt;

&lt;pre&gt;
before(:each) do
...
  @frame = mock('Frame')
  @controller.frame = @frame
  @frame.stub!(:setIntValue)
  @bowling.stub!(:frame).and_return(9)
end

...

it "should update the current frame with the frame from the bowling object" do
  @bowling.should_receive(:roll).ordered
  @bowling.should_receive(:frame).ordered.and_return(9)
  @frame.should_receive(:setIntValue).ordered.with(9)

  @controller.roll
end
&lt;/pre&gt;

&lt;h4&gt;code&lt;/h4&gt;

&lt;pre&gt;
def roll
  @bowling.roll(@pins.intValue)

  @score.setIntValue @bowling.score
  @frame.setIntValue @bowling.frame
end
&lt;/pre&gt;

&lt;p&gt;Great!  We&amp;#8217;ve done it.  We&amp;#8217;ve implemented a controller that plays bowling.  Unfortunately since it uses a bowling object we haven&amp;#8217;t created it doesn&amp;#8217;t actually &amp;#8230;do &amp;#8230; anything yet.  This blog post is really about RubyCocoa and not about bowling, which is an article on it&amp;#8217;s own.  So I&amp;#8217;m going to just write a copy of bowling &lt;a href="http://blog.8thlight.com/files/bowling.rb"&gt;here&lt;/a&gt; and if you want to use it just save it into the same directory as your controller, although I recommend writing your own.&lt;/p&gt;

&lt;p&gt;So we&amp;#8217;ve got a controller and a model, now we must make Interface Builder aware of it and build our wicked awesome application.  That&amp;#8217;s right, it&amp;#8217;s wicked awesome.  Open up Interface Builder and make sure you&amp;#8217;ve got the Library window open.  Go to Objects &amp;amp; Controllers and choose the an NSObject.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080413-qq52d9825ryupsmu9irj67xdqf.jpg"/&gt;&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll need to create two of these, one for each class in your application.  Remember how they inherited from OSX::NSObject?  Well drag the first NSObject over to the Nib Document window.  Using the inspector name it BowlingController.  Then, and this is the cool part, open finder and drag the bowling_controller.rb file into the Nib Document window.  There will be a brief pause then open the Inspector again.  You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080413-ni624cekyqxp38kxdijkr8gw7p.jpg" alt="Bowling Controller Identity"/&gt;&lt;/p&gt;

&lt;p&gt;See those outlets and actions?  Previously we had to do all that in Interface Builder, and get it right the first time, otherwise regenerate it.  There were ways around it, but I much prefer this way.  Anytime you&amp;#8217;ve changed the outlets and actions you simply drag the new class.  Now do the same thing with the bowling class.  The outlets and actions are are in the Nib File, along with their associated implementation, but your Cocoa application still doesn&amp;#8217;t know how are they connected. Pause and take a minute to think about this, how does BowlingController know what pins points to?  How about bowling?  The answer is it doesn&amp;#8217;t, we&amp;#8217;ll be embedding that information into the Nib file here.  To do that you drag from the item that needs to know something to the item it needs to know about.  Let&amp;#8217;s try this with our famous action, the Roll button.  Hold the ctrl key and drag to the bowling controller.  Unfortunately I can&amp;#8217;t get a screenshot since I can&amp;#8217;t ctrl-drag and take the nice shot at the same time, but what you should see is a blue line from the Roll button that you&amp;#8217;ll drag to the bowling controller.  When you let go the screen should flash Received Actions roll:, click the roll.  To verify completeness open BowlingController in the inspector and click the Connections tab, that&amp;#8217;s the blue circle with the error in it, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080420-pw36b7pk2bgccahp5j4dfsfnft.jpg" alt="Bowling Controller Connections"/&gt;&lt;/p&gt;

&lt;p&gt;Under received actions it shows that roll: is connected to Push Button (Roll).  Embedded in the Nib file is the information Cocoa needs to send the message roll to BowlingController when the button is pushed.  Now we need to connect the rest of the conections.  Connect from the BowlingController to the pins Text Field, the score, and the frame.  Finally connect from BowlingController to the Bowling object.  Remember you&amp;#8217;re going from BowlingController to the other objects because BowlingController is using those outlets.  Each time you&amp;#8217;ll be asked to pick the proper outlet, and if you named your outlet properly this should be obvious.  You should see this in your inspector for BowlingController when you are done.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080420-e57iqp5gari5cqygnpbj5n5mh4.jpg" alt="Bowling Controller Connections"/&gt;&lt;/p&gt;

&lt;p&gt;Well build that puppy.  Holy cow it works!&lt;/p&gt;

&lt;p&gt;Well it should.  If it doesn&amp;#8217;t you may have made one of the classic blunders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did you make sure that bowling_controller.rb and bowling.rb are in your build target?&lt;/li&gt;
&lt;li&gt;Do all your tests pass?&lt;/li&gt;
&lt;li&gt;Did you save your Nib file?&lt;/li&gt;
&lt;li&gt;Are all you connections drawn?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well that about does it for me, I hope this helped you learn a bit about TDD and a bit about RubyCocoa.  Here&amp;#8217;s a quick review:&lt;/p&gt;

&lt;div style="border: 1px solid black; background-color: silver"&gt;
    &lt;b&gt;Learned Concepts:&lt;/b&gt;
    &lt;ul&gt;
        &lt;li&gt;What is Cocoa?  What is RubyCocoa? (check my earlier blog)&lt;/li&gt;
        &lt;li&gt;Installing RubyCocoa.&lt;/li&gt;
        &lt;li&gt;Test-Driving your first controller.&lt;/li&gt;
        &lt;li&gt;Basics of Outlets.&lt;/li&gt;
        &lt;li&gt;Basics of Actions.&lt;/li&gt;
        &lt;li&gt;Connecting Outlets and Actions.&lt;/li&gt;
        &lt;li&gt;Instantiating Cocoa Outlets.&lt;/li&gt;
        &lt;li&gt;Importing Ruby classes into a Nib file.&lt;/li&gt;
        &lt;li&gt;Inheriting from NSObject&lt;/li&gt;
        &lt;li&gt;Getting a value from an outlet.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;
Here&amp;#8217;s hoping this helped put to bed the myth that GUIs can&amp;#8217;t be tested as well.&lt;/p&gt;

&lt;p&gt;* &lt;a href="http://www.rubyinside.com/the-ultimate-list-of-rubycocoa-tutorials-tips-and-tools-728.html"&gt;RubyInside&lt;/a&gt; thanks for the cite of my original tutorial.  For future reference my last name is Smith, which is actually more anonymous than &amp;#8220;X&amp;#8221;.&lt;/p&gt;</description>
      <pubDate>Sun, 20 Apr 2008 22:28:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a552f5df-9570-47fc-9594-e39dbd8f6d77</guid>
      <author>Eric</author>
      <link>http://blog.8thlight.com/articles/2008/04/20/bowled-over-by-rubycocoa</link>
      <category>Eric</category>
      <category>RubyCocoa</category>
      <category>TDD</category>
    </item>
    <item>
      <title>Rinda and setting up Rindlets</title>
      <description>&lt;p&gt;Jim Suchy recently laid down some basics of Rinda in his blog &lt;a href="http://blog.8thlight.com/articles/2008/02/12/rinda-101"&gt;Rinda 101&lt;/a&gt;.  I would like to build on that and talk a little about the rindlet architecture.  A rindlet is some process that is listening to the tuplespace, waiting to read or take messages.  &lt;/p&gt;

&lt;p&gt;When a tuple is written to the tuplespace, the rindlet will look at the message and determine if this is a tuple of interest to it.  If it is, then the engines warm up and the tuple gets processed by the logic in the rindlet.  Otherwise, the rindlet will take a pass, and wait for another message to be written to the tuplespace.&lt;/p&gt;

&lt;p&gt;These rindlets are autonomous and asynchronous pieces of business logic that are messaging across many systems, or across many modules of the same system.  We deploy them as daemon processes.&lt;/p&gt;

&lt;p&gt;As a proof of concept, Jim and I built a trivia game, with two different interfaces.  One will be a rich client, developed using a ruby framework called &lt;a href="http://blog.8thlight.com/articles/2008/02/05/limelight-at-railsconf-2008"&gt;limelight&lt;/a&gt;, and one will be a command line ruby client.&lt;/p&gt;

&lt;p&gt;Lets look at the code in the rich client application which updates the question on a screen for all the trivia participants to answer.&lt;/p&gt;

&lt;pre&gt;
require 'rinda_client'

module CurrentQuestion

  def start_update_question
    Thread.new(self) do |current_question|
      while true
        update_question(current_question)
        sleep 1
      end
    end
  end

  def question_update(current_question)
    client = Rinda::RindaClient.new
    tuple = client.read ["questioner", "response", "current question"], 1

    unless tuple.nil?
      current_question.text = tuple[3] 
      current_question.update
    end

  end

end
&lt;/pre&gt;

&lt;p&gt;This code spawns a thread to sit and listen to the rinda server to see if there are any new questions.  The questioner rindlet will post a tuple called &#8220;current question&#8221; every 30 seconds to change the question.  After we create a rinda client, we set up the match criteria for the tuples we are interested in.&lt;/p&gt;

&lt;pre&gt;
tuple = client.read ["questioner", "response", "current question"], 1
&lt;/pre&gt;

&lt;p&gt;We want to read all tuples that match&lt;/p&gt;

&lt;pre&gt; 
["questioner", "response", "current question"]
&lt;/pre
with a timeout of 1 second.  The matching criteria we used was very deliberate, we use the first parameter to indicate the name of the rindlet the tuple was written from, the second parameter indicating if this tuple is a request or response, and the third parameter indicating the action being requested or responded to.  All parameters after this third parameter (by convention only) are the information you need to send to the client of your tuple.  In this case, after we check to see if we have a tuple, we are interested in:

&lt;pre&gt;
current_question.text = tuple[3] 
&lt;/pre&gt;

&lt;p&gt;The fourth parameter, which is the question text to display on the screen.  &lt;/p&gt;

&lt;p&gt;This example shows you can integrate your application with rinda.  Your application can listen to the tuplespace to get messages that are relevant only to it.  If you are writing a rails application, then you would have to use the view helper periodically call remote, since rails is single threaded, it isn&amp;#8217;t as easy as firing a thread and moving on.&lt;/p&gt;

&lt;p&gt;Lets start with some rindlet code.&lt;/p&gt;

&lt;pre&gt;
require "rindlet"

class QuestionerRindlet &lt; Rinda::Rindlet

  def run
    with_standard_tuple("questioner", "next question") do |tuple|
      game = Game.active_game

      question_text = nil
      if game.nil?
        question_text = "No active game!"
      else
        question = game.next_question
        question_text = question.nil? ? "No more questions!" : question.text
      end

      @rinda_client.write(["questioner", "response", "current question", "#{question_text}"])
    end
  end

end
&lt;/pre&gt;

&lt;p&gt;First, the with&lt;em&gt;standard&lt;/em&gt;tuple method is a standard wrapper to match elements and take the tuple if it matches and pass it into the block.  Alternatively, you could do:&lt;/p&gt;

&lt;p&gt;tuple = client.take [&amp;#8220;questioner&amp;#8221;, &amp;#8220;request&amp;#8221;, &amp;#8220;next question&amp;#8221;] &lt;/p&gt;

&lt;p&gt;The rindlet itself then gets the next question from the game, and writes a tuple back to the tuplespace with a response, containing the question text.  Notice the code in this rindlet feels a lot like controller code in the MVC pattern.  Since rinda is a technology and notation of communication, it will just call the business logic in the models and respond to the actions performed if needed.  Rindlets often behave as system level controllers, not specific to any one application.&lt;/p&gt;

&lt;p&gt;I have had lots of fun getting rindlets to work, and they have been an interesting tool for decoupling business logic from any specific application.  Happy coding!&lt;/p&gt;

&lt;p&gt;Note:  I will soon be releasing a rinda gem with the rinda server and the base rindlet class, amongst some of its functionality.&lt;/p&gt;</description>
      <pubDate>Thu, 17 Apr 2008 02:59:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:72f3a71e-67ef-48e6-89f9-db4ba5a9a069</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/04/17/rinda-and-setting-up-rindlets</link>
      <category>Coding</category>
      <category>Rinda</category>
    </item>
    <item>
      <title>Agile Production Support: Final brush strokes</title>
      <description>&lt;p&gt;There is no perfect software.  At least I have never seen it.  Bugs and minor feature changes are indications people are using your software.  Real users hit a system in ways that no control group can, and on non-critical applications, this is the best way to test your software.  Let people use it and see what happens.  This is goes in line with the agile philosophy of release early and often.  Get your application out there as fast as you can, so you can mold the finishing touches around the real users experience rather than a faux-environment.&lt;/p&gt;

&lt;p&gt;There is some conversation about what is and what is not a &#8220;bug&#8221; in the software world.  That is not a conversation I would like to partake in here, so lets call both bugs, integration items,  minor feature enhancements, and things that fall through the cracks of development tweaks.  It doesn&amp;#8217;t matter what the nature of origin is, these are all things that MUST get done.&lt;/p&gt;

&lt;p&gt;After the release of one of our products, a load of tweaks came in from the customer.  As proud craftsman, we decided tweaks were our responsibility, and we would take them on in addition to our normal iteration.  So we started to do them, to the detriment of our iteration.  We accomplished only about half of our iteration&amp;#8217;s velocity.  &lt;/p&gt;

&lt;p&gt;The next iteration, much to our surprise, we were twice as busy with production support.  This is about the time that a developer looses a little faith.  What did we miss?  Is this high quality software we are writing?  So we lost even more velocity when it came to iteration 2 after the release. Also, the customers were now unable to accurately plan new features moving forward due to an unstable velocity.&lt;/p&gt;

&lt;p&gt;It is so hard to predict or estimate production support and tweaks.  However, we needed to be able to so that the production support didn&amp;#8217;t leave such a footprint in the project.  It felt and looked like we were not getting very much done, even though we were working harder than usual.  It was the time being put into a vacuum and being unaccounted for that was troubling the project.  It also had a negative effect on the morale of the team.&lt;/p&gt;

&lt;p&gt;We came up with a card, we call the &#8220;Production Support Card.&#8221;  The amount of the iteration&amp;#8217;s velocity this card took up was calculated by the amount of time we spent on production support the previous iteration averaged with the amount of time allocated for that iteration(sound like a familiar formula?).  It is added as a card to the next iteration.  If the developers only spend 6 of the 10 points on production support, it is expected that they will complete 4 points worth of stories, which are automatically entered in the iteration.  For the first iteration where it becomes apparent that we need a production support card, we set the point value of the card at 0 and track how much time we spend, bumping out of the iteration the least important stories if needed.&lt;/p&gt;

&lt;p&gt;So, what does this tracking buy you, if you have to spend the same amount of time on tweaks?  First, it allows transparency to the customer about what you are working on that week.  When they see your normal velocity of 20 points turn into 5 points, they have a right to be worried.  When you say, in a defeated voice &#8220;we were fixing bugs,&#8221; they also have a right to worry about the stability of the code you have been writing, even though this spike in minor changes to the application is a part of the normal process.&lt;/p&gt;

&lt;p&gt;Second, it raises the moral of the team, because they are working towards a specific goal, to remove the production support cards from the iteration.  Also, we get the satisfaction of maintaining a velocity in points, which is something we know so well it is hard to work without.&lt;/p&gt;

&lt;p&gt;It takes a few iterations, and the team squeezes the life out of the production support card, putting you back on track.  After those iterations, the footprint goes from sasquatch to mini-me.&lt;/p&gt;

&lt;p&gt;It also helps the customer plan around production support.  Their time lines and release dates are made from a projection of feature difficulty to development&amp;#8217;s velocity.  Over a long period of time, the velocity normalizes, and it hurts the projections to have hiccups.  If you have production support data, you can predict about how much time around a release you will loose on the initial release of brand new development.&lt;/p&gt;</description>
      <pubDate>Mon, 18 Feb 2008 14:39:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:b81e3e34-826b-4e54-bc8b-71f9acbc891a</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/02/18/agile-production-support-squashing-release-bugs</link>
      <category>Craftsmanship</category>
      <category>Coding</category>
      <category>Process</category>
    </item>
    <item>
      <title>Rinda 101</title>
      <description>&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When building a software system composed of multiple decoupled components, the need typically arises for interprocess coordination and communication.  As an example, say that we have a customer requirement that allows emails to be sent based on certain events or conditions that occur while the user is interacting with a web application.  We build an email component that takes care of the details of actually sending of the email.  The web application could use the email component directly, but that would introduce a dependency that we&amp;#8217;d rather avoid.  How can the two processes communicate without creating a dependency between the two?&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re using Ruby, there&amp;#8217;s an option that is built right into the standard library.  The &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/rinda/rdoc/index.html"&gt;Rinda module&lt;/a&gt; implements the Linda distributed computing paradigm in Ruby.  That&amp;#8217;s great, but what is Linda?  &lt;a href="http://en.wikipedia.org/wiki/Linda_%28coordination_language%29"&gt;Linda&lt;/a&gt; is a coordination language developed by a couple of Yale researchers in the early 1990s.  Linda itself is built on the concept of a tuplespace.  A tuple is an ordered list of objects, and a tuplespace contains a set of tuples which can be accessed concurrently.  A basic set of operations were defined by the language to allow reads, writes and takes.&lt;/p&gt;

&lt;p&gt;Getting back to the example, how can Rinda be utilized to enable communication between the web application and the email component?  First, a tuplespace will need to be setup that both components can access.  When a condition arises within the web application that requires an email to be sent on its behalf, a specific tuple will be written to the tuplespace.  The email component is looking for tuples that match a specific pattern.  When it finds the tuple written by the web application that matches this pattern, it processes the request and reports back to the tuplespace when finished.  In this way, we end up with only data coupling between the two processes, which is a much looser coupling than a direct dependency.  This type of approach bears some resemblance to a &lt;a href="http://en.wikipedia.org/wiki/Blackboard_Metaphor"&gt;blackboard system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we know a little bit about what Rinda can buy us, let&amp;#8217;s dive in and try it out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hello World&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s put together a simple server and client to demonstrate how each works.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a simple server (server.rb):&lt;/p&gt;

&lt;pre&gt;
require "rinda/tuplespace"

port = 4000
ts = Rinda::TupleSpace.new
DRb.start_service("druby://:#{port}", ts)
puts "Rinda listening on #{DRb.uri}..."
DRb.thread.join
&lt;/pre&gt;

&lt;p&gt;We start by setting the default port to 4000.  We then create a new TupleSpace object.  The call to start_service starts a local dRuby server listening on port 4000.  Passing the TupleSpace as the second parameter sets the server&amp;#8217;s front object to the TupleSpace.  The URI of the server is output, and the program waits for a kill signal, and we have a Rinda server ready to be accessed by a client.  To start the server:&lt;/p&gt;

&lt;pre&gt;
$ ruby server.rb
&lt;/pre&gt;

&lt;p&gt;Here&amp;#8217;s a simple interactive client (client.rb).  It allows input to be gathered on standard input, with the form &lt;write|take|read&gt; &lt;topic&gt; &lt;message&gt;.&lt;/p&gt;

&lt;pre&gt;
require "rinda/rinda"
include Rinda

port = 4000
ts = DRbObject.new(nil, "druby://:#{port}")

while message = gets
  begin
    args = message.split(" ")
    method = args.shift.to_sym
    topic = args.shift.to_sym
    message = args.shift
    message = nil if message == "nil"
    tuple = [topic, message]

    puts ts.send(method, tuple)
  rescue Exception =&gt; e
    puts e.message
  end
end
&lt;/pre&gt;

&lt;p&gt;We&amp;#8217;re using the send method in order to invoke the method specified on standard input.  There&amp;#8217;s also a conversion between nil as a string into nil proper.  This is necessary because of wildcards, which we&amp;#8217;ll get to in a minute.  With the server running, run the client to start a new interactive session:&lt;/p&gt;

&lt;pre&gt;
$ ruby client.rb
&lt;/pre&gt;

&lt;p&gt;Below is a sample session (output is indented for clarity):&lt;/p&gt;

&lt;pre&gt;
write message hello
    Rinda::TupleEntry:0x4f998
write message world
    Rinda::TupleEntry:0x4cfa4
read message nil
    message
    hello
take message nil
    message
    hello
take message nil
    message
    world
&lt;/pre&gt;

&lt;p&gt;The inputs above translate to these method calls:&lt;/p&gt;

&lt;pre&gt;
ts.write([:message, "hello"]) =&gt; Rinda::TupleEntry:0x4f998
ts.write([:message, "world"]) =&gt; Rinda::TupleEntry:0x4cfa4
ts.read([:message, nil]) =&gt; "hello"
ts.take([:message, nil]) =&gt; "hello"
ts.take([:message, nil]) =&gt; "world"
&lt;/pre&gt;

&lt;p&gt;Note that reads do not remove the tuple from the tuplespace.  The tuple is left untouched such that other clients can access the same data.  This is an important concept when dealing with synchronization that we&amp;#8217;ll return to in a future post.  &lt;/p&gt;

&lt;p&gt;The structure of the patterns used in the read and take methods deserve some additional attention.  When the tuplespace is queried through a read or a take, there are two criteria used to determine if a tuple matches.  First, the length of the tuple must match the pattern&amp;#8217;s length.  In the example above, all patterns are pairs (2-tuples), so only tuples that are pairs will qualify.  Second, the tuple must match the pattern specified.  When specifying a pattern, nil is used as a wildcard, which will match anything.  &lt;/p&gt;

&lt;p&gt;Assume that our tuplespace has the following tuples:&lt;/p&gt;

&lt;pre&gt;
1) [:message]
2) [:message, "hello"]
3) [:message, "hello", "world"]
&lt;/pre&gt;

&lt;p&gt;If the pattern [nil] is specified, e.g. ts.read([nil]), only #1 will match.  &lt;/p&gt;

&lt;p&gt;If the pattern [:message, nil] is specified, only #2 will match.  Of course, [:message, &amp;#8220;hello&amp;#8221;] would also result in #2 matching as well, while [:message, &amp;#8220;world&amp;#8221;] would not.  &lt;/p&gt;

&lt;p&gt;Using [:message, nil, nil], [:message, &amp;#8220;hello&amp;#8221;, nil], or [:message, nil, &amp;#8220;world&amp;#8221;] would all result in #3 matching.  So it is important to remember that patterns are matched on both length and content of the tuple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We haven&amp;#8217;t even scratched the surface of what can be done with Rinda.  This introduction only gets the simplest client and server talking to each other.  Stay tuned for more.&lt;/p&gt;</description>
      <pubDate>Tue, 12 Feb 2008 00:12:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:fcbdbd2a-6776-44f0-a00b-e29bc172b21e</guid>
      <author>Jim</author>
      <link>http://blog.8thlight.com/articles/2008/02/12/rinda-101</link>
      <category>Coding</category>
      <category>Rinda</category>
    </item>
    <item>
      <title>Emotional Iterations</title>
      <description>&lt;p&gt;After all the cards are written and estimated, it is time for the customers to pick the first iteration, for which they need a velocity and a length of time.  Usually after a creatively exhausting meeting, both are chosen arbitrarily , or with minimal stimulus.&lt;/p&gt;

&lt;p&gt;I have been on projects with one week iterations and one month iterations, all with varied success.  The formula for the length seems to have different inputs for success, involving customer participation, speed of changing requirements, and physical location.  All of these factors are prescriptive, attempting to plan the needs of the team based upon known constraints, something software craftsman are very familiar with.  The most successful iteration length for the teams I have been on is one week, regardless of other constraints.  Thanks to an excerpt from Donald Norman&amp;#8217;s new book, &lt;a href="http://www.amazon.com/Emotional-Design-Love-Everyday-Things/dp/0465051367/ref=pd_bbs_sr_3?ie=UTF8&amp;amp;s=books&amp;amp;qid=1202420238&amp;amp;sr=8-3"&gt;Emotional Design&lt;/a&gt;, I think I understand why environmental constraints do not affect iterations ideal length.&lt;/p&gt;

&lt;p&gt;&#8220;&amp;#8230;being happy broadens the thought process and facilitates creative thinking.  [Alice] Isen discovered that when people were asked to solve difficult problems, ones that required unusual &#8220;out of the box&#8221; thinking, they did much better when they had just been given a gift &#8211; not much of a gift, but just enough to make them feel good.&#8221;&lt;/p&gt;

&lt;p&gt;One week iterations are the perfect length for all of these emotions to be useful.  At the begging of an iteration is when you solve the tougher problems, not worried about a deadline.  Your creativity can know no boundaries, everything is possible.  A refactoring spanning a few days seems manageable, a large story looks like it can get done without sweating.  Really, as a developer, the day after the iteration meeting is often the happiest day you have, especially if you hit your velocity.  You are ready to spread your wings and impress the customers at the next iteration meeting. &lt;/p&gt;

&lt;p&gt;The book goes on to say, &#8220;&amp;#8230;when people are anxious they tend to narrow their thought process, concentrating upon aspects directly relevant to a problem.&#8221;&lt;/p&gt;

&lt;p&gt;As the iteration progresses, you start to feel the meeting.  You think &#8220;I can&amp;#8217;t get all of my ideas done by the meeting&#8221; and &#8220;I can&amp;#8217;t show up empty handed&#8221;.  This is when some of the more grandiose ideas get cut and you start to concentrate more on the acceptance of stories.  As it gets closer to iteration day, you become more granular, focusing all of your energy on acceptance of stories.  This blocks out the bigger designs and system solutions from your frame of reference.  &lt;/p&gt;

&lt;p&gt;Even within a solution, I have banged my head against a solution for hours, without thinking to sidestep it.  It is always harder to think of an alternative solution to a problem on the last day of an iteration than on the first.&lt;/p&gt;

&lt;p&gt;This is good for iterations, you cycle through all of these emotions, not staying on any of them too long.  Too many days at the beginning of an iteration leaves developers wide eyed about refactorings or experiments.  Sprinting at the end of an iteration for too long leaves a team stressed and under productive.  However, all those emotions in small doses, on a continuum is good for the project and good for the developer.  You get to flex your developer muscles and try out something cool, but by the end of the iteration, you are focussed on finishing the features the customer needs.&lt;/p&gt;</description>
      <pubDate>Thu, 07 Feb 2008 21:36:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:fe914a9b-b7a6-42f7-a51d-442a633a3600</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/02/07/emotional-iterations</link>
      <category>Process</category>
    </item>
    <item>
      <title>LimeLight at RailsConf 2008</title>
      <description>&lt;p&gt;Back at RubyConf 2007 I prepared a &lt;a href="http://rejectconf4.confreaks.com/d2t3_4th_annual_reject_conf_8th_light.html" target="new"&gt;1 minute presentation&lt;/a&gt;, well&amp;#8230; more of a teaser, about an application framework called LimeLight.&lt;/p&gt;

&lt;p&gt;What is it?  LimeLight is a selfish dream of mine.  In a nutshell it&amp;#8217;s a light weight ruby framework for building rich client applications.  To explain further, know this. I hate building web applications.  Not because they&amp;#8217;re hard to build or anything silly like that.  It&amp;#8217;s because they&amp;#8217;re so perverted.  Writing web apps makes me feel dirty; as though I&amp;#8217;ve sunk into a pit of waste and decay where the foundation of my work is a pool of sludge.  No matter how hard I may try, the very nature of modern web apps taints my code and leaves me a sour, grumpy developer.&lt;/p&gt;

&lt;div style="border: 1px solid blue; width: 100px; height: 100px; text-align: center; background-color: white; float: right;"&gt;
    &lt;div id="light" style="border: 1px solid black; width: 50px; height: 35px; margin: 10px 24px 10px 24px; 
                            background-color: red; text-align: center; padding-top: 15px;"&gt;
        Stop
    &lt;/div&gt;
    &lt;input id="button" type="submit" value="Start" onclick="stopOrGo();"/&gt;
    &lt;script type="text/javascript"&gt;
        function stopOrGo() {
            var button = document.getElementById('button');
            var light = document.getElementById('light');
            if(button.value == 'Start') {
                start(button, light);
            }
            else {
                stop(button, light);
            }
        }

        function stop(button, light) {
            light.style.backgroundColor = "red";
            light.innerHTML = "Stop";
            button.value = "Start";
        }

        function start(button, light) {
            light.innerHTML = "Go!";
            button.value = "Stop";
            blink();
        }

        function blink() {
            var light = document.getElementById('light');
            if(light.innerHTML == "Go!")
            {
                if(light.style.backgroundColor == "green") {
                    light.style.backgroundColor = "lightgrey";  
                }
                else {
                    light.style.backgroundColor = "green";
                }
                setTimeout("blink()", 500);
            }
        }
    &lt;/script&gt;
&lt;/div&gt;

&lt;p&gt;To understand what I mean, consider the trivial little widget on the right here.  Try clicking the button and watch the light blink. Simple huh? Can you count the number of languages/technologies used in implementing this widget? And don&amp;#8217;t forget the code required on the server side&amp;#8230;.. &lt;/p&gt;

&lt;p&gt;I count 5.  That is, in most cases this widget would require about 5 or more different languages.  Let&amp;#8217;s count.  HTML of course.  CSS to make it look right.  JavaScript.  That&amp;#8217;s 3, but in most cases you&amp;#8217;ve got server-side code which, if you&amp;#8217;re lucky, involves Ruby and ERB.  Think about it.  You need to know 5 difference languages to build that silly widget. Yikes!&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll include the code below.  Know that I&amp;#8217;ve made every effort to make this code as clean and simple as possible.  Still, I would need to borrow your hands and feet to count all the things I find distasteful about it.  Have a close look.  Ask yourself, &amp;#8220;Couldn&amp;#8217;t there be an easier way to do this?&amp;#8221;  I say there is.    &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.railsconf.com" style="float: left; margin: 5px;"&gt;
&lt;img src="http://en.oreilly.com/rails2008/public/asset/asset/1174" width="210" height="60"  border="0"  alt="RailsConf 2008" title="RailsConf 2008"  /&gt;
&lt;/a&gt;
If you&amp;#8217;d like to learn more, I&amp;#8217;ll be &lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/1984" target="new"&gt;presenting on the topic&lt;/a&gt; at RailsConf 2008.  Or you can come back this this blog site later.  I&amp;#8217;ll be sure to post any exciting progress.&lt;/p&gt;

&lt;div&gt;
&lt;pre&gt;
&amp;lt;div style="border: 1px solid blue; width: 100px; height: 100px; 
               text-align: center; background-color: white; 
               float: right;"&amp;gt;
    &amp;lt;div id="light" 
            style="border: 1px solid black; width: 50px; 
            height: 35px; margin: 10px 24px 10px 24px; 
            background-color: red; text-align: center; 
            padding-top: 15px;"&amp;gt;
        Stop
    &amp;lt;/div&amp;gt;
    &amp;lt;input id="button" type="submit" 
              value="Start" onclick="stopOrGo();"/&amp;gt;
    &amp;lt;script type="text/javascript"&amp;gt;
        function stopOrGo() {
            var button = document.getElementById('button');
            var light = document.getElementById('light');
            if(button.value == 'Start') {
                start(button, light);
            }
            else {
                stop(button, light);
            }
        }

        function stop(button, light) {
            light.style.backgroundColor = "red";
            light.innerHTML = "Stop";
            button.value = "Start";
        }

        function start(button, light) {
            light.innerHTML = "Go!";
            button.value = "Stop";
            blink();
        }

        function blink() {
            var light = document.getElementById('light');
            if(light.innerHTML == "Go!")
            {
                if(light.style.backgroundColor == "green") {
                    light.style.backgroundColor = "lightgrey";  
                }
                else {
                    light.style.backgroundColor = "green";
                }
                setTimeout("blink()", 500);
            }
        }
    &amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;

&lt;/pre&gt;
&lt;/div&gt;</description>
      <pubDate>Tue, 05 Feb 2008 04:32:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:ff4a010a-3b9e-4b2e-95b3-e8fce2d24838</guid>
      <author>Micah</author>
      <link>http://blog.8thlight.com/articles/2008/02/05/limelight-at-railsconf-2008</link>
      <category>Coding</category>
      <category>Fun</category>
      <category>Micah</category>
    </item>
    <item>
      <title>Peer Pressure</title>
      <description>&lt;p&gt;One of the famous studies on peer pressure was the &lt;a href="http://en.wikipedia.org/wiki/Stanford_prison_experiment"&gt; Stanford prison experiment&lt;/a&gt;.  A group of average people were selected to play either a prisoner or prisoner guard.  As the participant became engrossed in the role, the peer pressure from other participants quickly degraded their moral compass.  The small negative actions lead the groups to quickly fall into patterns of behavior which were unlike their own.&lt;/p&gt;

&lt;p&gt;I see peer pressure work in the same manner for good all the time.  Since software is written by teams, the software is often a reflection of how well the team works together more so than individual skills of the developers.  When you have a group of developers who entice each other to do good work, the outcome can be great work.&lt;/p&gt;

&lt;p&gt;Creating a culture of positive peer pressure is about doing lots of little things.  Small positive actions will lead the team to create positive patterns of behavior.  &lt;/p&gt;

&lt;p&gt;Here are different techniques which have worked for different teams I have been a member.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Name your team, not just your project.  This gives me as a developer some self-identity as part of a team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Greet your team mates each day.  We shake hands to show respect each day for each team member.  We generally start and finish each day with a &lt;a href="http://blog.8thlight.com/articles/2007/07/19/shake-things-up"&gt;handshake&lt;/a&gt;.  This can alleviate tense situations by itself, as personal contact often does.  No chance to avoid a team member.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do some activity everyone enjoys.  Anything from eating lunch together to playing a competitive game as a team.  We have played basketball together.  Being competitive with my team gives me pride in the team, win or loose.  Get to know your team members.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We keep a good supply of coffee, tea, snacks, and gum for each other as gifts.  This act of giving to the team promotes the selflessness any team needs from its members top succeed.  There are different levels of skill on a team, but each team member is important.  It is difficult to write software for any project of magnitude without the full contribution of each member of the team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Switch pairs pairs often.  When you work with everyone on the team, you feel closer to everyone on the team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Talk while you pair.  Reading someone&amp;#8217;s mind takes more effort than talking.  Talking aloud also is a great way of brainstorming.  Pair communication starts when words become sound waves.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These small things can improve the accountability and creativity to make a well functioning team.  A happier team will become a creative and productive team.  A team that has a strong sense of togetherness will lift each other up when needed.  I find myself more willing to step up to daily challenges with the support of the team on my side.  There is no place for apathy and complacency in a team which has pressure to succeed.&lt;/p&gt;

&lt;p&gt;When the team succeeds, as positive teams often do, it becomes a group success and brings the entire team great pride.  A team which pressures each other to do better can turn an average developer into a great developer.&lt;/p&gt;</description>
      <pubDate>Fri, 18 Jan 2008 16:18:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:d8395950-2ba2-4b33-a03d-d986e322956a</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/01/18/peer-pressure</link>
      <category>Craftsmanship</category>
      <category>Etiquette</category>
    </item>
    <item>
      <title>Lessons of a Craftsman: Are you Test Driving, or just writing tests?</title>
      <description>&lt;p&gt;Recently I wrote the beginnings of a blackjack game in Java, and I found myself making what I believe is a common error.  The Java gameplay mechanic uses a state machine to manipulate the deck.  As I was implementing the state machine I found I needed a Card object, in addition to my Card3DObject which actually drew the card, a look-up table for the 3D cards, an interface for the Deck and an object representing the Deck (so I could mock it out), and when I came across the situation for an Ace I decided a needed an object responsible for computing a Total in order to handle the situation of an Ace being a 1 or 11.&lt;/p&gt;

&lt;p&gt;Apparently an if statement would cause an irreversible hand cramp, ending my programming career.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;ve ever done the bowling game, and really why haven&amp;#8217;t you, there&amp;#8217;s more than a few ways to skin that particular cat.  Ron Jefferies has done it about [four thousand different ways] (http://www.xprogramming.com/xpmag/index.htm), whereas Bob Martin typically teaches a simple one.  While none of them are wrong, I&amp;#8217;m partial to the Martin version because it&amp;#8217;s a simple problem, and it deserves a simple solution.  I can give that version to a college student, and he can understand it.  Furthermore in that version the tests &lt;em&gt;drive&lt;/em&gt; the design.  Let&amp;#8217;s go back and look at my blackjack game to see what I mean.&lt;/p&gt;

&lt;p&gt;When writing the game I decided blackjack would be a FSM.  I drew a couple of diagrams, then used the Java state machine generator to make my state machine.  The problem, as I see it, is that I did this without writing a line of code.  Furthermore as I was coding I was thinking two steps ahead, and making design decisions before I needed to.  I did a mini-version of the BDUF, and it&amp;#8217;s something I see people do all the time.  I was writing test first but I wasn&amp;#8217;t always letting tests drive that design.  Frankly that&amp;#8217;s not necessarily a bad thing, and virtually all large systems need some design as a sort of guide, but what I should have done is wait until the code forced me into the state machine, forced me into other objects, etc.  It&amp;#8217;s not the end of the world, and in the end I may even have made the same decisions I would have anyway, but given that I didn&amp;#8217;t let my tests drive my design I probably won&amp;#8217;t end up with the simplest thing that could possibly work.  That&amp;#8217;s a shame.&lt;/p&gt;</description>
      <pubDate>Mon, 07 Jan 2008 21:58:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:189f4cb4-6eca-4b18-822f-ce3016f36272</guid>
      <author>Eric</author>
      <link>http://blog.8thlight.com/articles/2008/01/07/lessons-of-a-craftsman-are-you-test-driving-or-just-writing-tests</link>
      <category>Coding</category>
      <category>Eric</category>
    </item>
  </channel>
</rss>
