Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: August 2009

Dan Podsedly

New Pivotal Tracker feature: Points Breakdown Chart

Dan Podsedly
Sunday, August 23, 2009

We’ve added a new report feature to Pivotal Tracker, to help you analyze how smoothly your project is progressing. It’s based on this popular idea, shared in our Get Satisfaction powered support community.

points breakdown

These new Points Breakdown charts help you visualize the progress of your project as stories move through different stages of completion. Stories start out as “Unstarted”, then move on to “Started”, “Finished”, “Delivered”, and then “Accepted” (unless they get rejected). The different colored bars show the point totals of the stories that are in each state at the end of each day. As days pass, you would expect the number of unstarted to go down, and the number of accepted to go up. If any of the other groups are especially big, the chart may help you identify bottlenecks in your workflow.

This breakdown is available for both the current iteration and the previous one. You can also use it to visualize the development of your entire project for the last 15, 30, or 60 days.

To access the Points Breakdown charts, click the Reports link on top of the page, or navigate from your project via the Reports option in the View menu.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

Rake, Set, Match!

Adam Milligan
Sunday, August 23, 2009

A few days ago I finally discovered why rake db:migrate:redo consistently angers me nearly as much as watching Paula Dean deep fry the vegetable kingdom. As any devoted connoisseur of the db rake tasks in Rails knows, db:migrate:redo always leaves your schema.rb file in the wrong state. The reason, as mentioned in our standup blog, is that rake will only invoke a given task once in a particular run.

To trivially test this try running a single task twice:

rake db:rollback db:rollback

You’ll find that your database only rolls back one migration. Now, you can set the STEP environment variable when calling db:rollback, but this is, as I said, a trivial example. It gets worse.

Take a look at the implementation of the db:migrate:redo task. The part we’re interested in looks like this:

namespace :migrate do
  task :redo => :environment do
    ...
    Rake::Task["db:rollback"].invoke
    Rake::Task["db:migrate"].invoke
  end
end

That looks fine; db:migrate:redo just verifies that your new migration will properly run down and up without blowing up. Sweet.

But, here’s what db:migrate looks like:

  task :migrate => :environment do
    # Do migratey stuff
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end

And rollback:

  task :rollback => :environment do
    # Do rollbacky stuff
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end

Both db:migrate and db:rollback dump the schema after they run, as they should. If you were to migrate or rollback your database and not dump the schema, then your schema would be in an invalid state. So, of course you can see where this is going, when you run db:migrate:redo the task performs the rollback, dumps the schema, performs the migrate, and then doesn’t dump the schema, because that task has already run. Boom, your schema is one migration behind, db:test:prepare loads the invalid schema into your test database, and all your tests fail (or, worse, pass inappropriately)

Now, I assumed this was a bug in Rake, and so I went on a little investigatory safari through the jungles of the Rake code to find it and kill it. I found the culprit, but invoking each task at most one time is, somewhat surprisingly, the expected behavior; it’s tested and everything. Now I can only wonder why. Why prevent invocation of a task more than once in a given rake run? The code contains unrelated guards against circular task dependencies, so that’s not it. Is this an example of overly-speculative defensive coding, or is there an actual use case for which this behavior is desirable? I’d like to hear from anyone who has written tasks that depend on this behavior, as well as anyone who (like me) considers this behavior unexpected and has run into problems because of it.

Assuming no one steps forward with a compelling reason that Rake should behave this way, I’d suggest that this be changed. I could see the value of it (perhaps as a performance optimization?) if rake tasks were guaranteed to not change the state of anything they operate on, or even were guaranteed to be idempotent; but neither is the case. This behavior severely limits the composability of tasks, since a task writer has to know which atomic tasks have run, and avoid any task that might try to run them again.

In the meantime, Rake provides a way to explicitly re-enable tasks that have run once, but it doesn’t seem to work. The db:schema:dump definition looks like this:

namespace :schema do
  task :dump => :environment do
    # Do dumpy stuff
    Rake::Task["db:schema:dump"].reenable
  end
end

That #reenable call is meant to tell the task “hey, task, you can run again.” I tried calling #reenable on the db:schema:dump task inside the db:migrate and db:rollback tasks as well, but without any luck.

Fellow Pivot David Stevenson would likely put it this way: Khaaaaaaaaaaaaaaann!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Joe Moore

Testing Desert Plugins in Isolation

Joe Moore
Saturday, August 22, 2009

At Pivotal, some of our client projects use plugins from our home-grown social networking platform and rely on Desert to tie them all together. To test this package of plugins we created a project that contains all of our Desert plugins and wrote some rake tasks that run all of their tests. Great, right?

Mostly. We want to ensure that our plugins have the absolute minimum dependencies to function. Let’s pretend we have an UserAuth plugin and a SocialPivots plugin, where UserAuth has no dependencies, but SocialPivots depends on UserAuth. We would like to test these the to plugins in isolation. But, with Desert doing it’s job so well, our UserAuth plugin could have a dependency on the SocialPivots plugins’ models or tables and we would never know it. Everything from SocialPivots is mixed-in and loaded into memory, and all of its migrations have executed, at the time we are running UserAuth’s tests.

What we need is a way to tell Desert to load only the plugin under test, plus its dependencies listed in init.rb. Hacking Desert and Rails to allow us to specify which plugins to load turned out to be pretty easy. Check it out (full gist here):

Here, we override plugin loading:

# lib/plugin_dependency_limiter.rb
class Rails::Initializer
  def load_plugins
    # Only load the plugin under test
    Rails::Plugin.new("vendor/plugins/#{ENV['PLUGIN']}").load(self)
  end

  def add_plugin_load_paths
    # Do nothing.  We'll handle plugin loading ourselves.
  end
end

We might have many plugins in vendor/plugins but we only want to test our Desert plugins. We list them in config/plugins/plugins_to_test.yml and keep track of them here:

# also in lib/plugin_dependency_limiter.rb
class Rails::Plugin
  def self.plugins_of_interest
    # Keep track of the Desert plugins we care about
    @of_interest ||= YAML.load_file(RAILS_ROOT + "/config/plugins/plugins_to_test.yml").collect
  end

  def self.tracked_plugins
    @tracked_plugins ||= []
  end

  def require_plugin_with_plugin_tracking(plugin_name)
    self.class.tracked_plugins << plugin_name if self.class.plugins_of_interest.include?(plugin_name)
    require_plugin_without_plugin_tracking(plugin_name)
  end
  alias_method_chain :require_plugin, :plugin_tracking
end

Once you can control which plugins are loaded you can expand this to dictate which routes and migrations should be run:

Routes:

# config/routes.rb
ActionController::Routing::Routes.draw do |map|
  if ENV['PLUGIN']
    Rails::Plugin.tracked_plugins.each do |plugin|
      map.routes_from_plugin(plugin)
    end
    map.routes_from_plugin(ENV['PLUGIN'])
  end
end

Migrations:

# db/migration/001_migrate_desert_plugins.rb
class MigrateDesertPlugins < ActiveRecord::Migration
  def self.up
    Rails::Plugin.tracked_plugins.each do |plugin|
      migrate_plugin(plugin, nil)
    end
    migrate_plugin(ENV['PLUGIN'], nil)
  end

  def self.down
    raise ActiveRecord::IrreversibleMigration
  end
end

Let’s run some tests! Though we don’t provide the rake task here, it runs db:drop db:create db:migrate db:test:prepare before running the plugin tests.

First, the UserAuth plugin that has no dependencies:

$ rake testspec:plugins PLUGIN=user_auth
(in /Users/pivotal/workspace/desert_plugins)
==  MigrateDesertPlugins: migrating ===========================================
==  CreateUserAuthStuff: migrating ====================================================
-- create_table(:user_auth_stuff)
   -> 0.0023s
==  CreateUserAuthStuff: migrated (0.0026s) ===========================================

==  MigrateDesertPlugins: migrated (0.0076s) ==================================

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I"lib:test" "/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
....................................

Finished in 0.494227 seconds

36 examples, 0 failures

Now the SocialPivots Plugin, which relies on UserAuth:

$ rake testspec:plugins PLUGIN=social_pivots
(in /Users/pivotal/workspace/desert_plugins)
==  MigrateDesertPlugins: migrating ===========================================
# Look, the migrations from UserAuth!
# Look, the migrations from UserAuth!
# Look, the migrations from UserAuth!
==  CreateUserAuthStuff: migrating ====================================================
-- create_table(:user_auth_stuff)
   -> 0.0201s
==  CreateUserAuthStuff: migrated (0.0204s) ===========================================

==  CreateSocialPivotStuff: migrating ==============================================
-- create_table(:social_pivot_stuff)
   -> 0.0034s
==  CreateSocialPivotStuff: migrated (0.0036s) =====================================

==  MigrateDesertPlugins: migrated (0.0332s) ==================================

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I"lib:test" "/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
........................................................................

Finished in 1.381141 seconds

72 examples, 0 failures

I hope this code makes testing Desert plugins easier. Thanks to Pivots Adam and Edward for pairing with me through these solutions.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Standup 8/17: RubyMine rebase issues and Ruby truthiness

Pivotal Labs
Friday, August 21, 2009

Interesting Things

Truthiness

You can’t make something “falsy” in ruby. For example, let’s say you are a good Fowlerite and you are implementing a nil object pattern like so:

class User; end

class NilUser
  def nil?() true end
end

user = NilUser.new

if user
  puts "Access Approved"
else
  puts "Access Denied"
end

If you run that code, even though you’ve defined .nil? to be true, it will print “Access Approved”. Ruby if/unless/else only recognize nil and false to be “falsey”.

RubyMine rebase strangeness

When you rebase from the command line and get a merge error, then run the merge tool from RubyMine, the “Your changes” and “Their changes” will be the reverse of what you might think. If you are accustomed to clicking “accept theirs” to mean taking other people’s changes, you’ll be in for a surprise.

If you botch the git rebase, you can always go back with this awesome git command, brought to you by Peter Jaros:

git reset --hard "master@{ 1 }"
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Will Read

Standup 8/21/2009: "Not Missing Constant" and "Rake Set Theory"

Will Read
Friday, August 21, 2009

Interesting Things

  • “… not missing constant” ERROR To reproduce this error you do something like this:

Generate a rails app, call it “test”.

Create a module scoped model called Post in app/models/mumble/post.rb

class Mumble::Comment < ActiveRecord::Base
  belongs_to :post
end

Create a module scoped model called Comment in app/models/mumble/comment.rb

class Mumble::Comment < ActiveRecord::Base
  belongs_to :post
end

Then at the command line

$ script/console
Loading development environment (Rails 2.3.3)

comment = Mumble::Comment.first
=> #
comment.post
=> #
exit
$ script/console
Loading development environment (Rails 2.3.3)
post = Mumble::Post.new
=> #
exit
$ script/console
Loading development environment (Rails 2.3.3)
post = Mumble::Post.create!
=> #
comment = post.comments.create!
=> #
comment.post
ArgumentError: Mumble is not missing constant Post!
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.3.3/lib/active_support/dependencies.rb:417:in load_missing_constant'
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.3.3/lib/active_support/dependencies.rb:80:in
const_missing’

Apparently, there are various situations that can cause the infamous “Mumble is not missing constant Post!” error. In this case it appears the associations do not understand the module scoping, despite the statement:

By default, associations will look for objects within the current module scope.

at http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

The solution was to explicitly declare the class name in the association:

class Mumble::Post < ActiveRecord::Base
  has_many :comments, :class_name => "Mumble::Comment"
end

and

class Mumble::Comment < ActiveRecord::Base
  belongs_to :post, :class_name => "Mumble::Post"
end

Then to show the error is no longer present

$ script/console
Loading development environment (Rails 2.3.3)

post = Mumble::Post.create!
=> #
comment = post.comments.create!
=> #
comment.post
=> #

  • “Rake Set Theory” when running the same thing in rake multiple times, Rake strips out the extra commands. For example:
    $rake db:rollback db:rollback
    which you might expect to preform two rollbacks, only does one rollback. This can be frustrating if you’re trying to couple rollbacks with a db:test:prepare or some other logical chain of events. At the command line you can of course work around most situations by && together multiple rake commands.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Mocking ScrewUnit with iSpy

Pivotal Labs
Wednesday, August 19, 2009

I was looking for a mocking framework to use with Screw.Unit when I found out that Rajan had ported the spying framework from Jasmine over. His project is called iSpy and we just started using it on my current project. It’s worked really well for us and I’d definitely recommend it.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Standup 8/19/09: Memcache mock and Paperclip gotcha

Pivotal Labs
Wednesday, August 19, 2009

Ask for Help

“Does anyone have experience with memcache mock?”

Some team members are experimenting with this, and were looking to connect with people who have experience with this.

Interesting Things

  • Paperclip gotcha. Paperclip expects 3 columns. And if you don’t do this database migration, it will just silently fail.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jonathan Berger

Pivotal Labs NY hosts the Agile Experience Design meetup

Jonathan Berger
Wednesday, August 19, 2009

On Tuesday night Pivotal Labs NY hosted the first “Agile Show & Tell”, organized by the Agile Experience Design Meetup. More after the fold…

The evening started off with Ben Woosley and myself giving a brief tour of the Pivotal Labs Agile practice, culminating with a discussion of how we integrate UX. Ben and I sketched out a quick talk earlier in the day and then converted it to html slides using the excellent Slidedown. When an early show-of-hands from the audience indicated that most of them weren’t familiar with Pivotal Tracker, we stopped our slides and dove right into Tracker, demonstrating the basics to a sea of mostly nodding heads. A conversation followed with a number of great questions, including discussions of automated design testing, integrating design velocity and development velocity, and the finer points of pair-programming. I’m looking forward to continuing this conversation as the Agile Experience Design meetup continues.

After the Pivotal presentation, a few group members came up and gave short talks. Lane Halley gave a brief overview of the upcoming Agile Alliance convention in Chicago. Lar Van Der Jagt gave a great demo explaining Test-Driven Development using Cucumber, a testing framework that lets users write in pretty-close-to-plain-English, which looks something like this:

Canonical Cucumber example from http://cukes.info

and Pickler, which synchronizes user stories between Pivotal Tracker and Cucumber via the command line.

Finally, Jeff Gothelf talked about the journey from waterfall to Agile and gave a great illustration of the use of wikified style guides to aid in the transition and streamline communication between developers and designers.

Thanks to the speakers, the attendees, the organizers, and especially the UX Workshop for livestreaming the whole event!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Standup 8/17/2009: Parallel-spec, Keycaster and more

Pivotal Labs
Monday, August 17, 2009

Ask for Help

“Does anyone have experience with the parallel_specs plugin?”

One team member has begun experimenting with the Parallel Specs plugin. This plugin allows your testing framework (RSPec, Test::Unit and Cucumber) to use any additional CPUs which your machine may have. Initial usage suggests that this dramatically reduces testing time.

“geminstaller.install breaks Passenger”

This references a help from Friday. geminstaller.install works fine when using Mongrel, but it breaks Passenger.

Interesting Things

  • Some team members have begun using KeyCastr while pairing. This app displays your keystrokes in a small floating window. It is especially useful if you use a lot of macros while coding.

  • Rails 2.3 & JSON. One team member noticed some gotchas with Rails 2.3 and JSON which seem to also be described here.

  • Rails 2.3 now lazy-loads sessions. This can be a problem, though, if you want to truly disable sessions on a site.

  • The Formtastic plugin has been getting great reviews from team members. It describes itself as “a Rails FormBuilder DSL (with some other goodies) to make it far easier to create beautiful, semantically rich, syntactically awesome, readily stylable and wonderfully accessible HTML forms in your Rails applications.”

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Colin Shield

Marshal.dump vs YAML::dump

Colin Shield
Sunday, August 16, 2009

We find ourselves with a project with a very large dataset, more than 2 million items. This dataset changes frequently. The changes need to be transported to their respective servers ready to be served out to clients.
We decided to use a queuing architecture to distribute data. Objects are serialized and pushed to a queue. The large size of the dataset requires us to optimize as much as possible. There are only so many hours in a day and there is a lot of data to transport.
A question was raised in standup as to what was the fastest serialization method: YAML::dump or Marshal.dump. It seemed appropriate to write a quick script and work out which would be appropriate for our particular situation.
The objects we are serializing are simple hashes. I thought I’d write something that was representative of our situation in order to present a nice clear decision.
Here’s some code:

require 'yaml'
obj = {:a => "hello", :b => "goodbye", :c => "new string", :d => {:da => 1, :db => 2}, :e => 1}
start = Time.now
(0..10000).each do
  ser_obj = YAML::dump(obj)
  new_obj = YAML::load(ser_obj)
end
puts "YAML::dump time"
puts Time.now - start
start = Time.now
(0..10000).each do
  ser_obj = Marshal.dump(obj)
  new_obj = Marshal.load(ser_obj)
end
puts "Marshal.dump time"
p Time.now - start

I think we all knew how the results would look. It was nice to see that for our particular case there was a clear winner.

YAML::dump time
5.397909
Marshal.dump time
0.280292

Seems fairly cut and dried to me.
I personally prefer YAML for test result comparison. Maybe we’ll put something in our spec_helper to use YAML for testing and Marshal for production.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (780)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (20)
  • cucumber (20)
  • jasmine (19)
  • design (18)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • tracker ecosystem (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to Community Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >