Implementers Unite!
There’s a lot of things that Rubinius, MatzRuby (including YARV), JRuby, IronRuby, MacRuby, Ruby.NET, MagLev don’t agree on. But that’s ok, because above all, they seem to agree that Ruby is one awesome language. And lately, that apparent agreement has gotten a boost of sorts.
Earlier this week, Rubinius (an Engine Yard project) announced the RubySpec project at rubyspec.org. The effort to write an executable specification using RSpec-style specs started with the Rubinius project in late December 2006. Since then, many people all over the world have contributed to the effort, including core folks from JRuby. Engine Yard has been financially supporting significant development of the RubySpecs since hiring Evan in June 2007 and other full-time developers (myself included) in Jan 2008. All this effort has been to ensure that the Ruby programming language continues to evolve and receive the recognition it deserves.
Another recent development has been a regular meeting of folks working on various Ruby implementations. These Ruby design meetings are bringing together folks to discuss tough issues with Matz and everyone else.
Well, after last night’s meeting, Tanaka Akira (sorry, I don’t have a link to his website; if you do, please let me know) checked in some changes to the ruby-core Makefile to fetch and run the RubySpecs. This is a very proud moment for me.
If you love Ruby, it doesn’t matter what color shirt you wear, what language you play with, or what country you live in. You can play a valuable role in helping make Ruby a wonderful language for everyone. Please help us with the RubySpecs.
Protx: An update
Last year I wrote a rather angry post about the quality of service provided by Protx during a system upgrade.
This caused a bit of a stir, possibly due to the high Google ranking and certainly the derogatory tone of the post.
I've since been contacted by Simon Black who took over as Managing Director of Protx last year. He has been pushing through a number of changes that he hopes will improve the customer support experience.
One of the more apparent surface changes is an update of the Protx support pages. The change in tone from the original pages is very positive:
"At Protx we are passionate about providing high quality support and service to our customers. Our technicians are trained to ensure that they provide you with a professional service and the correct technical response to your question.
We are happy to speak to you over the phone, communicate via email, or if you prefer you can resolve the query yourself using our in-depth website. You choose the method that’s best for you.
We aim to pick up calls within 60 seconds and respond to emails within 24 hours."
Simon also sent the following update on the progress they've been making to improve the service:
"Since last August Protx has transformed it's support operation by more than doubling the size of the team and investing in training and development. During 2008 there will be continual improvements to the way we provide customer service which will include overhauling the entire Support web pages.
Our aim is provide an excellent customer experience and we are proud to receive feedback showing that this is now happening more and more. The software platform we launched last Summer has resulted in a significant decrease in the number of Support issues raised on average. It has also allowed us to launch new features, for example, a much more efficient method for taking regular payments.
In the coming months and years we will invest significantly to ensure we provide a great service, remain the easiest payment gateway to integrate with and provide more and more added value to our customers' businesses.
Any customers or developers that are unhappy with the service they have received from Protx can send an email to feedback@protx.com and they will receive a prompt response from one of our senior managers."
I'm not sure I'd use Protx again, but I think it's great to see positive action being taken on something as important as customer service.
Customer service is a product itself in any successful company. It should be treated with the same care and attention as you give other products you sell.
The two kinds of programmers
In my time as a developer, and now managing a team of developers, I have come to realize that there are two kinds of programmers: the Journeyman and the Craftsman. These terms aren’t mine – I’ve seen them used other places – but they describe the developers I’ve worked with pretty well.
The Journeyman
...knows one programming language.
...knows one operating system.
...can’t be bothered to learn something on their own.
...doesn’t know anything about the operating system or hardware their applications run on: “Someone else takes care of that”.
...never masters his tools. “I know my way around my IDE, that’s good enough”
...doesn’t refactor: “It’s ugly, but it works. Leave it alone!”
...only learns about the part of the system they are working on. No need to learn the rest of the system: “That’s not my job”.
...doesn’t want to take on an unfamiliar technology: “I haven’t had any training on x”.
The Craftsman
...knows a handful of programming languages, and is always on the lookout for the next one he should learn. He knows that learning any new language will stretch his mind and make him a better programmer in the language he uses day to day.
...devotes time to learning about new technologies, and helps to make others aware of them.
...understands the platform and operating system his applications run on, because he knows that’s the only way to diagnose many problems.
...masters his tools. He can perform magic in his chosen editor, and is always looking for ways to make himself more efficient.
...rarely passes up an opportunity to broaden his knowledge of the system he is working on.
...is always willing to take on something he’s unfamiliar with. He can pick up most things pretty easily, and enjoys the challenge of learning something new.
One craftsman is worth three or four journeymen. Easily.
It’s the journeymen whose jobs often end up moving overseas (and rightfully so, they add little, if any, value).
The longer I manage development projects, the more I value the craftsmen I have around me.
POPSignal in Boston
Tonight I’ll be at POPSignal in Boston, a party graciously organized in part by Brian Balfour, the founder of our company (Viximo). Hope to share a beer with you there.Bike rage
Perhaps it's because it is Bike to Work day today in San Francisco, but there seems to have been a lot of controversy stirred up on the web this week by the gentle art of cycling.
First, there was the ridiculous assertion that cycling is less efficient in terms of energy consumption than driving, as if we -- in developed countries -- need to consume any extra food to fuel our cycle rides or as if drivers fast to compensate for the energy not used when driving their cars. I could go on...
And then a post by jwz, offering his own advice for people wanting to start cycling in San Francisco, attracted an enormous pile of enraged comments, many from other cyclists upset by his recommendation to "Never take bike advice from anyone who owns bike shorts, clip shoes, a messenger bag, or a fixie." I don't necessarily agree with all his advice either (though he did make it clear that it was specific to the cycling situation in San Francisco), but I wouldn't get upset about it. People cycle for all kinds of different reasons, and have their own preferences, requirements and constraints. There really is more than one way to do it.
I suppose that I don't understand why cycling inspires such ire in people. If you're not being harassed by drivers (or anyone else who seems to take it as a personal rebuke that you are using a eco-friendly mode of transportation), or or pedestrians, or being taunted by gangs of school children, or having your tyres shredded by the glassy remains of outdoor binge-drinking sessions that seem a permanent fixture next to every park bench in Birmingham, other cyclists also seem to want to join in.
Of course, some cyclists act like idiots, just like some drivers and some pedestrians, but does that have to mean that the rest of us who just want to potter quietly to work have to take the rap? In that context, watching this video of a school run in the Netherlands (via Velorution) made me want to cry -- it's like glimpsing Utopia. All those comfortable, sensible, load-bearing bikes! The broad, glass-free, well-maintained cycle paths! The people cycling calmly along in their ordinary clothes, and not wearing helmets! The hordes of children cycling with their parents! Sigh.
Topology Aware Consistency Policies
I am increasingly fascinated by consistency options, in a distributed
storage system, made available by topology awareness on the
client. For example, if you consider a write committed iff the
write has been made to a majority of all storage nodes and a
majority of the local nodes, where local would typically be "same
datacenter," it allows you to achieve repeatable read
read what you wrote
consistency locally when a majority of local nodes have responded
to a read request with a matching response, while still providing
overall consistency across the entire system.
StaticMatic 2 is coming
StaticMatic is currently going through a major over-haul. There are loads of great features in the works as well as changes to the way to core works.
The major change is that StaticMatic 2 will now use ActionPack. This means we get loads of great new features:
- Any templating language you like
- Access to all ActionView helpers
On top of this we also now have:
- Rake tasks for commands
- Better error handling
- 'Modified Date' sensitive building of static files - StaticMatic now only builds files you've modified
We're also now hanging out with cool kids on github: http://github.com/stevebartholomew/staticmatic/tree/master.
Call to Arms
Now, we need your help. StaticMatic 2 is not yet feature complete. There is still a lot of work to do with getting all the current features in as well as working up the new stuff.
What we need is for you to try out the new features on your existing StaticMatic sites. The great thing is, you can run the new version without conflicting with the current one:
Download the edge version into your site's root directory:
~/Sites/mygreatsite $ git clone git://github.com/stevebartholomew/staticmatic.git
Create a Rakefile in your site's root containing this:
require 'rake' require 'staticmatic/lib/tasks/staticmatic'
That's it. You can use the new StaticMatic commands:
rake preview
rake build
Or you can use your Gem version:
staticmatic preview .
staticmatic build .
The main thing that needs testing is integration into ActionView - try out the helpers, see what happens. There's a fair few hoops to jump through to make ActionView happy being separated from ActionController so it can play up!
New to StaticMatic?
If you're new to StaticMatic, you can try out the new version by installing the current one and creating a new site:
sudo gem install staticmatic
staticmatic setup mygreatsite
and following the instructions above.
Be Gentle!
There's a fair way to go before we're ready for a release, but hopefully you can still have fun trying out the new features. Join us over at the Google Group for more discussion.
GetText, Rails, Authentication, Japanese Firefox, Setting the Language Manually
There occurs an interesting problem when you are using Ruby’s GetText to translate a site that requires authentication.
Most likely, you have a before_filter that calls a method that authenticates the user for certain methods. Within this filter you probably have something like:
user = (attempt_oauth or
attempt_basic_auth or
attempt_session_auth or
attempt_cookie_auth or
(@authentication_attempt = nil))
If the user has clicked “Remember Me” and stored an cookie locally, than we’re going to validate the user using attempt_cookie_auth. But what if the user has a default language set (stored most likely in the database). We’ll assume there is a method user.lang that returns the default language or nil.
Your first attempt at setting this here may be this one.NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
end
That sets the cookie for the user, but the GetText stack has already been invoked, so the language will be that sent over by the browser. Refreshing the page will cause GetText to pick up the cookie value and render the proper language.
Next, we try using set_locale (GetText.set_locale) to set the language manually, which seems like a perfectly reasonable option.NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
set_locale u.lang
end
Why is this bad? The set_locale method persists for the life of the Ruby instance (in this case, Mongrel), not the session. This means that there will be a literal battle for contention over which language to use.
User A sets the language to JA and the page renders JA.
User B sets the language to EN and the page renders JA.
User A sets the language to JA and the page renders EN.
You see the problem! We want a clean slate at the beginning of each request so GetText has no pre-conceived notions about what the language should be. Hrm … let’s try something.
NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
set_locale u.lang
else
set_locale nil
end
Note … to be thorough, and because the authentication stack is not called for all methods, we also add this in our application.rb
before_init_gettext :set_default_locale
def set_default_locale; set_locale nil; end
Here, everything seems to work! We can even write a test to verify that the contention above doesn’t occur.
def test_lang_should_be_set_on_a_per_session_basis
bob.lang = 'ja'
assert bob.save
bob.reload
assert_equal 'ja', bob.lang
post '/sessions', {:username_or_email => bob.screen_name, :password => 'foo'}
assert_response :redirect
follow_redirect!
assert_response :redirect
follow_redirect!
assert_response :success
assert_equal 'ja', Locale.current.language
phoenix.reload
assert_equal nil, phoenix.lang
post '/sessions', {:username_or_email => phoenix.screen_name, :password => 'foo'}
assert_response :redirect
follow_redirect!
assert_response :redirect
follow_redirect!
assert_response :success
assert_equal 'en', Locale.current.language
end
But alas, download the Japanese version of Firefox and visit the page.

The browser is hungry for UTF-8 data. As you can see, the part of the page in which we set the locale manually using set_locale is being pushed as SHIFT-JIS. The blue highlighted area is actually outside of the application.rb controller stack, so is sent via GetText’s default assumptions: UTF-8.
But this isn’t a problem in Safari or Internet Explorer. Why? Let’s look at the value of HTTP_ACCEPT_LANGUAGE.
Firefox : "HTTP_ACCEPT_CHARSET" => "EUC-KR,utf-8;q=0.7,*;q=0.7"
Safari : "HTTP_ACCEPT_CHARSET" => ???
Safari actually doesn’t pass one, while Firefox gives precedence EUC-KR (effectively SHIFT-JIS) over UTF-8.
Sigh. Things are looking grim. Back to the drawing board. Let’s look at the order of precedence for how the Rails GetText integration determines the langauge.
The language passed to GetText.bindtextdomain.
The lang query param. ( url?lang=foo )
The lang cookie.
The value of HTTP_ACCEPT_LANGUAGE passed by the browser.
The default (English).
Aha! GetText.bindtextdomain! Looking at the RDocs and source, this is not only called within the init_gettext method, but can be set on a per session basis without mucking with default language settings!
Let’s try!NOTE: THIS IS CORRECT! CELEBRATE!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
GetText.bindtextdomain("Twitter", :locale => u.lang)
end
So finally, we can set the language on a request manually after the GetText stack has already been invoked. Whew!
Customer service, one at time.
A lot of companies think of customer service at the high-level or grand scale. Help systems, Call centers, Infrastructure, etc. Running Beanstalk and Newsberry, I do as much as possible at the individual level as possible. It's where customer service really counts. Deciding to use Campfire chat for support has been one of the best moves for us, despite the mishaps. We offer direct access, and in turn, obtain direct feedback from our customers.What's New in Edge Rails: DB Console
For those of you that haven’t committed the database username and passwords for your many apps to memory yet, there comes some help from edge Rails – the addition of a dbconsole script that will automatically drop you into a database prompt using the info in config/database.yml configuration.
In an edge rails app that has a mysql db config:
script/dbconsole
...
mysql>
And there I am, logged into the dev database in the mysql command prompt. No scrounging around for that app-specific username or db name or cat ing the config/database.yml file anymore.
tags: ruby, rubyonrails
"loaded_specs" Gem Error
For those of you that have run into this gem error when running the latest rails:
./script/../config/../vendor/rails/railties/lib/initializer.rb:175:in `install_gem_spec_stubs': undefined method `loaded_specs' for Gem:Module (NoMethodError)
from ./script/../config/../vendor/rails/railties/lib/initializer.rb:175:in `reject!'
from ./script/../config/../vendor/rails/railties/lib/initializer.rb:175:in `install_gem_spec_stubs'
from ./script/../config/../vendor/rails/railties/lib/initializer.rb:89:in `send'
from ./script/../config/../vendor/rails/railties/lib/initializer.rb:89:in `run'
from ./script/../config/boot.rb:46:in `load_initializer'
from ./script/../config/boot.rb:38:in `run'
from ./script/../config/boot.rb:11:in `boot!'
from ./script/../config/boot.rb:109
from script/dbconsole:2:in `require'
from script/dbconsole:2
the solution is a quick and dirty:
gem update --system
Or, if you currently have rubygems v0.8.4 or earlier installed:
gem install rubygems-update
update_rubygems
Just a public service announcement from the “Ryan’s been bitten by this one” dept.
Progress on Projects
This weekend saw forward progress on several of projects. The progress wasn't less than I hoped for but I was limited by back and wrist pain.
Userscripts.org got a bunch of spam removed, and I integrated uservoice.com's feedback service. Hopefully this will help with prioritization of what the users want most. I debated using Get Satisfaction but they do much more than just idea collection and voting - solving more problems than I have and resulting in a consuming UI (in my opinion).
I brainstormed with Ian about syncing for Taboo and UI cleanup. Then Jake Dahn pinged me that he had knew how to fix a bug with middle clicking not working (seems that gecko doesn't like middle click on a span only an anchor tag). I have been trying persuade him to contribute to open source for a while (since I was at Flock), so seeing his first push to github is awesome.
Book Burro, unfortunately didn't get as much time as I was hoping. A major rework of the extension is done, waiting on Librarius to be published. Librarius is a catalog of libraries that can be used by Book Burro or a new version of Library Lookup. I'm specifically aiming to fix the problem we hit last time, "the accuracy of those lists has decayed over time, and I'm not able to maintain them."
Holy God, Powerset Launches
We’re out, searching Wikipedia and FreeBase. Proud doesn’t begin to describe my feelings about what’s been created. I think it speaks for itself, and I’ve been using it instead of Wikipedia for the last few months.
Some people even seem to really get it. And that’s an amazing high.
Huge thanks are not only due to the Powerset team (I love working with these people), but also to all of the open source projects we’re making use of. Hadoop. HBase. Thrift. Ruby. Merb. Rails. god. Mongrel. Mootools. RabbitMQ. The ActiveMessaging Project. Memcache and MemcacheDB. Erlang. Fuzed. YAWS. Countless others. All those people who take the time to answer our questions, and respond to our bugs, and consider our patches, and write interesting articles, and make our code better. You guys rock, and we couldn’t do it without you. So much love is heading in your direction right now. Thank you, thank you, thank you.
I’m exausted, and going to bed. Good night, and good luck. And try the app. I’m stoked.
tms [fernLightning] [ma.gnolia]
Interesting-looking tool which allows you to see your Time Machine backups as something similar to a VCS.
Saved By: bsag | View Details | Give Thanks
Tags: command-line, timemachine
bag is hot [ma.gnolia]
Tumblelog by musician Joseph Arthur, complete with tracks.
Saved By: bsag | View Details | Give Thanks
Tags: music
ToDo's On Your Desktop
I’m not going to lie and tell you that I’m great at task management. Frankly, I suck and I blame it on technology. If only there were a task system that could light a fire under my butt. We all know there isn’t, but the system that I’ve found to work best for me is Todoist. Todoist is really light and fast. Also, it has a simple API so it’s very extensible and already has a lot of tools surrounding it (quicksilver, launch, dashboard widget, mobile, gmail integration, etc).
The Problems
The problem that I have with task management is two fold. First, I need reminders. My programming brain is sharply trained to scoot information in and out, only keeping what is immediately necessary. It’s great to have a to do list but if it doesn’t remind me, it barely works. The good news is that todoist has a premium service that is only $3/month (yes only $3) that allows for reminders in any form you like (twitter, sms, email, jabber, etc). First problem solved.
The second problem that I have is that sometimes a reminder is not enough. I personally need to see my upcoming projects, tasks and calendar items in front of me anytime I can. It hit me the other day that I look at my desktop a lot. This got me wondering if I could use the todoist API to put my upcoming, date sensitive tasks right there, on the desktop, in front of me whenever I’m on my laptop.
The Solution
I did some googleing and found Geektool, which I had installed/uninstalled before but this time seemed to have a purpose. The end result is in the screen cap below.

To do this, I created a quick and dirty ruby script to hit the todoist api and put out a simple list of all time sensitive tasks. 1) I put the following script at ~/bin/todoist.rb.
require 'yaml'
require 'rubygems'
require 'rio'
require 'json'
require 'active_support'
def todoist_query(*args)
token = args.pop
queries = %Q{["#{args.flatten.join('","')}"]}
url = "http://todoist.com/API/query?queries=#{queries}&token=#{token}"
JSON.parse(rio(URI.encode(url)).read)
end
lines, now = [], Time.now
config = YAML::load(rio(File.join(ENV['HOME'], '.todoist')).read)
format = '%Y-%m-%dT%H:%M'
days = (now..now.advance(:days => config['days'] || 3)).step(1.day)
todoist_query("overdue", days.map { |d| d.strftime(format) }, config['token']).each do |type|
next if type['data'].size == 0
lines << (type['type'] == 'date' ? Time.parse(type['query']).strftime('%b %d').gsub(/\s0/, ' ').upcase : type['type'])
type['data'].each { |i| lines << " - #{i['content']}" }
lines << "\n"
end
puts lines
Like I said, it’s quick and dirty. 2) Now setup geektool to run the script at a given interval (I chose 2 minutes).

3) I created a file in my home directory to store my todoist token and the number of days I want to show. The main reason I separate the token from the ruby script is in case I feel like using it somewhere else on my system with another script. If my token ever changes, I can update it in one place and all the scripts will still use correct one. Anyway…I put the file at ~/.todoist and it looked something like this:
token: foobarbaztoken
days: 4
Now every two minutes the script runs and updates based on how I am updating my tasks at todoist.com. My tasks are continually in front of me, which helps keep them in my mind so that I actually get stuff done.
Other Uses
Some other uses I could see valuable for this would be calendaring. Google Calendar has an API so you could hit that and show your upcoming events right by your tasks. Maybe there is some site that posts a lot of updates and it’s hard to keep up with by feeds? Just use feedtools and a tinye ruby script to show the latest posts for your perusal when you get a few seconds. Just some thoughts.
Anyone else do something along these lines? Have some code to share or thoughts on how to do it better? Let me know.
A prelude
What good would a comeback be if there wasn’t some Rocky story about how I found myself at the end of the road, the bottom of the bottle, the back of the bus, only to be miraculously motivated to push myself to the limits to get back in shape and fight for glory? That [...]Was away on vacation
It’s been quiet here the past several weeks and that’s because for the first time since I started Planet Argon, I was able to take an extended vacation.
My partner and I headed to France (Paris, Nice, Lascaux II, and Bordeaux) for a few weeks. It was a first time for both of us. I’ve posted some photos on my flickr (vacation set).
I’d like to thank my amazing team for helping make it easy for me to take off for that much time. :-)
In any event, I wanted to post a few non-technical links…
- Veggie Tastespotting (tastespotting without the meat)
- Robby’s Muxtape
- Robby’s Grabb.it
- Robby on twitter
- Robby’s feedflix (netflix queue/stats)
Link yours up!
In the coming weeks… I’ll be posting some more thoughts on Project Management, time management, and anything else that seems to come up. If there is anything you’d like me to write about, feel free to drop me a line with a request.
Thinking with Tinderbox
I've been trying to write another grant proposal recently (a seemingly Sisyphean task for academics), but I ended up a bit stuck. It was a collaborative idea that a colleague and I sketched out last year, but which -- for one reason or another -- ended up on the back-burner for a while. I was really struggling to pull it together. We had plenty of ideas, but I was having trouble rearranging and grouping them into a sensible structure and seeing gaps that needed to be filled. Finally, I decided to blow the dust of my copy of Tinderbox and try that.
I wish I'd done it earlier. I used to use Tinderbox a lot for writing notes and organising ideas1, but newer, shinier applications have come along, and I've gradually turned to them. But Tinderbox is still a great tool, and it really excels at visual brainstorming. If you open a map view, you can just hammer out short notes containing all your ideas, then group them into similar themes later. With a linear outliner (a view which Tinderbox also has), you end up worrying more about where stuff should fit than what the important ideas are.
Once I'd got all the ideas down, I made some adornments ('sticky notes' on the page to visually group notes), and started moving notes around, first into similar ideas, then dividing them into aims, questions, hypotheses, techniques and random things to remember. Once that was done, I moved back to the linear outline view, and tidied things up, fleshing out the outline a bit as I went. It was really effective, and almost fun2! While Tinderbox can export notes quite easily as text (or HTML or XML), I probably won't bother to do so in this case, because I was just using it as a tool for thinking rather than writing. I've started to write the final document with the Tinderbox outline view open to guide my writing, and it's working really well.
1 I even constructed, managed and wrote this weblog with it when I first started blogging. ↑
2 Something which can make grant writing even almost fun is a miraculous tool, in my opinion. ↑



