This week we moved our gems over to GemCutter. It's very easy to claim the gems that were automatically synced over from RubyForge, but if you have gems on GitHub it takes a little more work. We had several gems to move over, some of which had quite a few versions we wanted to preserve. You can't just push the .gem files over because GitHub built the gem namespaced with your username (e.g. "pivotal-apdex"). So Sam and I built a little script to pull down the gems from gems.github.com, fix the name in the spec, repack, and push up to GemCutter.
You can get the hubcut script at http://gist.github.com/220908
I was introduced to the world of Ruby in general (and Ruby on Rails specifically) almost 2 years ago. Prior to that my professional programming experience consisted mostly of PHP, with a little bit of Java and ASP thrown in for good measure.
Then came that almost magical day when I was hired to a new job and instructed that I needed to learn Ruby on Rails.
"Ok, I can do that."
I absolutely fell in love with the language and the framework, and that experience put me on the path that led here to Pivotal Labs. But I know that I still have a lot to learn, so am still picking up things that in some ways I feel stupid for not having picked up earlier.
One such thing is RailsConf. I had heard of it before, but not in any kind of context that I really appreciated it or understood what that was (I'm getting a better idea now after some research).
Now I really want to get involved and submit a proposal for a talk/presentation at RailsConf. I just have no idea what to do it on or where to start....
Ask for Help
"How does a Rails newbie know where to find out about the best gems and plugins?"
Interesting Things
One Pivot had frequent timeouts to S3 when using Ubuntu and a Linksys router. After some research it was discovered to be a TCP window scaling issue
Ubuntu 9.10 has been released
Interesting Things
- Josh Susser announced Refraction, a Rack replacement for
mod_rewrite. It's available on GitHub.
I recently released a new version of ActiveHash which adds a number of features that make it even easier to use Hash or Yaml data stores for ActiveRecord-esque models. The recent updates include:
- Setters
- belongs_to and has_many associations
- save, create and destroy methods that add or remove the objects from the in-memory collection (great for object mother libraries like Fixjour)
- support for string ids
- support for hash-style yaml data (think Rails fixtures)
- auto-incrementing ids by default (again, for Rails fixtures)
If you have earlier versions of ActiveHash I highly recommend that you upgrade. It makes testing and common uses much nicer. If you are on gemcutter, it's as simple as:
gem install active_hash
Enjoy!
Ask for Help
"How do I stop bit.ly from adding trailing slashes to my URLs?"
If you have a url of the form http://maps.google.com?q=37.7,+-122.4 then bit.ly will normalize it by adding a trailing slash: http://maps.google.com?q=37.7,+-122.4/. However, the work around is to instead correctly insert the slash yourself: http://maps.google.com/?q=37.7,+-122.4
"Mongrel is raising undefined constant exceptions. How do we stop this or workaround it?"
A non-threaded Rails 2.1 application using Pivotal Labs' Desert Plugin gets occasional NameError exceptions about undefined constants that should have been loaded by Rails / Desert. The application preloads all dependencies and the errors don't occur until there is a request; it's not the same NameError every time.
No one had seen this behavior and so the main suggestion was to upgrade Rails. A work around to make monit reload the Mongrel process is to have Mongrel exit on NameError exceptions by calling Process.exit in a rescue_from block.
Interesting Things
One of the things I've always liked least about building web applications is dealing with mod_rewrite. It's a very useful feature, but it's quirky and the config languages for webservers are difficult to use (at least from my experience with Apache and Nginx). But like it or not, mod_rewrite is often a necessary part of a web app. Until now...
Recently I had to redo the rewrite rules for pivotallabs.com when we switched from Apache to Nginx, which we did when moving to EngineYard's cloud hosting. Since then our Nginx config has grown to over 150 lines, mainly to deal with multiple virtual hosts.
Now, managing a custom Nginx config on the EY cloud system isn't as simple as I'd like, especially when the configs are different on production and demo environments. (Demo is what we call our usual environment for doing feature acceptance.) It's far easier to use the automatically generated config, but that doesn't work when you need to support multiple domain names.
The obvious thing to do was to move the rewrite/redirect logic out of the Nginx config. I found a couple Rack middleware components that did something sort of like what we needed, but none of them were sufficient for what we needed. So we created our own.
Refraction is a Rack middleware replacement for mod_rewrite. With Refraction we were able to replace our 150+ line Nginx config with a 50 line Ruby file, and go back to using the standard automatically generated config on EY cloud.
Here's an example Refraction config file:
Refraction.configure do |req|
feedburner = "http://feeds.pivotallabs.com/pivotallabs"
if req.env['HTTP_USER_AGENT'] !~ /FeedBurner|FeedValidator/ && req.host =~ /pivotallabs.com/
case req.path
when %r{^/(talks|blabs|blog).(atom|rss)$} ; req.found! "#{feedburner}/#{$1}.#{$2}"
when %r{^/users/(chris|edward)/blog.(atom|rss)$} ; req.found! "#{feedburner}/#{$1}.#{$2}"
end
else
case req.host
when 'tweed.pivotallabs.com'
req.rewrite! "http://pivotallabs.com/tweed#{req.path}"
when /([-\w]+.)?pivotallabs.com/
# passthrough with no change
else # wildcard domains (e.g. pivotalabs.com)
req.permanent! :host => "pivotallabs.com"
end
end
end
These rules are extracted from the full config file for pivotallabs.com. They redirect high-traffic syndication feeds to feedburner, rewrite a subdomain (tweed.pivotallabs.com) to a path for that sub-site (pivotallabs.com/tweed), and redirect some aliases to our standard domain name (pivotalabs anyone?).
Refraction is thread-safe, which means you can put it outside the Rack::Lock, something we felt was important for performance. It will never have the performance of mod_rewrite, but it will certainly be better than handling redirections in Rails itself.
Full documentation is available in the README. Contributions welcome.
And of course big thanks to Sam Pierson and Wai Lun Mang who both paired with me on developing Refraction.
I just got the chance to listen to this interview with Arlo Belshee about Naked Planning ("Kanban Simplified"):
http://cdn2.libsyn.com/agiletoolkit/Agile2008_Arlo_Belshee.mp3
Highly recommended. My summary of Naked Planning:
- Teams work toward delivering Minimum Marketable Features - usually chunkier than User Stories but more relevant to customers. Think "administrator can set user permissions" vs what you might break that down to in terms of finer-grained stories.
- The dev team breaks MMFs into tasks as appropriate.
- Teams work on MMFs in a ratio of about one MMF to every two pairs.
- There is no estimation (it's usually wrong, there's no particular reason why the time before you start a story - when you know very little - ought to be when you assess cost). Instead a pure yesterday's weather approach is taken: you write down the date you start the MMF, and the date you finish it, and keep a rolling average days to complete an MMF - that becomes your "velocity" (no need for that word though).
- "Done" means everyone - customers, developers - determine that the MMF is done. That means development is finished, any follow-on discovery or bug fixing is done, support staff are trained up, and the feature is really ready to go out into the world and be used by users and create value.
- The MMF backlog is somewhere between 5 and 9, because beyond that prioritization (remember, we're talking about something chunkier than a User Story) is mostly useless. If it takes, say, 15 days to finish an MMF, on a two pair team with a 7 MMF backlog, you're out about 6 weeks - this is when any backlog typically starts to degrade a bit. At the outside you're planning for an entire quarter.
- One slot, that you try to keep empty, is reserved for fires. The customer can put in a fire card that the team immediately works on. You can only work on one fire at a time - others go into the backlog with the MMFs.
This is a sort of Lean/XP/Kanban fusion that Arlo created and refined on a project he heads up. It drops some of the weirder parts of XP-style planning and distills down to its more interesting ideas, and addresses many of the beefs I have with point estimates, velocity, and iterations in practice. At the very least it's food for thought.
And here's a video in which Arlo explains the planning board.
Interesting
- A lot of us have been seeing significant slowdown and memory problems with RubyMine lately. One of the Pivots brought this up again today, and remarked that RubyMine performed much better after he removed/detached a bunch of gems and only added back in the ones he was concerned about ever having to go into again.
- Still in the vein of RubyMine, my Pair and I at one point set the memory allocation for RubyMine higher than the initial settings a weeks or so ago. I got to talking with a few of the Pivots about RubyMine and its memory settings and they said this is actually what you do NOT want to do. Apparently if RubyMine has too much memory available, then it doesn't garbage collect anywhere near as often as it probably should.
Helps
- In an Rspec test file, integrate_views is set up to be active by default. However, we want to run a particular describe block in the file in isolation mode. We tried using 'integrate_views( false )' right after the describe header, but that didn't seem to do anything like what was expected. Just calling 'integrate_views' when the default is Isolation mode runs a describe block in Integration mode, but is there a way to do the opposite?
Helps/Interesting
- It was brought up that Snow Leopard has finally, completely, disabled the ability to re-enable the "Awesome" extra functionality of the Screen Sharing app. Once you upgrade to Snow Leopard, you'll have to pay for Remote Desktop to get that awesomeness.
