Tuesday, September 23, 2008

Ruby's Best Feature?

In my experience of building systems in Ruby over the last 7 years, I believe there is one main feature of Ruby that made these systems successful.  Before I get to that unique feature of Ruby I want to describe a few of the first systems I built in Ruby and what I learned from them.

The first system I developed in Ruby was a testing infrastructure for a distributed multi-agent system being developed and funded by DARPA.  DARPA is the research arm of the US Department of Defense.  This project's grand challenge was to build a software system that could survive "in theater".  The system had to continue functioning in a war-like situation with enemies attacking the software or the hardware the software is running on.  The main function of the software (beyond surviving) was real-time logistics planning.  Logistics includes routing supplies to people and places where its needed.  That may not sound very interesting but logistics happens to be the key function that makes large groups operate effectively.

What I built for DARPA was a testing framework that observed the events being generated by the software agents using XMPP and then sent commands to these agents using HTTP.  The core of the framework was a Domain Specific Language (DSL) which allowed us to script the multi-agent system.  Initially this scripting was limited to simple things, but that basic automation helped the program significantly.  In the first four months I wrote all the scripts.

During the next year the DSL was rewritten and then expanded to include all the forms of network and system attacks the program was tasked with creating.  What was really cool was the majority of the extensions to the DSL were written by other non-Ruby developers in the program.  The multi-agent system was written in Java, but each of the 80 people contributing to the attack-side of the program ended up learning enough Ruby to encode their attacks.  We also expanded the DSL to generate the logistics rules and from the rules the agent society definition.

This was a large deployment.  We had 300 dual core machines with 4GB of RAM and 10,000 agents running across them.  The Ruby script that was generated for a single agent society definition was over 1 million lines of code.  The events that Ruby handled per hour were well over 3 million messages of 1-10k each.

By the end of the program, Ruby was used to generate the entire agent configuration, drive the simulation, generate the attacks, record the results, generate reports and summarize them for the Program Manager.  This development taught me three very important lessons about Ruby:

  1. Ruby is an excellent language to encode domain specific logic in.  Its flexible syntax makes Ruby almost disappear and what's left is domain terms.  Once the domain is encoded its very easy for domain experts to use the Ruby DSL.  These domain experts may not be able to write it, but they most definitely can read and validate it.  When people talk about a 10x developer productivity increase, I believe this is the primary reason for it, the close communication between domain experts and those building the system.
  2. Programmers can quickly learn Ruby and can be effective in it, especially if they learn it in the context of something they know.  Every person on our project that wrote Ruby enjoyed it.  Their enjoyment was the main motivator to them becoming more and more proficient in Ruby.  I believe any good programmer can be a good programmer in Ruby.
  3. Ruby scales.  We pushed Ruby to unbelievable levels on this program and it exceeded our expectations.  The application under test was critical which made the testing framework even more critical.  There were places in our code where we had to drop into C to perform computationally intensive operations.  The ease of doing this is another key aspect of Ruby's scalability.

The second system I developed in Ruby was a desktop-based functional prototype for a complex system that was being designed for the US Air Force.  The goal of this system was to create a unified view across the 18 different groups that coordinate the movement of military aircraft and provide mid-air refueling with tankers.

The team that hired me to do this was a Human Computer Interface research organization that had spent the prior 3 years traveling the world to interview and capture the requirements of all 18 groups.  They had written a very detailed user interface specification for the system.  They wanted to deliver this user interface specification along with a functional prototype to show the final implementors what they meant in the text & pictures of their design.

The primary challenge was time.  They had less than 2 months left to build the functional prototype after a failed 24 person-month Java effort.  I chose Ruby and Flash to build the prototype in.  I will not focus on the Flash side of what I did because the Ruby side of this, although non-visual, ended up being transformative to the project.

My first meeting with the research scientist (who had become the domain expert) occurred in Boston.  On the flight up, I had no idea where to start with the massive tome of information in the specification they had created.  After arriving in her office we sat down in front of my computer and I brought up a text editor.  I asked her to describe the the concepts in the domain.  As she described it I typed in what I knew was valid Ruby syntax.  As we encoded her domain knowledge we created a DSL on the fly.  After 5 hours of talking and typing we had produced a very elegant 400 line script that she could read as her domain and I could read as code.  On the flight back to DC, I wrote the code behind this syntax to enable the construction of the domain model objects (I called this approach syntax-driven development.)

Over the next 4 weeks we iterated on the domain model.  I wrote scripts to parse flight plans and convert them to DSL code and flushed out more of the domain.  I sent snippets of the DSL to domain experts for review.  What amazed the team was the DSL encoding of the specification exposed numerous examples where the specification was incomplete or contradictory---something that none of them had seen in their reviews of it.

The final 4 weeks were spent developing the Flash-based UI which was driven by the domain objects in Ruby.  In the end we met our goals.  The functional prototype was delivered along with the updated specification.    Although the user interface specification was main product delivered to the implementation team, the Ruby DSL was an important tool they could use to better understand the domain.

So, what did these two projects have in common?  In both projects I used Ruby to implement the system through a language customized to the project domain.  These domain specific languages became effective mediums for team communications.  In my experience, this is the single most important feature of the Ruby language---capturing the domain in a language the entire team can speak. If you believe clear communications is an essential quality of highly effective teams, this feature is something that you should strive to exploit in your own Ruby projects.

Monday, July 23, 2007

First Facebook App (but not the last)

We have been working with Voxant over the last 6 months or so to move them over to a new infrastructure for their Web service TheNewsRoom. TheNewsRoom is a pretty cool service that allows you to find and embed 70+ news sources' news stories into your own Web site/blog and you get a cut of the ad revenue generated. They have LOTS of news sources too in video, text or image formats. The stories are streamed down in Flash.

TheNewsRoom has been resurrected in Ruby/Rails (of course) from is prior short and painful life in Java. Tom, Ryan and Dave have been working mostly on the Ruby/Rails stuff and I have been focusing on creating a very flexible media streaming framework in Flash/Actionscript for them. I would prefer the Ruby coding, but hacking Actionscript is where I am needed right now.

That is until about two weeks ago when Chad (our new CTO) and I decided that it would be cool to get TheNewsRoom to run inside of Facebook using their new app API. Chad and I did a quick weekend development effort and then showed the Voxant folks. They were quite thrilled to see their content streaming inside of a network of 30 million potential users (and growing). They gave me the go-ahead to develop the app in full and last Friday we launched it (and I got to build it in Ruby...and Rails...yeah!). After a weekend of waiting for the Facebook folks to approve the application its now in the directory. Since Facebook does not really have news outside of what your friends are up to, this is a pretty solid news app. Right now its focused on video news but we surface 13 different categories including Business, Entertainment, Health, Life and Leisure, Politics, Science and Tech, Sports, US, World, and a few others including "Odd" (which has some weird stories in it). When you watch a news story you can comment on it and your comment will post on your profile (so your friends will see it in their feed if they have TheNewsRoom installed). There is an additional category of just news items that you and your friends have commented on (News with Comments). Its simple to use and fun to watch and comment together on what's happening in the world. Give it a spin if you are on Facebook. If you are logged in, navigate to this URL: http://www.facebook.com/apps/application.php?id=2406724706. Let me know what you think.

Update: It seems like if you have a Facebook app that you want to link to, you can just use this URL pattern: http://apps.facebook.com/thenewsroom and it will take you either to the app or let you install it. So, go install TheNewsRoom app!

Thursday, February 16, 2006

Get indi baby!

Well, after a year of very hard work, we have finally entered a (limited, invitation-only) Beta for indi. What is indi? You can find out here: http://getindi.com. indi is our answer to folks who believe that you need to put all your stuff on their servers to gain anytime-anywhere access to it.

Technically indi combines a lot of the work I have done in Ruby such as FreeBASE (plug-in framework for the FreeRIDE IDE), Jabber4r and Alph (Ruby to Flash bridge) with the work I have been doing in Flash/ActionScript...specifically the ActionStep port of the OpenStep/Cocoa App Kit to Flash. This combination creates a cross-platform execution environment with Ruby as the data manager, and Flash for the UI.

indi runs on OS X and Windows right now, and as soon as Flash 8 is supported on Linux it will run there as well. indi is more like a platform than an application, and its going to allow us to give some really cool capabilities to our users and deliver on a vision we have of digital independence (reverse the two and you get in..di - indi).

Anyway, we have a busy schedule ahead to release our next Beta in about 4 weeks at O'Reilly's Emerging Technology Conference.

Saturday, August 06, 2005

ActionStep and Rails

Some may have heard the crazy story about my integrating ActionStep and Rails at OSCON. ActionStep is an OSS component framework for Flash written in the ActionScript programming language. Rails is...well that goes without saying. I was slotted to speak on ActionStep on Thursday in the Emerging Tech track. I have to admit that although I have been doing Ruby programming for 4 years, I had never touched Rails. My job really has nothing to do with Web frameworks and such, and time slips by... Anyway, OSCON presented an opportunity to see Rails in action and I sat through David's great tutorial session. Rails is a really nice Ruby framework, and it struck me that it would be cool to come up with a templating language to build ActionStep-based UIs with Rails. Monday and Tuesday I iterated on a design with David, Dave Thomas, Glenn Vanderburg...all the fun Ruby folks, and came up with something linguistically nice. David asked me to add to my ActionStep/Rails syntax slides into my presentation as a 'teaser'. Here is an example of the templating format:

NSView :test do
  attributes :rect => {:x => 0, :y => 0, :width => 200, :height => 400}, 
             :backgroundColor => 0xdddd00
  publishes :selected_person_id => execute { names.selectedItem.label }
  NSButton :hello do
    attributes :title => "Test", 
               :rect => {:x => 10, :y => 10, :width => 20, :height => 20}
  end
  ASList :names do 
    attributes :items => @names, 
               :rect => {:x => 10, :y => 50, :width => 100, :height => 200}
  end
end

Having slides that showed this format was cool with me...but on Wednesday night all that changed. I went to hang with the FOSCON folks, and presented the teaser slides to them. People really liked the syntax and the implications of what having a Flash framework attached to Rails could mean. Then all hell broke loose. Well, actually not hell proper, but chaos harnessed in a very Ruby way by _why the lucky stiff. After his side splitting performance I went back to my hotel around 11pm and decided to just implement the syntax in Rails and ActionStep. I mean, how hard could it be to build a Rich Internet Application framework? I started at 11:30 with two Dr. Pepper and by 6:00am had stuff rendering from Rails to ActionStep. I crashed for an hour and a half, and then went to the David's keynote on Rails. His keynote gave me just the boost I needed to push it a little further and I spent the next hour getting data sent back from ActionStep to Rails. At my 11:30am session I was able to fully demonstrate Rails dynamically creating and serving an ActionStep-based UI. You could update the text templates, press refresh in your browser, and the UI would re-render with your changes. Round-tripping data...the works.

I would like to say that it was just a few lines of code, but that is not quite the case...its a few more than a few. I will be creating a Gem by the end of the month to allow people to play with things, and until that time I wrote up what the syntax looks like...you can see it here in more detail:

http://www.osflash.org/doku.php?id=actionstep_rails

To Open Source and all that it implies..um...ok, I need to sleep now.

PS. United Airlines sucks, I just needed to get that out.

Friday, April 29, 2005

Ruby 1.8.2 in Tiger

Nice...the Apple team included Ruby 1.8.2 in Tiger. Tis a sweet thing indeed. If you want to build extensions for it though you need to install xCode Tools. And then, there is a minor problem with the shipped rbconfig.rb file. The wiki on the rails site here documents the change.

You can also use RubyGems to fix it too thanks to Chad Fowler who already built a Gem (fixrbconfig) to fix the problem. After you install RubyGems you just do this:


% sudo gem install fixrbconfig
Password:
Attempting local installation of 'fixrbconfig'
Local gem file not found: fixrbconfig*.gem
Attempting remote installation of 'fixrbconfig'
Updating Gem source index for: http://gems.rubyforge.org
Successfully installed fixrbconfig-1.0

Then run (from another terminal window):


% sudo fixrbconfig
====================
This program will replace your rbconfig.rb , located in /usr/lib/ruby/1.8/powerpc-darwin8.0/rbconfig.rb
Press enter continue or ctrl-c to abort.
Backing up original rbconfig.rb in /usr/lib/ruby/1.8/powerpc-darwin8.0/rbconfig.rb.bak
All Done! You should be able to compile C extensions now!

Its nice when package managers ship fixes to OSes on the same day the OS ships!

Now, full steam ahead with Ruby on Tiger!

[UPDATE] Lucas Carlson posted this very nice script to fix both the rbconfig.rb file and download and install readline support (which gives you command recall in IRB). Very nice indeed! If you have already applied the rbconfig fix, you can just snip out the lines starting with: curl ftp://ftp.gnu.org/gnu/readline...

Tuesday, October 19, 2004

RubyGems marches toward 1.0

We have a lot to celebrate today in the world of RubyGems...we passed the 5000 download mark of RubyGems and over 20000 gem libraries have been downloaded and installed. Chad Fowler has captured this nicely on his blog.

Its not too long before we reach the 1.0 milestone...but with over a hundred Ruby libraries already available and more coming every day, there is no time like the present to install RubyGems and experience an elegant solution to package management for an elegant dynamic language.

Viva Ruby!

Saturday, October 02, 2004

Alph code released into the wild

Well, here is the first public release of Alph:

Alph Project Site

Alph is a Ruby/Java/Flash (I know...I am insane) that bridges the Ruby and Flash runtimes (and Java too...but that is to solve the cross-platform projector problem that Macromedia will not solve.) With Alph and Ruby (>= 1.8.1) you can create Flash user interfaces (forms, etc) that are fully coded in, and controlled by Ruby. No Actionscript required, no Flash IDE required, just Ruby (and those dependent runtimes). Here is a simple ruby script:

This example demonstrates the List Box family of components (ComboBox, ListBox, Grid). See: http://www.ultrashock.com/tutorials/flashmx2004/ui-components06.php

$:.unshift '../lib'
require 'alph'
app = Alph::Application.new
frame = app.new_frame
frame.control.setBounds(100, 100, 640, 480)
flash = frame.flash
myComboBox = flash.new_component("mx.controls.ComboBox", 
  :editable=>false, :rowCount=>5,
  :_x=> 14, :_y=>26, :_width=>291, :_height=>22)
myComboBox.labels = ['Organic Snacks', 
 'Recycled Office Paper', 'Wind Energy', 
 'Solar Power']
myComboBox.change do |event|
  # The myComboBox.selectedItem method returns 
  # the label (not an object) because the data is not set.
  puts "You selected #{myComboBox.selectedItem}."
end
myList = flash.new_component("mx.controls.List", 
  :_x=> 14, :_y=>66, :_width=>291, :_height=>120)
# Data provider is an array of anonymous objects (label/data)
myList.dataProvider = [ 
  {:label=> "Organic cotton underwear", :data=> 7.25},
  {:label=> "Organic T-Shirt", :data=> 15},
  {:label=> "Recycled Office Paper", :data=> 6.99},
  {:label=> "Organic Cola", :data=> 1.25}
]
myList.change do |event|
  # The myList.selectedItem method returns an object with
  # a label and data property because the data _is_ set.
  item = myList.selectedItem
  puts "#{item.label} costs $#{item.data}"
end
myDataGrid = flash.new_component("mx.controls.DataGrid",
  :_x=> 14, :_y=>200, :_width=>291, :_height=>120)
# Column names align with column ids
myDataGrid.setColumnNames( ["Product", "Price", "Quantity"] )
# Data provider is an array of anonymous objects (keys = column ids)
myDataGrid.dataProvider = [
  {:Product=> "Underwear", :Price=> 7.25, :Quantity=> 3},
  {:Product=> "T-Shirt", :Price=> 15, :Quantity=> 1},
  {:Product=> "Paper", :Price=> 6.99, :Quantity=> 7},
  {:Product=> "Cola", :Price=> 1.25, :Quantity=> 24}
]
myDataGrid.change do |event|
  # The myDataGrid.selectedItem method returns the anonymous object
  item = myDataGrid.selectedItem
  puts "#{item.Product} costs $#{item.Price} (#{item.Quantity} left in stock)"
end
# You can rename column names by index
myDataGrid.getColumnAt(0).headerText = "Product Name";
myDataGrid.getColumnAt(1).headerText = "Price";
myDataGrid.getColumnAt(2).headerText = "Quantity Left";
flash.new_component("mx.controls.Button", :label=>" Close", 
  :_x=>380, :_y=>89, :_width=>120, :_height=>35, 
  :icon=>"icon_16x16_warning") do |closeButton|
  closeButton.click do 
    frame.control.close
    exit
  end
end
frame.control.show
app.wait_until_done

Pretty sweet eh?

Go download it, and let me know what you think.

Monday, March 15, 2004

RubyGems Alpha I Release

Well, tonight Chad Fowler and I released the first version of RubyGems (Alpha I). If you are a Rubyist you can download it from here. I wrote on RubyGems after I returned from RubyConf 2003 last fall, and since then we have had little time to work on it until this last weekend. Our intent is to now press on until we reach the 1.0 release. To get a good sense of the power of RubyGems see the User's Guide at RubyForge.org. My hope is that folks will start using and producing Gems and move Ruby's handling of libraries (creation, distribution, installation, uninstallation) to the next level.

Monday, March 08, 2004

Using Xcode to Edit Ruby Files

This is the first of a series of posts on using Xcode to edit Ruby files.

For those that are familiar with Xcode, this will likely not be very informational, but for those of us that are new to Apple's programming editor, perhaps it will be useful. Xcode ships with Apple's developer tools which can be downloaded here (free/subscription required). A little known fact is that Xcode syntax highlights Ruby source code, so if you aren't a VIM or Emacs disciple, perhaps Xcode is for you.

First things first. If you always want to edit your Ruby files using the Xcode editor, use the Finder to browse to a folder with a Ruby (.rb file) in it. Then single click on the file (to select it) and then chose the File/Get Info menu item. This will present a nice long information panel. In that panel there is an 'Open with:' section that has a drop down in it. Select that then choose 'other'. This will bring up a file browser. The Xcode .app file is located in /Developer/Applications. After you select 'Xcode' make sure and select the 'Always open with' checkbox in the lower left corner, then press the 'Add' button. The drop down should now say 'Xcode' and if you click on the 'Change All...' button the Finder will open all Ruby files with Xcode.

That's it. Now, whenever to double-click on a Ruby (.rb) file in the Finder, it will open the Xcode editor. Also, if you are at a command line and there is a Ruby script you want to edit, you can just type 'open myscript.rb' and it will open the default application for .rb files...which we have now made Xcode!

In my next post I will discuss setting up the editor using the Preferences in Xcode that make editing Ruby extra special (like showing line numbers, indenting, coloring, etc). I will conclude with post on using the project capability of Xcode to edit groups of Ruby files.

Saturday, February 21, 2004

At FOSDEM 2004

Well, I am here in sunny Brussels at FOSDEM 2004 going to evangelize the wonders of Ruby to our European brethren. I conducted on interview last month about Ruby and that can be found here. I will start with a tutorial on Ruby at 1400 today (Saturday) and then tomorrow at 1600 give a talk on Ruby. It seems like its going to be a nice size group, and look forward to interacting with the other speakers this evening. As things go, I will post my tutorial source and presentation here on this blog, but since these things are still evolving, they will have to wait a bit ;-)