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
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: August 2011

Glenn Jahnke

Standup 8/31/2011 – RubyMine and Compostable Utensils!

Glenn Jahnke
Wednesday, August 31, 2011

Ask for Help

“Does anyone know about random highlighting occurring in RubyMine / IntelliJ on all OSes?”

RubyMine 3.1 apparently had issues with random highlighting which were resolved simply by upgrading to at least 3.2 release.

Interesting Things

Compostable Utensils

The office got compostable utensils that meet San Francisco city requirements!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Phil Goodwin

Standup 8/30/2011 Cruisin’ for trouble

Phil Goodwin
Tuesday, August 30, 2011

Helps

*Why is Cruise Control green when my tests are failing?

Probably because the rake task running the tests returns zero. Cruise Control relies on the exit code of the processes it runs to determine whether to report success or failure. This seems like a common Cruise Control pitfall. It’s good practice to run a failing test through Cruise Control during initial set up in order to avoid this problem

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Danny Burkes

Ruby + Salesforce = Happy Developers

Danny Burkes
Monday, August 29, 2011

Pivotal is proud to announce the release of the databasedotcom gem. Developed in partnership with Heroku and Salesforce, this gem wraps the Force.com REST API in familiar Ruby idioms, making it a snap to create web applications that integrate with your existing Salesforce instance, or even straight Ruby apps that do offline analysis of your Salesforce data.

I will be giving a session at Dreamforce on Tuesday, August 30, introducing the gem and demonstrating how easy it is to integrate into a Rails application. The session is entitled Building and Deploying Great Applications with Salesforce, Ruby, and Heroku, and takes place in Moscone West Room 2008 from 5:00 pm – 6:00 pm.

Source code from the session will be available soon, as will the session slides.

Hope to see you there!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Dan Podsedly

Pivotal Tracker is at Dreamforce this week

Dan Podsedly
Monday, August 29, 2011

Pivotal Labs is a DevZone partner at Dreamforce, and we’ll be there to talk agile and Pivotal Tracker. If you’re attending the conference, come to the DevZone in the Cloud Expo and say hi. We’ll be doing demos, showing upcoming features (including Epics), and entering visitors into a daily prize drawing.

I’ll also be doing a 30 minute talk on agile development and Tracker in the Lightning Theater. It’s this Wednesday at 6pm, in the DevZone. Stop by!

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

Cross joins for fun and profit

Pivotal Labs
Monday, August 29, 2011

In my experience cross joins aren’t very common, but very powerful and performant when used correctly. In this post I’ll describe one example of where cross joins, also known as cartesian joins, can improve performance of your
app while also improving maintainability.

Imagine that you just landed a contract with the Department of Education. They want you to build an app that
will track which singers can sing on which songs for performances in Glee clubs nationwide. The project manager, Will Schuester, tells you:

  • Sometimes everyone sings on a song
  • Sometimes a song has restrictions (i.e. only boys can sing on “it’s my life”)
  • Sometimes everyone sings except for one or two singers (i.e. everyone can sing on “don’t stop believing” except rachel)
  • This will be a nationwide platform, with millions of Glee club members tracked

You know you’ll track Singers and Songs, so create those and add some data:

Singers

create table singers (id serial, name varchar(20));

insert into singers (name) values ('finn'), ('rachel'), ('mercedes');

select * from singers;
+----+----------+
| id | name     |
+----+----------+
|  1 | finn     |
|  2 | rachel   |
|  3 | mercedes |
+----+----------+

Songs

create table songs (id serial, name varchar(255), has_restrictions boolean);

insert into songs (name, limited) values ('it's my life', true), ('don't stop believing', false), ('loser like me', false);

select * from songs;
+----+----------------------+------------------+
| id | name                 | has_restrictions |
+----+----------------------+------------------+
|  1 | it's my life         |                1 |
|  2 | don't stop believing |                0 |
|  3 | loser like me        |                0 |
+----+----------------------+------------------+

Now you have to figure out how to store which user sings on which song. Here are two possible solutions:

Solution 1: Store each Singer / Song combination in a table

You might start with a structure like this:

create table song_performers( id serial, singer_id int(11), song_id int(11) );
CREATE UNIQUE INDEX index_song_performers ON song_performers (singer_id, song_id);

The idea here is that you insert one row singer per song that they can sing on. This is a simple solution that might work well for your app, but it has a few downsides. For example, when a singer is added to the Glee club, something will have to insert that singer into every song that they can sing on. That table might also grow to be millions of rows long very quickly, and require archiving as time goes on.

Solution 2: Store rules about which singer can sing in which songs

You can get the same result as above by using a table list just the rules about who can sing in which songs, and using a cross join and some conditions to limit the result set.
Here’s what the tables might look like:

create table performer_rules( id serial, singer_id int(11), song_id int(11), rule_type varchar(20) );
create unique index index_performer_rules on performer_rules (singer_id, song_id);
insert into performer_rules (singer_id, song_id, rule_type) values (1, 1, 'included');
insert into performer_rules (singer_id, song_id, rule_type) values (2, 2, 'excluded');

Notice the unique index singer_id and song_id – that’s a crucial step for the queries below to return the correct data without having to use distinct.

To ensure the query is returning the correct results, add some data that might throw the results off. In this case, it should
suffice to exclude Mercedes from “it’s my life” (she should already be excluded), and include her in “loser like me” (she should already be included):

insert into performer_rules (singer_id, song_id, rule_type) values (3, 1, 'excluded');
insert into performer_rules (singer_id, song_id, rule_type) values (3, 2, 'included');

select songs.name as song_name, singers.name as singer_name, has_restrictions, rule_type
from performer_rules
inner join songs on performer_rules.song_id = songs.id
inner join singers on performer_rules.singer_id = singers.id
order by songs.name, singers.name;

+----------------------+-------------+------------------+-----------+
| song_name            | singer_name | has_restrictions | rule_type |
+----------------------+-------------+------------------+-----------+
| don't stop believing | mercedes    |                0 | included  |
| don't stop believing | rachel      |                0 | excluded  |
| it's my life         | finn        |                1 | included  |
| it's my life         | mercedes    |                1 | excluded  |
+----------------------+-------------+------------------+-----------+

Now that table of rules is there, you can get the correct result set with the following query:

select songs.name as song_name, singers.name as singer_name
from singers
cross join songs
left join performer_rules on performer_rules.singer_id = singers.id and performer_rules.song_id = songs.id
where (songs.has_restrictions = false and rule_type is null) or rule_type = 'included'
order by songs.name, singers.name;

+----------------------+-------------+
| song_name            | singer_name |
+----------------------+-------------+
| don't stop believing | finn        |
| don't stop believing | mercedes    |
| it's my life         | finn        |
| loser like me        | finn        |
| loser like me        | mercedes    |
| loser like me        | rachel      |
+----------------------+-------------+

Let’s break that down a bit. First, take a look at the result of the cross join: it contains a row for every singer
for every song.

select songs.name as song_name, singers.name as singer_name
from singers
cross join songs
order by song_name, singer_name;

+----------------------+-------------+
| song_name            | singer_name |
+----------------------+-------------+
| don't stop believing | finn        |
| don't stop believing | mercedes    |
| don't stop believing | rachel      |
| it's my life         | finn        |
| it's my life         | mercedes    |
| it's my life         | rachel      |
| loser like me        | finn        |
| loser like me        | mercedes    |
| loser like me        | rachel      |
+----------------------+-------------+

Next, add the performance_rules, matching on both the song and the singer:

select songs.name as song_name, singers.name as singer_name, has_restrictions, rule_type
from singers
cross join songs
left join performer_rules on performer_rules.singer_id = singers.id and performer_rules.song_id = songs.id
order by song_name, singer_name;

+----------------------+-------------+------------------+-----------+
| song_name            | singer_name | has_restrictions | rule_type |
+----------------------+-------------+------------------+-----------+
| don't stop believing | finn        |                0 | NULL      |
| don't stop believing | mercedes    |                0 | included  |
| don't stop believing | rachel      |                0 | excluded  |
| it's my life         | finn        |                1 | included  |
| it's my life         | mercedes    |                1 | excluded  |
| it's my life         | rachel      |                1 | NULL      |
| loser like me        | finn        |                0 | NULL      |
| loser like me        | mercedes    |                0 | NULL      |
| loser like me        | rachel      |                0 | NULL      |
+----------------------+-------------+------------------+-----------+

Notice how we still have every row of every singer and every song (because of the left join). We also see that we have
6 possible combinations of has_restrictions and rule_type. We can figure out whether they should be included with a simple logical statement:

(songs.has_restrictions = false and rule_type is null) or rule_type = 'included'

Here’s what that might look like as a select:

select songs.name as song_name, singers.name as singer_name, has_restrictions, rule_type, coalesce((songs.has_restrictions = false and rule_type is null) or rule_type = 'included', false) as 'include?'
from singers
cross join songs
left join performer_rules on performer_rules.singer_id = singers.id and performer_rules.song_id = songs.id
order by song_name, singer_name;

+----------------------+-------------+------------------+-----------+----------+
| song_name            | singer_name | has_restrictions | rule_type | include? |
+----------------------+-------------+------------------+-----------+----------+
| don't stop believing | finn        |                0 | NULL      |        1 |
| don't stop believing | mercedes    |                0 | included  |        1 |
| don't stop believing | rachel      |                0 | excluded  |        0 |
| it's my life         | finn        |                1 | included  |        1 |
| it's my life         | mercedes    |                1 | excluded  |        0 |
| it's my life         | rachel      |                1 | NULL      |        0 |
| loser like me        | finn        |                0 | NULL      |        1 |
| loser like me        | mercedes    |                0 | NULL      |        1 |
| loser like me        | rachel      |                0 | NULL      |        1 |
+----------------------+-------------+------------------+-----------+----------+

The final step is to add that logical statement to the where clause:

select songs.name as song_name, singers.name as singer_name
from singers
cross join songs
left join performer_rules on performer_rules.singer_id = singers.id and performer_rules.song_id = songs.id
where (songs.has_restrictions = false and rule_type is null) or rule_type = 'included'
order by song_name, singer_name;

+----------------------+-------------+
| song_name            | singer_name |
+----------------------+-------------+
| don't stop believing | finn        |
| don't stop believing | mercedes    |
| it's my life         | finn        |
| loser like me        | finn        |
| loser like me        | mercedes    |
| loser like me        | rachel      |
+----------------------+-------------+

Summary

This type of database structure works well for access lists and permissions apps, and in my experience these kinds of simple cross joins perform reasonably well as long as there are proper indexes on the tables, and the datasets are not too massive.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Dan Podsedly

New Pivotal Tracker Video: Introduction to the Concepts

Dan Podsedly
Monday, August 29, 2011

We’ve just published a new video that introduces the concepts behind Pivotal Tracker. It talks about the agile process that works best with Tracker, including story breakdown and estimation, prioritization, and workflow. If you’re new to Tracker, or would like to make sure you’re getting the most of out of the tool, this should be 8 minutes well spent!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mike Barinek

Jasmine Workshop 9/8 & 9/9

Mike Barinek
Monday, August 29, 2011

Cory Flanigan and Justin Searls are hosting a two day Jasmine workshop very soon in Denver on 9/8 & 9/9 at Uncubed. Details here: http://www.regonline.com/builder/site/Default.aspx?EventId=1004029

The event is non-profit. There’s a fee of $120, but it is intended to only cover costs. If proceeds manage to exceed our costs, they’ll be donated to charity.

Their objectives are to introduce people to Jasmine, pair on a basic kata, pair on spec’ing some behavior that would involve DOM interactions/jQuery, illustrate patterns for using spies on dependencies and callbacks (like AJAX), and also to spend time working through methods for rigging up Jasmine specs in CI.

In addition, they’re inviting everyone who attends to bring some of their own existing JavaScript (especially if it’s untested). As time permits on the second day they’d like to mob program on these real-world examples by characterizing legacy JavaScript code with Jasmine and then refactoring with our tests as a safety net.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ash Hogan

Fall College Career Fairs

Ash Hogan
Saturday, August 27, 2011

Pivotal is committed to developing careers with those who are still studying or have recently graduated from college. We offer paid intern and full time positions with consideration to your study program and relevant intern or coop experience.

In the Fall of 2011, Pivotal Labs will be attending 23 college job fairs in 49 days – an average of one careers fair every 2.13 days! If you want to share your knowledge while learning from others, work sustainably, and work on some serious projects, we think you’ll have a blast working with us. We encourage you to come along and visit us at the following locations:

University Illinois College Engineering; Colorado School of Mines; Cornell; Stanford; University Pennsylvania; Brown; MIT; UC Berkeley; Rutgers; University Michigan College Engineering; University Maryland; Waterloo; Olin; University of Colorado; Cooper; Princeton; Harvard; Caltech; Columbia; Pace.

And if you can’t meet us in person, remember to always check us out online: http://www.pivotallabs.com/jobs/welcome.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Max Brunsfeld

Standup 8/26/2011

Max Brunsfeld
Saturday, August 27, 2011

Interesting Things

  • Radio buttons behave strangely when they have no ‘value’ attribute. If you had a form containing a tag like this:

<input type="radio" name="foo" /> (no value attribute),

and you selected that radio button, then the POST data will contain foo=on. The default value is not an empty string, but the word “on”.

You might run into this problem using rails form helpers. If you pass a nil value to ActionView’s radio_button_tag method, it will render a tag without a ‘value’ attribute, so the string “on” might show up in your params.

  • Watch out for old middleware that expects the :body method of a Rack::Response to return a string. In newer versions of rack, the method returns an enumerable. We ran into this problem with an old version of pdfkit. It’s fixed in the new version.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Max Brunsfeld

Standup 8/24/2011

Max Brunsfeld
Wednesday, August 24, 2011

Ask for Help

Cocoa applications can be made scriptable with AppleScript. Unfortunately, nobody at the office this morning had experience with this.

Interesting Things

SF Pivots should check out the free PCs in the ops area. These were cutting edge linux development machines several years back, and now they and there parts are up for grabs!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (85)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to Community Feed
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • 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 >