<?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: Category Coding</title>
    <link>http://blog.8thlight.com/articles/category/coding</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In the minds of the craftsmen...</description>
    <item>
      <title>Some Random RubyCocoa stuff</title>
      <description>&lt;p&gt;I went to WWDC last week (1), and while I was there I got a chance to talk to a couple of their engineers and picked up a few things about RubyCocoa.  Neither of them are really enough for a blog post on their own, hence the title of this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running tests in XCode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you&amp;#8217;re writing RubyCocoa you may find you have three windows open.  XCode to create your files, Interface Builder to design your interface, and Textmate to edit code and run tests.  If not Textmate, then probably a command window.  To put it politely - this sucks (2).  While I&amp;#8217;m no big fan of XCode&amp;#8217;s text editor I pretty much have to have it open (3) while I&amp;#8217;m developing RubyCocoa, so how do I run specs from within XCode?  It&amp;#8217;s simple.  Open up or create a new RubyCocoa project.  On the left you should see Targets, click the tree to open it:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080617-qqkycnfesfhxhhmjduy8aj5ax1.jpg" alt="ForDemo"/&gt;&lt;/p&gt;

&lt;p&gt;You can see the process for building your application here.  We&amp;#8217;re going to add running specs as a last step, so that our build will fail when our specs do.  Right click on the target, and add a new Run Script phase:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080617-ex1ydknsd6uyp4156d4r8jqtj8.jpg" alt="ForDemo"/&gt;&lt;/p&gt;

&lt;p&gt;Then just add this to the script.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080617-n7satjkd1ej3hd41c8b87h4scg.jpg" alt="Run Script Phase for &#8220;ForDemo&#8221; Info"/&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s just that simple!  I put all my specs in a spec directory, don&amp;#8217;t add them to the target of course, and they get run on each build.   Here&amp;#8217;s an example from a project I&amp;#8217;m working on with a failing test:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080617-bderfj86n4ixyqcsdpbpddyihu.jpg" alt="RspecRunner - Build Results"/&gt;&lt;/p&gt;

&lt;p&gt;This shows up in the Build Results window in XCode which you&amp;#8217;ll see when you click the worlds tiniest red x in the corner of the screen.  &lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080623-xnnxh8qnwkuqnqykp2keiqimea.jpg" alt="choose_specs_controller.rb - RspecRunner"/&gt;&lt;/p&gt;

&lt;p&gt;Congrats, now you can code in XCode and not Textmate.  Okay it&amp;#8217;s text editor is poor, but Interface Builder and XCode are built to work together.  For example when you have XCode and Interface Builder open you don&amp;#8217;t have to constantly drag-and-drop from finder to IB, it just detects your code changes.  This is extremely handy when adding actions or outlets.  In fact the two apps are so intertwined Interface Builder just plain doesn&amp;#8217;t work that well stand-alone.  That&amp;#8217;s yet another reason to keep using XCode, no matter how much I dislike it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opening a File or Directory in RubyCocoa&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first two tutorials use simple &amp;#8220;selectors,&amp;#8221; Objective-C&amp;#8217;s fancy name for a method.  Actually that&amp;#8217;s Smalltalk&amp;#8217;s name for a method, and Objective-C steals it.  To use Smalltalk terms there are unary messages, which are the kind that only take one or 0 parameters, and keyword messages.  Keyword messages have named parameters, and ruby doesn&amp;#8217;t have named parameters, so how do we send multiple arguments to a method in RubyCocoa?  This simple example of opening a directory will demonstrate.&lt;/p&gt;

&lt;p&gt;Start by creating a new RubyCocoa project.  For directions on the basics go &lt;a href="http://blog.8thlight.com/articles/2008/04/20/bowled-over-by-rubycocoa"&gt;here&lt;/a&gt;.  We&amp;#8217;ll be doing BDD again so I expect you&amp;#8217;ll be able to run tests.  Call your new project OpenDirectory or something similar, then use the directions above to add a run specs phase to your build process.  Now open the MainMenu.nib, and create a window that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080623-dp9e832tyk9gb6iq4x1rg2k8x3.jpg" alt="Directory Opener"/&gt;&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s a lovely dialog.  Let&amp;#8217;s get started running code.  Click on the build and go button.  What&amp;#8217;s this?&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080623-qxqxma7p9wearnbyj3bamcwn59.jpg" alt="OpenDirectory - Build Results"/&gt;&lt;/p&gt;

&lt;p&gt;Our build doesn&amp;#8217;t work!  We don&amp;#8217;t have a directory called spec, or any specs in it.  Create a spec directory under Create a spec in the spec directory called choose_directory_spec.rb.  Remember not to add it to the target, and make sure it is in the specs directory.  Here&amp;#8217;s our first spec:&lt;/p&gt;

&lt;pre&gt;
require 'choose_directory'

describe ChooseDirectory do
    it "should be an NSObject" do
        directoryController = ChooseDirectory.new
        directoryController.is_a?(OSX::NSObject)
    end
end
&lt;/pre&gt;

&lt;p&gt;I know pretty simple.  I&amp;#8217;m not going to go baby steps through this because at the moment I lack the patience.  If you see an error that your build failed because you don&amp;#8217;t have a file choose_directory then you&amp;#8217;re on the right track.  Create the ChooseDirectory class, this time in the root directory and add it to the target.  I choose to group my specs in an XCode group called Specs and my classes in the Classes group that&amp;#8217;s already provided for you, but those are just groups and you can feel free to do this any way you please.  Now let&amp;#8217;s look at the next few tests.&lt;/p&gt;

&lt;pre&gt;
def OSX._ignore_ns_override; true; end

before(:each) do
    @mock_panel = mock(OSX::NSOpenPanel, :canChooseDirectories= =&gt; nil, :canChooseFiles= =&gt; nil)
    OSX::NSOpenPanel.stub!(:openPanel).and_return(@mock_panel)
    @directoryController = ChooseDirectory.new
end

it "should have an action open directory" do
    @directoryController.open_directory
end

it "should open a panel" do
    OSX::NSOpenPanel.should_receive(:openPanel).and_return(@mock_panel)

    @directoryController.open_directory
end

it "should configure it to select directories" do
    @mock_panel.should_receive(:canChooseDirectories=).with(true)

    @directoryController.open_directory
end

it "should configure it so it can't select files" do
    @mock_panel.should_receive(:canChooseFiles=).with(false)

    @directoryController.open_directory
end
&lt;/pre&gt;

&lt;p&gt;One thing probably jumps out at you, that big strange command &lt;code&gt;def OSX._ignore_ns_override; true; end&lt;/code&gt;  If you don&amp;#8217;t include this you&amp;#8217;ll get warnings that you can&amp;#8217;t override the methods in OSX::NSOpenPanel because the arguments don&amp;#8217;t match.  We didn&amp;#8217;t override them of course, we stubbed and mocked them with RSpec, but from Cocoa&amp;#8217;s perspective that&amp;#8217;s the same thing.  We remove the error by monkey-patching &lt;code&gt;_ignore_ns_override&lt;/code&gt; to return true.  Rucola (4) apparently has this problem licked, otherwise you&amp;#8217;ve got to put this before your mocks get loaded.  Looking down the specs you can see I&amp;#8217;m calling NSOpenPanel class methods, and configuring it.  The method &lt;code&gt;openPanel&lt;/code&gt; creates an NSOpenPanel object and returns it, the other two methods should be self explanatory.  Isn&amp;#8217;t it interesting how you can figure out the intent of the code from these tests?  It&amp;#8217;s almost like a specification.  Here&amp;#8217;s the code that makes this pass:&lt;/p&gt;

&lt;pre&gt;
    ib_action :open_directory
    def open_directory
        panel = OSX::NSOpenPanel.openPanel
        panel.canChooseDirectories = true
        panel.canChooseFiles = false
    end
&lt;/pre&gt;

&lt;p&gt;One action, open_directory, that sets up the panel.  We haven&amp;#8217;t displayed the panel yet.  Remember what I said about selectors with named parameters?  Well here&amp;#8217;s where it comes into play.  We need to call the &lt;code&gt;beginSheetForDirectory&lt;/code&gt; method on that panel.  This will display a standard dialog box for opening directories.  Here&amp;#8217;s the full method signature, from the Objective-C documentation:&lt;/p&gt;

&lt;pre&gt;
    - (void)beginSheetForDirectory:(NSString *)absoluteDirectoryPath file:(NSString *)filename types:(NSArray *)fileTypes modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo
&lt;/pre&gt;

&lt;p&gt;This is a keyword message.  The syntax works like this:&lt;/p&gt;

&lt;p&gt;[method name]: [first parameter] [first keyword]: [second parameter]&amp;#8230;..forever&lt;/p&gt;

&lt;p&gt;So for beginSheetForDirectory that&amp;#8217;s one, two, three&amp;#8230;oh man that&amp;#8217;s a lot of parameters.  Here&amp;#8217;s what my first attempt at doing this in RubyCocoa looked like (in another application):&lt;/p&gt;

&lt;pre&gt;
    beginSheetForDirectory_file_types_modalForWindow_modalDelegate_didEndSelector_contextInfo(nil, nil, nil, nil, self, "open_panel_did_end", nil)
&lt;/pre&gt;

&lt;p&gt;Now that is a method name!  Fortunately I found a &lt;em&gt;slightly&lt;/em&gt; (5) better way to do it.  It looks an awful lot like sending a hash of parameters, something that should be familiar to Rails users.  Here comes our next test:&lt;/p&gt;

&lt;pre&gt;
    it "should call beginSheetForDirectory" do
        @mock_panel.should_receive(:beginSheetForDirectory).with(nil, 
                                                                 :file, nil, 
                                                                 :types, nil,
                                                                 :modalForWindow, nil,
                                                                 :modalDelegate, @controller,
                                                                 :didEndSelector, "open_panel_did_end",
                                                                 :contextInfo, nil)
        @directoryController.open_directory
    end
&lt;/pre&gt;

&lt;p&gt;This is closer to the named parameters convention of Objective-C.  The panel will call beginSheetForDirectory with nil as the name of the initial directory.  The first parameter isn&amp;#8217;t named, it&amp;#8217;s specified by saying &amp;#8220;ForDirectory&amp;#8221;.  By passing nil we say &amp;#8220;open this directory to the same directory I did last time.&amp;#8221;  Works fine for most situations.  Only two of the parameters are really interesting.  The first is the modalDelegate, which I&amp;#8217;ve specified will be the controller.  A message will be sent to the modalDelegate when the panel operation ends.  I just want it to send it back to the controller.  The second is the didEndSelector which I&amp;#8217;ve specified to be the method open_panel_did_end.  We&amp;#8217;ll come to that method in a minute.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s make that spec pass:&lt;/p&gt;

&lt;pre&gt;
    def open_directory
        panel = OSX::NSOpenPanel.openPanel
        panel.canChooseDirectories = true
        panel.canChooseFiles = false

        panel.beginSheetForDirectory(nil, 
                                     :file, nil, 
                                     :types, nil,
                                     :modalForWindow, nil,
                                     :modalDelegate, @directoryController,
                                     :didEndSelector, "open_panel_did_end",
                                     :contextInfo, nil)
    end
&lt;/pre&gt;

&lt;p&gt;Pretty simple.  That command will display an Open Directory screen.  What do we want to do with it when we&amp;#8217;re done?  That&amp;#8217;s where open_panel_did_end comes in.  It will be called by Cocoa when the panel is closed.  I want to take the directory that was selected by the user, and display it in the text box in our interface.  &lt;/p&gt;

&lt;pre&gt;
    it "should set the directory name outlet on open_panel_did_end to the directory selected" do
        @directory = mock(OSX::NSTextField)
        @directoryController.directory = @directory
        @mock_panel.stub!(:directory).and_return("Directory")

        @directory.should_receive(:stringValue=).with("Directory")
        @directoryController.open_panel_did_end(@mock_panel, 0, nil)
    end
&lt;/pre&gt;

&lt;p&gt;This is a kind of big test.  What I&amp;#8217;m doing is setting up the controller with the directory outlet, and making sure it gets set with the directory that panel will have set to it when this method is called.  You notice that 
open_panel_did_end takes three parameters.  This is a rule of Cocoa, but I don&amp;#8217;t care about the second and third parameters, so we just pass 0 and nil.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s make this guy pass:&lt;/p&gt;

&lt;pre&gt;
    def open_panel_did_end(panel, return_code, context=nil)
        @directory.stringValue = panel.directory
    end 
&lt;/pre&gt;

&lt;p&gt;You can see why I was reluctant to write more than one test.  The method is done.  Finally let&amp;#8217;s build and run our app.  It &amp;#8230; doesn&amp;#8217;t work.  Aw heck we haven&amp;#8217;t connected our outlets.  We haven&amp;#8217;t even created an object.  This is where InterfaceBuilder starts to shine.  In the library get an Object and drag it over to the Application window.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080702-j12p7dyx9b2bbfn9sdtg6xiuch.jpg" alt="Library"/&gt;&lt;/p&gt;

&lt;p&gt;Open its Inspector and go to the information tab.  That&amp;#8217;s the one with with places for the Class, Actions and Outlets.  It has a drop-down menu next to class - use it to select ChooseDirectory.  Notice how we didn&amp;#8217;t have to drag-and-drop the file into the app?  Look at the Actions and Outlets, they just filled right in!&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080702-eamwfth5bxkrq4rmgaiqg9cuap.jpg" alt="Choose Directory Identity"/&gt;&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s fantastic.  Now we can just draw our connections and build the app.  Just do it already and run it.  If you&amp;#8217;ve done all the steps, and I haven&amp;#8217;t messed this up, you should have an application that selects a directory and displays it in a text box.  It&amp;#8217;s not very exciting, but you now know two different ways to translate Objective-C&amp;#8217;s methods into Ruby methods.  Soon you will take over the world!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sometimes it takes a while for me to write a blog post.&lt;/li&gt;
&lt;li&gt;Doug would not find this polite.  Jim would claim I&amp;#8217;m being too nice.&lt;/li&gt;
&lt;li&gt;Real footnote this time - there is a gem called Rucola that can apparently free you from XCode.  I haven&amp;#8217;t had much luck getting it&amp;#8217;s dependencies installed and can&amp;#8217;t vouch for it.&lt;/li&gt;
&lt;li&gt;There&amp;#8217;s that name again.  I promise Eloy I&amp;#8217;ll get it working one of these days.&lt;/li&gt;
&lt;li&gt;After beginning this blog post I discovered this method is deprecated.  That said I strongly prefer it to the long method name, so I decided to leave it, and will do a little research as to the &amp;#8220;why&amp;#8221; it&amp;#8217;s been deprecated.  In the meantime you can use either, or objc_send.  That third way is another blog post.&lt;/li&gt;
&lt;/ol&gt;</description>
      <pubDate>Thu, 24 Jul 2008 04:17:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:8562a2a2-b7cc-4735-ae62-5a182db8fe74</guid>
      <author>Eric</author>
      <link>http://blog.8thlight.com/articles/2008/07/24/some-random-rubycocoa-stuff</link>
      <category>Coding</category>
      <category>Eric</category>
      <category>RubyCocoa</category>
      <category>TDD</category>
    </item>
    <item>
      <title>Apprenticeship month one report</title>
      <description>&lt;p&gt;8th Light has an apprenticeship program whereby an 8th Light craftsman will mentor an individual for three months.  During that time, the craftsperson becomes responsible for a single apprentice.  I am one month into a mentorship with an apprentice.  This blog is about observations I have made about myself as a mentor.&lt;/p&gt;

&lt;h3&gt;Curiosity&lt;/h3&gt;

&lt;p&gt;He asks me questions that I wouldn&amp;#8217;t ask myself.  I had him do an exercise about &lt;a href="http://en.wikipedia.org/wiki/Law_Of_Demeter"&gt;Law of Demeter&lt;/a&gt; , to find Law of Demeter violations in my code base.  He found something like:&lt;/p&gt;

&lt;p&gt;Law of Demeter&lt;/p&gt;

&lt;p&gt;&amp;#8220;Ted Williams&amp;#8221;.to_s.strip.upcase&lt;/p&gt;

&lt;p&gt;He was counting the periods, which is what I explained is often good measurement of Law of Demeter violations.  Yet this is not a Law of Demeter violation.  Each one of those methods returns itself (a string) in a changed state.  It is not a string of implementation details- this example is just changing a single object.  The pivotal piece of information is that all of these methods on string return the string itself.  Also, is anything inside of Ruby core language capable of Law of Demeter?  It is unlikely to change, and is there a problem being coupled tightly to your language?&lt;/p&gt;

&lt;p&gt;I sometimes get desensitized to the original premises of good development.  When I first learn something, I remember the example of the rule more than the value of the rule.  The value of learning about Demeter is rooted in encapsulating logic in such a way to hide implementations from an object&amp;#8217;s clients.  When I first learned about Demeter, all I could do was point out violations.  The more I developed, the more it was internalized as a guide for a higher development idea.  I want to keep my modules as decoupled as possible.  However, that notion only came with development experience.  Now I don&amp;#8217;t think in terms of violations or non-violations of Demeter when I read a piece of code.  It is just ingrained in my developmental context that I should develop my modules in such a way that they are autonomous.  This weeds out most Law of Demeter violations by itself.  Bringing these premises back up in my development as a craftsman gets my curiosity started.  Like a good song or piece of writing, every time I come back to it, I take something different from it, because I am in a state of constant change.&lt;/p&gt;

&lt;h3&gt;Teaching&lt;/h3&gt;

&lt;p&gt;Sometimes I forget how important teaching is to the craftsmanship model, because I am still an extreme novice at it.  It is one of the steps involved with internalizing development skills.  When I pair with my mentor, I am constantly amazed at how he skips steps in the development rational process.  Instead of following a linear thought pattern to a solution, it seems there is a giant shortcut in the rational processes I go through.  That gap is a lookup table of solutions in his head.  It appears so easy and effortless.  Teaching is part of a formula that has given him a development context that is superior to mine.  The more I am able to teach, the more I internalize the ideas about development.  &lt;/p&gt;

&lt;p&gt;There is a &lt;a href="http://sports.espn.go.com/espnmag/story?id=3336514&amp;amp;campaign=rss&amp;amp;source=MLBHeadlines"&gt;baseball story&lt;/a&gt; from about a year ago.  Greg Maddux was warming up before a game and his catcher exclaimed to the pitching coach, &amp;#8220;I bet I could catch him with my eyes closed.&amp;#8221;  Well, after much effort, they convinced Maddux to give it a shot.  The catcher was going to call his pitch, then close his eyes.  When the ball was about to hit his mitt, the pitching coach with his eyes open was going to yell &amp;#8220;now&amp;#8221;, whereupon the catcher would squeeze his glove on the ball.  Well, on the third try, the catcher caught the ball.  The degree of difficulty of the exercise is incredible, but Greg Maddux had spent so many years internalizing the mechanics of his craft that he could effortlessly hit the catcher&amp;#8217;s mitt.  There probably are only a few pitchers in the long history of baseball who could match that exercise.  I am not anywhere near that kind of skill in development, but that is my goal.  When you get the mechanics of your craft to be intuition, it frees your mind to think about and solve larger problems.  I have been fortunate to spend time with enough great developers to see this mastery in action.&lt;/p&gt;

&lt;h3&gt;Communication&lt;/h3&gt;

&lt;p&gt;For me, what is special about teaching is the commitment of thoughts to sound.  Forcing something outside of my internal monologue always changes it, even if it is a small change.  When I explain something, I often have to explain it multiple ways (this is telling of my communication skills, not of my apprentice&amp;#8217;s learning skills).  So, the more I am forced to answer questions on the spot, the better I get at quickly thinking through a question and giving a good answer.  This dialogue is another one of the mental exercises which translates into my everyday development.  It makes me a better pair programmer, better presenter, and better writer.  Being able to accurately explain a problem and a solution using the language of software development is a very important tool in being a successful craftsman, and a tool that I fight uphill to improve upon.  When I go to a talk at a conference and the presenter hits the problem and solution perfectly, it is a wonderful experience.  The same is true when a team member can explain a solution in such intuitive terms that everyone gets it immediately.&lt;/p&gt;

&lt;p&gt;Apprenticeship for me is as much about internalizing and expanding my own skill set as it is about expanding my apprentice&amp;#8217;s.  &lt;/p&gt;</description>
      <pubDate>Tue, 01 Jul 2008 01:14:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:29809293-4427-4262-bc2c-eeda47e56d81</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/07/01/apprenticeship-month-one-report</link>
      <category>Craftsmanship</category>
      <category>Coding</category>
      <category>Paul</category>
      <category>Apprenticeship</category>
    </item>
    <item>
      <title>Developing against web browser navigation</title>
      <description>&lt;p&gt;I find while writing web applications that I end up redefining what it means to go &amp;#8220;back.&amp;#8221;  This means where I want the user to go when they hit the back button.  The creation of AJAX has killed the behavior of the navigation buttons in the browser.  The navigation buttons on a browser are from the time of sundials and static web pages.  We live in the world of atomic watches and dynamic content.  I don&amp;#8217;t want you to go back to the last static web page that was loaded.  More times than not, that messes up the user&amp;#8217;s experience.&lt;/p&gt;

&lt;p&gt;I have seen/implemented some solutions.  One that we have used is when the first page is served up you start some kind of memory.  Start a stack of the user&amp;#8217;s actions, saving them in the session.  When the user tries to go back to the main page, they are redirected to the real last page they were at.  This is good for AJAX intensive applications.  These days I am finding the percentage of AJAX requests is many times higher than AJAX requests when I am trying to create a rich user experience.  The problem is you get into situations where the user really does want to go back to the last domain they are at, but your application, very annoyingly, will not let them leave.  As a user of the internet, I quickly learned that if I hit the back button many times quick enough, the page doesn&amp;#8217;t have time to render the redirect, and I can get back.  The fact I even know that is annoying, let alone what it takes away from my application.&lt;/p&gt;

&lt;p&gt;Another solution is to have lots of static pages.  Don&amp;#8217;t let the user get too far without loading a new page.  This way the back button can really only do minimal damage.  Use lots of client side JavaScript and limit the amount of AJAX calls to the bare minimum.  This has become industry standard for web pages which involve payment processing.  Since the developers can&amp;#8217;t guarantee that a user won&amp;#8217;t hit the back  refresh / or forward buttons, you have to be able to have some kind of state recovery.  If the distance between static pages is short, then you don&amp;#8217;t do too much damage.   However, this constraint limits what you can do with your web application, limiting AJAX calls.&lt;/p&gt;

&lt;p&gt;My favorite solution is to take the browsers out back and teach them about feature envy.  They are telling me to serve HTML/JavaScript/Flash content inside their main pane architecture, and they will take care of the rest.  Well then, keep your hands to yourself!!!  Navigating between web applications(domains) makes sense at some high level, because that is in the job of a web browser.  They get you from one web application to another.  However, inside of my web application, let me decide what I want the back button to do.  I understand some kind of backwards compatibility so the Geocities web page with the contra code on it doesn&amp;#8217;t get lost (like we don&amp;#8217;t all have it memorized).  So, let me turn it off for my domain.  Give me a JavaScript API to say what the back button behavior should be or let me at least turn it off.  There are &lt;a href="http://www.robertpenner.com/experiments/backbutton/backbutton.html"&gt;some attempts&lt;/a&gt; to do just this, but they are not straightforward or part of the core library.&lt;/p&gt;

&lt;p&gt;So, this will require all developers of web applications to implement navigation that makes sense within their web applications.  Great!!!  If they are worried at all about user experience, they have already thought about this and have some solution in place.  Getting rid of the back button just gives them more power.  I have never met a developer who wouldn&amp;#8217;t embrace more freedom in their tools.&lt;/p&gt;</description>
      <pubDate>Fri, 27 Jun 2008 15:07:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:e133fb36-4860-4c9e-aba5-fafa73e2dab4</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/06/27/developing-against-web-browser-navigation</link>
      <category>Coding</category>
      <category>Paul</category>
      <category>Browser</category>
    </item>
    <item>
      <title>Active Record migration dependencies</title>
      <description>&lt;p&gt;We had a new developer join our project recently, and he needed his computer to be setup with the project.  &amp;#8220;Here is the svn repository, when you check it out, run these rake tasks.&amp;#8221;  It unfortunately, is never that easy.  This project setup revealed something about Active Record and migrations that I didn&amp;#8217;t know about.&lt;/p&gt;

&lt;p&gt;When I create a migration, I will often do data manipulation on the database, or pre-populate some fields with data needed for a lookup table.  Lets look at a sample migration from a trivia game.&lt;/p&gt;

&lt;pre&gt;
class CreateQuestions &lt; ActiveRecord::Migration

  def self.up

    create_table :questions do |t|
      t.column :text, :string
      t.column :answer, :string
      t.timestamps
    end

    Question.populate
  end

  def self.down
    drop_table :questions
  end
end

&lt;/pre&gt;

&lt;p&gt;I want to add some sample questions, so that even if you don&amp;#8217;t have your own questions, you will still be able to play the game.  I added the method to the populate model, because I use it elsewhere in the code, and I try to keep it DRY.  The populate method on the question model looks like this:&lt;/p&gt;

&lt;pre&gt;

class Question &lt; ActiveRecord::Base
  belongs_to :game
  has_many :answers

  def self.populate
    Questions.create(:name =&gt; "What is your favorite color?", :answer =&gt; "I don't know")
    Questions.create(:name =&gt; "Who was the first President", :answer =&gt; "George Washington")
    Questions.create(:name =&gt; "Who was born Samuel Clemens?", :answer =&gt; "Mark Twain")
  end

end
&lt;/pre&gt;

&lt;p&gt;So, later on, I decided to add a degree of difficulty to the questions, so the players can get more points for answering harder questions.  Here is what the migration looked like.&lt;/p&gt;

&lt;pre&gt;
class CreateQuestions &lt; ActiveRecord::Migration

  def self.up
    add_column :questions, :rank, :integer
    Question.destroy_all #In case there are any old ones
    Question.populate
  end

  def self.down
    remove_column :questions, :rank
  end
end
&lt;/pre&gt;

&lt;p&gt;Of which I had to change the populate method on the question class to:&lt;/p&gt;

&lt;pre&gt;
class Question &lt; ActiveRecord::Base
  belongs_to :game
  has_many :answers

  def self.populate
    Questions.create(:name =&gt; "What is your favorite color?", :answer =&gt; "I don't know", :rank =&gt; 1)
    Questions.create(:name =&gt; "Who was the first President", :answer =&gt; "George Washington", :rank =&gt; 3)
    Questions.create(:name =&gt; "Who was born Samuel Clemens?", :answer =&gt; "Mark Twain", :rank =&gt; 8)
  end

end
&lt;/pre&gt;

&lt;p&gt;Then I ran my migrations, and continued development.  Then when developer number 2 came across and checked out the project and ran the migrations, he got the error.&lt;/p&gt;

&lt;p&gt;undefined method rank= for class Question (&amp;#8230;or something very similar)&lt;/p&gt;

&lt;p&gt;The problem is the old migration is dependent on the new model.  All models in rails are just a mirror of the database, so the new model has a forward definition of the data.  The code in the model knows about the rank field, but the schema of the database hasn&amp;#8217;t caught up to create that portion of the mirror yet.  This creates a little bit of a catch 22.  The rails wiki (http://wiki.rubyonrails.org/rails/pages/UsingMigrations) about migrations tells you to redefine the class to stop name conflicts.  This would require me to make my migrations model agnostic, inserting straight to the database.  As a spoiled brat when it comes to databases and rails, I refuse to let go of my Active Record sugary syntax.  Another solution I thought of is to just make the last change to question do the populate, and remove it from the previous versions.  This will become a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;I came to the realization that I want to make a distinction between form and content when it comes to migrations.  Form in this case is schema form, the changes to the database which reflect the data which the Active Records can potential hold.  Content is the specific data which is in the database.  This distinction allows for me to use the power of my model classes in my data migrations, which is the place it is useful.  It maintains backwards compatibility, because before I go touching the data, I have to make sure my schema is right.&lt;/p&gt;

&lt;p&gt;What does this look like in Rails?  I am not sure yet.  Possibly db/migrations/schema and db/migrations/data.  Possible saving the data migrations in each migration as a block and executing those at the end, only when you have the schema is correct.  I am going to try it out!&lt;/p&gt;</description>
      <pubDate>Sat, 14 Jun 2008 02:38:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a2f74c84-789c-4b60-86fb-2ac683c00831</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/06/14/active-record-migration-dependancies</link>
      <category>Coding</category>
      <category>Paul</category>
      <category>Migrations</category>
      <category>Ruby</category>
    </item>
    <item>
      <title>Code Less: A Language Keystroke Expirement </title>
      <description>&lt;p&gt;When I first started writing code in ruby, it was a breath of fresh air after writing C# code for a year.  Ruby had a thesis, a clear purpose, rather than a hodgepodge of features strung together.  It was a language obviously written by someone who cared about what the code looked like.  So I jumped into it and loved writing ruby code (still do!).  Recently I had to write a project in Java using IntelliJ, and the powerful IDE was also a breath of fresh air after using text editors to write ruby code.  The IDE helps me in the same way ruby helped me.  I write less code that does the same thing, without loosing expressiveness or transparency of intent.  Less code in this case meaning less keystrokes.&lt;/p&gt;

&lt;p&gt;So, I am going to do a little experiment using two editors and languages: ruby with textmate and java with IntelliJ.  I want to see how many lines of code I have to write.  The application I am going to start is a simple baseball at bat scorer.  First lets see the ruby version.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img style="border: 0px;" src="/files/ruby_first.gif"/&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;We have about 27 lines of code written, and other than the describe method, which I have a macro for, I typed them all by hand.  Lets look at the java code.  This is just the JUnit test I wrote, there is no production code yet.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img style="border: 0px;" src="/files/java_orig_test.gif"/&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;It is about 16 lines of code, which I wrote all of but the import statement.  By doing a few alt-enters on the squiggly lines, I can get a stub of a class looking like this.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img style="border: 0px;" src="/files/java_class_stub.gif"/&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;That is 13 more lines of code, without really typing, just hitting enter a few times.  Now, lets start to make the method pass.  I am going to write the algorithm without worrying about all the type definition java wants.  Here is what it looks like.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img style="border: 0px;" src="/files/starting_class.gif"/&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;So the code written is around 4 lines of code.  Lets use the IntelliJ autocomplete features to help us make a passing test, which looks like.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img style="border: 0px;" src="/files/java_finished.gif"/&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;So roughly, the ruby version was 23 lines of written code and the java version was about 20 lines of written code.  There is an expense to doing all of the alt-enters to auto-generate the method and variable stubs, but IntelliJ is pretty smart about what it generates.  Also, I understand a single test doesn&amp;#8217;t tell the whole story, but it is a good indication.  I found as I wrote more tests for this application, a smaller amount of keystrokes was needed for the java version, and the same amount was needed for ruby.  This is due to the refactoring tools, and intellisense.  As applications get larger, I find the IntelliJ refactorings become more useful.  Inversely, ruby refactorings become more painful, as they are mostly done by hand.  &lt;/p&gt;

&lt;p&gt;So, in the end the constraints on a static language allows the IDE to make the refactoring tools better.  Specifically, when writing java code, I can lean on the IDE to generate all the uninteresting stubs for me.  All I do is fill in the algorithms: the fun part.  When I start to see places where my code can be cleaned up a bit, I can lean on the IDE again to do those refactorings for me once I recognize the need for them.  Removing and optimizing the code is something which is easily deducible in static languages, as it is mostly pattern matching, with no monkey patches, meta-programming, and evals to worry about.  This is a limitation which frustrates me as a developer who wants to have a large set of tools in my bag, but is helpful when it comes to developing a powerful IDE.  &lt;/p&gt;

&lt;p&gt;The number of lines of code I need to type isn&amp;#8217;t the reason I choose a language over another.  In fact, it would be pretty low on the list of deciding factors.  However, it is interesting to see what each language and its sets of tools do best.  Hopefully the ruby community can take some notes from them.  I would rather solve the other end of the equation, get a powerful ruby IDE.  I know Eclipse and Net Beans have some preliminary refactoring tools, but they are still aways from being as seamless as their java counterparts.&lt;/p&gt;</description>
      <pubDate>Sun, 08 Jun 2008 18:06:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a89cc279-825b-4aac-aa2c-aff5ec4cfd3d</guid>
      <author>Paul Pagel</author>
      <link>http://blog.8thlight.com/articles/2008/06/08/code-less-a-language-keystroke-expirement</link>
      <category>Coding</category>
      <category>Paul</category>
      <category>Ruby</category>
      <category>Java</category>
    </item>
    <item>
      <title>Announcing Limelight</title>
      <description>&lt;p&gt;I&amp;#8217;m pleased to announce the open source Limelight project: A thin client and application framework written in Ruby (JRuby).&lt;/p&gt;

&lt;div style="text-align: center;"&gt;
&lt;a href="http://limelight.8thlight.com"&gt;&lt;img style="border: 0px;" src="/files/limelight_logo.png"/&gt;&lt;/a&gt;

&lt;a href="http://limelight.8thlight.com"&gt;
    http://limelight.8thlight.com
&lt;/a&gt;
&lt;/div&gt;</description>
      <pubDate>Mon, 02 Jun 2008 20:42:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:53147eae-e5e2-4b46-bbb8-f6f4ca47ec48</guid>
      <author>Micah</author>
      <link>http://blog.8thlight.com/articles/2008/06/02/announcing-limelight</link>
      <category>Coding</category>
      <category>Fun</category>
      <category>Micah</category>
    </item>
    <item>
      <title>Erlang and the OCP</title>
      <description>&lt;p&gt;OCP was defined in 1988 in Bertrand Meyer&amp;#8217;s book &amp;#8220;Object Oriented Software Construction&amp;#8221;  as follows:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modules should be both open (for extension and adaptation) and closed (to avoid modification that affect clients)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Recently we had an issue in my office with our system which uses Rinda (a Ruby implentation of Linda) as a blackboard architecture.  The architecture looks a little like this crude drawing.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.8thlight.com/files/rindapic.png" alt="Rindapic"/&gt;&lt;/p&gt;

&lt;p&gt;This hides the OCP violation.  The &amp;#8220;rindlet,&amp;#8221; our informal name for these subprocesses, actually removes the message from the blackboard.  So if you send a message that looked like this [1, 2, 3] and one rindlet took it then no other rindlets can receive it.  To repeat myself, this meant all messages had to have as their first data member the name of the rindlet they were sending the message too.  This is bad.  Adding another rindlet meant changing the client sending the message.  Now to quote Agile Software Development: Principles, Patterns, and Practices [Martin 2003] &lt;em&gt;An axis of change is an axis of change only if the changes actually occur.&lt;/em&gt;  That is to say if only one rindlet cared about a message than this wouldn&amp;#8217;t be an issue.  When this became a problem was when more than one rindlet wanted the same message.  Suddenly we have to send many otherwise identical messages to different rindlets.  This is the heart of the OCP, the Server (in this case the one sending the messages), should be closed for implementation, but is not.  In our case we changed the architecture to shield the server from those changes, and fixed the issue.&lt;/p&gt;

&lt;p&gt;This brings me to Erlang and its message passing system.  Last year I began playing with it, but lost interest as the difficulty of the syntax simply ruined the fun for me.  I do know enough about it that when this issue came up in our ruby system, I was immediately reminded of Erlang&amp;#8217;s message passing system.  Specifically it has three methods [Armstrong 2007 pg. 134]:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spawn&lt;/strong&gt; - Create a new concurrent process that evaluates a passed in Fun.  The new process runs in parallel with the creating process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pid ! Message&lt;/strong&gt; - Send a message to a Pid - returned by the previous spawn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;receive&amp;#8230;end&lt;/strong&gt; Receives a message that has been sent to a process. &lt;/p&gt;

&lt;p&gt;On a cursory glance it appears we have the same issue since you must know the Pid of the process.  Aha, but the command sending a message to the process actually created the process, and therein lies the difference.  The blackboard architecture deliberately decouples the &lt;em&gt;constantly running&lt;/em&gt; processes from messages, the messages are sent to the blackboard.  The sender has no right to know about the constantly running process, and should not need to change to add another one.  Erlang on the other hand &lt;em&gt;spawns&lt;/em&gt; processes as if they were objects, and sends them messages.  Sending messages, heck that&amp;#8217;s what you do with an object too isn&amp;#8217;t it?  I don&amp;#8217;t think creating an object and sending it messages is a violation of OCP, and neither is this.  The sender can be extended without effecting clients.  It turns out that Erlang does not intrinsically violate the OPC like I&amp;#8217;d originally surmised, although like any other system I could easily create an architecture that did.&lt;/p&gt;</description>
      <pubDate>Sat, 24 May 2008 17:39:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:1b061550-57bd-47ce-af20-d9248cf1f464</guid>
      <author>Eric</author>
      <link>http://blog.8thlight.com/articles/2008/05/24/erlang-and-the-ocp</link>
      <category>Coding</category>
      <category>Rinda</category>
      <category>Eric</category>
      <category>Erlang</category>
    </item>
    <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>
      <category>Paul</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>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>
  </channel>
</rss>
