Interesting Things
- Rails controller filters can also be objects
- Any object with a before, after or filter method can be a filter
- Will Read attempts the Matrix knot

Help
"How do you permanently remove a git tag?"
- One team would like a delete a tag created by their CI, but it keeps coming back if somebody who has pulled the tag locally does a push.
Let's say you are building a leetspeak that deals with w00ts. You might write a class that looks like this:
class Woot
def ==(other)
true
end
end
In theory, any Woot is equal to anything else:
puts Woot.new == Woot.new # true
You might think that with this setup, you could do something like this:
x = [ Woot.new ] y = [ Woot.new ] z = x - y
You might expect z to be an empty array in the case, but oh how wrong you would be. In the example above, the == is never called at all.
JQuery Events/live + ScrewUnit = :-(. ScrewUnit swaps the DOM "out from under" the elements that Events/live is watching, which messes with ScrewUnit. Call
dieon the DOM elements that live events are watching.ScrewUnit + CI + IE = :'-( Also, When ScrewUnit suites become large, they trigger IE's "slow script" warning, which can freeze your continuous integration build. Check out the Registry Hack to set your own timeout.
We have a fan of Thor in the house: "Map options to a class. Simply create a class with the appropriate annotations, and have options automatically map to functions and parameters." Which, as is (not) obvious, indicates that Thor is a replacement for rake.
Theo Schlossnagle: "I don't care what you use: puppet, chef, bcfg2, cfengine - choose one and automate your configuration." (Theo's presentation was a highlight, check out the slides here.)
Allspaw and Hammond from Flickr: "If there's only one thing you do, automate your infrastructure."
There were lots of Puppet users at the conference, and Luke Kaines gave a good talk on it.
Interested in a Chef intro? Watch the video of Adam and Ezra's talk:
From the Chef BoF:
- If you're just doing application deployment of a typical webapp then running chef-solo on deploy might be just fine for you (it is for the Remix team).
- Ezra points out that he has a chef subproject on git that even strips out cap - chef-deploy (vs cap sudo'ing out to chef).
- Adam gave a good explanation of the Chef run model.
- It's important to understand the basics of what's going on behind the scenes - otherwise you'll shell out right in the middle of your Chef scripts and be surprised by the run order.
- In short, all your Chef Resource statements are evaluated in a first pass. Then they're executed.
- This gives Chef the opportunity to evaluate what's to be done and optimize. Adam noted that included recipes are only executed once (analogous to ruby require's)
- Adam also mentioned something kind of cool - if I have this right - Resource statements return the associated Resource object. And when you refer to the Resource the same way twice, you're getting back the same Resource instance. So your included Recipes (for example) each have the opportunity to decorate a Resource defined earlier - if, say, it ought to be configured differently based on a combination of what else is getting installed on the box. Nice.
My favorite talk at Velocity was by Paul Hammond and John Allspaw from Flickr, who are doing real lowercase-a agile:
UPDATE
Here's the video, highly recommended:
"If there's one thing you do, it should be automated infrastructure". This was a refrain through the conference - as Theo Schlossnagle put it, it doesn't matter if it's chef, puppet, bcfg2, cfengine - whatever works for you, just do it.
Some of their techniques:
- One-step build. They literally go to a web page and click a button and watch the build take the full site from soup to nuts.
- Deploys: Who. What. When. You want to make all the meta-details of a deploy easily visible to anyone. Deploy logs are readily accessible.
- Always ship trunk. In a webapp this is possible. It vastly simplifies - everyone knows where to look for what's going out, and what's live.
- Flickr does their branching in the code (take note git people), and these become natural ops levers (i.e. uh-oh turn that feature off / turn it down).
- "Dark launches". Facebook does this too: launch the guts of a new feature with the UI turned off so you can see how the technology works in real production.
- Which results in anticlimactic launches, the best kind
- They roll forward (not back) to turn features off that aren't working.
- "Gather shitloads of metrics". System metrics, app metrics, everything. John has a great writeup on their Ganglia setup in his book.
- Developers watch the metrics just as obsessively as ops. Visualization is a powerful tool used day-to-day by the whole group.
- Developers have a way of putting in their own metrics via a little framework.
- They're all on IRC. This kept coming up at the conference - teams are on some chat tool like IRC, Skype chat LINK, or Campfire LINK.
- Important events are piped into IRC, so you'll be right in the middle of a conversation and an alert will pop in.
- Logs are piped into a search engine so they can find things in the log history, easily.
Culture, philosophy:
- There's an ongoing conversation between dev and ops. They're learning to solve the Flickr problem together. Each side's way of thinking informs the other (major conference theme as well)
- Failure will happen. Develop your ability to respond. Like ER doctors you practice on failures, that makes you better/competent at handling what comes along next.
- In addition to the ops people on call, there's always a developer who has a pager
More:
Interesting Things
You can never return: ... except when you can. From a block, that is. Returning from a block rarely works:
result = ['one', 'two'].each do |x| return x end => LocalJumpError: unexpected returnBut, you can pass
nextandbreakarguments, which will allow you to assign return values from the block:result = ['one', 'two'].each do |x| break(x) end => "one" result = ['one', 'two'].each do |x| next(x) end => ["one", "two"]
You can return from a lambda, though.
Check out Google Page Speed, which is like Yahoo's YSlow, only "better."
Page Speed is an open-source Firefox/Firebug Add-on. Webmasters and web developers can use Page Speed to evaluate the performance of their web pages and to get suggestions on how to improve them.
Like chef? Love capistrano? Check out chef-deploy, which "... Uses the same directory layout as capistrano and steals the git remote cached deploy strategy from cap and adapts it to work without cap and under chef."
SFTUG FTW! Another successful SF Tracker User Group Meetup on 06/24. Watch for future events on the Meetup site.
The project I'm working on has a lot of named scopes which are really great. If you're not using them already you should really try them out. Since we test drive everything we do, we needed a really easy way to write tests for all these named scopes. We came up with a little test helper method that I thought I'd share so that other people could use it.
Here's the code:
def test_named_scope(all_objects, subset, condition)
subset.should_not be_empty
subset.each do |obj|
condition.call(obj).should be_true
end
other_objects = all_objects - subset
other_objects.should_not be_empty
other_objects.each do |obj|
condition.call(obj).should be_false
end
end
To use it, just pass a superset of objects, the subset you want to test and then a lambda as a condition. The lambda should be true for all items in the subset and false for all the items outside of it.
It sounds complicated but it's really easy! Here's an example Let's look at a simple tag class that has a status column indicating whether the tag is on a whitelist or a blacklist. It could look like this.
class Tag < ActiveRecord::Base
WHITELISTED = 1
BLACKLISTED = 0
end
We want to be able to easily grab all the whitelisted tags, so we need to add a named scope.
Here's the spec we write first:
describe Tag do
describe "whitelisted named_scope" do
it "returns the whitelisted tags" do
test_named_scope(Tag.all, Tag.whitelisted, lambda{|tag|
tag.status == Tag::WHITELISTED })
end
end
end
end
We run the spec, watch it fail and then go add the named scope to our Tag class.
class Tag < ActiveRecord::Base
WHITELISTED = 1
BLACKLISTED = 0
named_scope :whitelisted, :conditions => {:status => WHITELISTED}
end
Then we just rerun the spec and watch it pass. Easy!
Update2: Josh Susser emailed me a really nice refactoring with the enumerable partition method and Kelly fixed a bug I introduced.
def test_named_scope(all_objects, subset, condition)
scoped_objects, other_objects = all_objects.partition(&condition)
scoped_objects.should_not be_empty
other_objects.should_not be_empty
scoped_objects.should == subset
other_objects.should == all_objects - subset
end
Ask for Help
"Does anyone have Nginx URL rewriting fu?"
The pretty documentation is actually quite hard to work with. Does anyone else have a good reference?
Interesting Things
- Pivotal in the New York Times: Regarding Palm Pre development and our own Tweed:
Some developers who were granted early access to Palm's new operating system said it was worth the wait. "We find it's the easiest one to develop for," said Christian Sepulveda, vice president for business development at Pivotal Labs. "It allows for a richer experience, like having a pop-up menu and background processing, which is helpful."
Mr. Sepulveda's company developed four of the first programs available for download through Palm’s app store, including an item for Twitter called Tweed.
- The next SF Ruby Meetup will be held here at Pivotal Labs. Sign up) and attend!
- BART strike warning! In the Bay Area we take our commute options seriously. Here are your options if BART goes on strike
Ask for Help
"Has anyone implemented mutli-table (class table) inheritance in Rails, as apposed to single table inheritance (STI)?"
- There are some plugins that nobody has tried, such as inherits_from
- What about a view to represent the super set of tables and rows?
"We're looking for a dead-simple, drop-in JS rating or 'starting' plugin."
Check out the start-rating jQuery plugin. Any other suggestions?
Interesting Things
- RubyMine 1.1 + Latest Mac OS X Java Upgrade + configuring RubyMine to work with Java 1.6 = Complex FAIL. We downgraded to RubyMine 1.0.5 and it works again.
