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
Ken Mayer

It’s The Volatility That Will Kill You

Ken Mayer
Tuesday, February 19, 2013

Volatility is what Pivotal Tracker uses to measure the consistency of your team’s work output. You can use that number to help you estimate the first approximation to answer the eternal question, “Will I make the deadline?”

One fine day at the office…

The Project

You’ve scoped out 100 points worth of stories for the Next Big Release™. Pivotal Tracker shows your velocity is 10 points per week. Your annual review is in 3 months and on-time delivery of this high profile project will figure prominently.

The Boss Then the CEO walks over to your desk and asks, “Will I make the launch date, 10 weeks from now?”

What do you say?

  1. “Yes, my lord. Of course we’ll make our date! I’m 100% certain of it; Behold; Tracker says we’ll finish in 10 parsecs.”
  2. “Probably; We had some iterations that cleared 30 points, but last week we were working on bugs and only accepted 2 points. A couple weeks of those and we might miss the deadline.”
  3. “There’s no clear answer. There are so many other uncertainties, technical debt, QA, deployment work.”

It’s a trap!

It's A Trap!Hopefully, you answered with “none of the above.” Velocity is just one measure of how your project is performing. Staking your career on it would be foolhardy. The second answer is honest, yet hopelessly vague. The third reply is why many people still think Agile is a way to duck your responsibilities as a software professional. There is hope, however; We can use Pivotal Tracker’s tools to make a better (albeit imperfect) estimate.

Past Performance is No Guarantee of Future Returns, but Yesterday’s Weather is Often Good Enough

Velocity, week over week, varies; sometimes a lot, sometimes a little. It depends on the project. Ideally, each iteration would have the same mix of stories, bugs and chores and Velocity would be very consistent. Steady velocity is a good thing™. In the real world, however, all sorts of things crop up; Your head-count goes up (or down), business priorities shift (or pivot), deferred technical debt demands payment, quality assurance files a slew of bug reports, user testing reveals flaws in product, visual design changes. The real world creates volatility in your Velocity.

A simple measure of this is standard deviation, which Tracker constantly computes for your project. Using that metric, you can decide what you should watch or change in order to meet your goals. Let’s go back to our example and look at the velocity charts in Tracker.

velocity

Assuming that we have a normal distribution of weekly velocities, the first sigma (±35%) will fall into the range of 10±3.5 points each week. That is, there is a 70% probability that your project will deliver all 100 points somewhere between 8 and 16 weeks. Why so much spread? 40% volatility is a big number! In the worst case scenario, where every iteration delivers only 6.5 points, it gets you to your goal in 100 ÷ 6.5 ≅ 16 weeks.

burndown

I Find Your Lack of Faith Disturbing

By now, you’ve had your meeting with the CEO. You’ve shown him the stories left in the backlog, the volatility of the project, and the range of estimates for delivery. This is the beginning of a conversation. If you’re team is not comfortable with the worst case scenario, something must change and, really, you have only two choices; you can reduce volatility or you can reduce scope. You will probably need to do both. Alas, there is no simple formula here. This is where skill, experience and insight will come into play. Here are some suggestions:

Reduce Volatility

  • It’s critical that stories are accepted as soon as possible after they are delivered. Is the project manager unable to accept stores as they are delivered, so they don’t get credited in the iteration where they started? You can backdate acceptance to reflect when the stories were ready (rather than when the PM accepted them), but it is not something I would do on a regular basis.
  • Are the stories marked as bugs and chores *truly* overhead, or are they “stealth” features? Does the story add business value to the product? That’s a feature. Flaws introduced by feature stories are bugs. Design changes surfaced by testing is a new feature.
  • Are there too many stories in flight? Can you deliver stories more reliably by starting fewer at a time? Study after study shows that human beings do not multitask well at all. Do one thing, do it well, then move on.
  • Are there blocked tracks? Do stories get stalled because of dependencies? Can you reorganize your backlog so each story is independent.
  • Are there outside resources, out of your control, that are introducing volatility?
  • Multiple rejected stories are toxic. If your team is getting more than one or two rejects each week, this may be a sign that your stories are not accurately representing what your product manager intended. It’s time to look at your work flow to prevent them from happening so often.
  • Are you not refactoring enough? Constant, steady refactoring, delivered during each story is much better than giant refactors that last a week. You should consider refactoring as critical to your process and not something to do “later, when you have more time for it.”
  • Make all of your projects small by breaking them up. Delivering a project on time is always tricky business. I’ve discovered that it is actually easier to work on projects with short time-lines (6 weeks seems to be a good number). Urgency and a looming dead-line focuses the mind in wonderful ways.
  • As a tactical measure, simplify your pointing strategy. Pivotal Tracker offers many pointing “styles;” linear, quadratic, fibonacci, or you can customize your own. Try going simpler (instead of finer granularity); a 0-1-2-3 scale (easy, medium and hard), might give you a more accurate picture.

Reduce Scope

  • What’s really at risk if you miss the deadline? Often, the perceived urgency is far greater than the actual risk to the project.
  • Are there features that you can jettison?
  • Are there features that you can defer?
  • Are you spending too much time on “pixel-perfect fidelity?” Talk to your designers; look for ways to reduce complexity. One good way to reduce complexity is to lean more heavily on standard user interface libraries (which might affect the unique visual design of the project).
  • Can you make “soft releases” where you deliver fewer features, earlier, to reduce risk?
  • Look at your project goals again. Are the stories in the backlog truly delivering features that will meet your goals?
  • Are there parallel “tracks” that allow you to add man-power to the project (but see below).

Watch for Icebergs

  • Do you need to stand up a new production environment? That will take time. It’s a point-able story. Make sure that all the necessary steps to release are in the budget.
  • Are you refactoring as you go? Have you been postponing technical debt? Those interest payments will start to pile up as you get closer to release time. Make sure you and your team know that keeping the code clean is an essential part of every story.
  • Anything that changes your team will change both Volatility *and* Velocity. Are you adding a new team member? (Remember Brook’s Law, “adding manpower to a late software project makes it later.”) Vacations, holidays, sick days and babies will affect your velocity. Remember to account for it in Tracker.

You’re all clear, kid, now let’s blow this thing and go home!

This article should give you a lot to think about. Good project management is hard work. When projects are just getting started, everything feels fine, and later you start to wonder when everything went to hell. Remember, volatility kills.


Notes

velocity
Just like a speedometer that measures how fast you’re hurtling through space, Tracker’s velocity is a measurement of how fast your team completes stories. Instead of miles or kilometers per hour, Tracker expresses velocity as the number of points completed per iteration (normally a week).Because Tracker stories are assigned point values instead of due dates, Tracker calculates velocity by averaging the number of points you’ve completed over the past few iterations. In Tracker, past predicts future.
volatility
Mathematically, Volatility isStandard Deviation ÷ Mean Velocity
acceptance
If stories languish in the accept/reject state (a field of red and green buttons in the backlog is a strong indicator), several bad things may happen to your project: You lose the fast feedback loop between delivery and deployment. Developers will move on to the next story and may have already lost “context” about past ones. Unaccepted stories can not be deployed, so there’s less and later feedback about the feature in the full project.
stories
What makes a feature or a bug or a chore is worthy of an entire article on its own.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jeff Hui

Red Bull Book Club Block Party (with fireworks)

Jeff Hui
Friday, February 15, 2013

Helps

Rails remote link gets updated

Rails link remote.

Get HTML into the Dom? Without the callback? (no id)

  • Turbo links?
  • Delete ujs from the app

Events

Friday: Block Party between 4th and 5th on Bluxome

http://engine.is/blockparty

This Friday celebrating start ups in SF w/food trucks at lunch time.

Come meet Engine Advocacy – startups' voice in government.
Bring your friends, enjoy great food, and learn about becoming
an Engine member.

Engine's Startup Block Party
February 15, 2013
11:00 am – 2:00 pm
Bluxome St., between 4th and 5th

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jeff Hui

Valentine’s “pair exchange”

Jeff Hui
Thursday, February 14, 2013

Helps

PostGIS 2.0 as a service?

We want to use PostGIS 2.0 but Heroku's docs on the matter say it's in beta and "subject to change". Has anybody used it in production? Does anybody know of a production-quality alternative?

Interestings

Where is my stdout on CI?

The ci_reporter gem suppresses stdout and stderr by default, so you won't see puts results in Jenkins' console output.

Setting your environment variable CI_CAPTURE to the string "off" will stop suppressing the output.

Events

Thursday: Thursday night pair exchange

In addition to the regular Tuesday event. Same time, 6:15 – 9:00.

Friday: Block Party between 4th and 5th on Bluxome

http://engine.is/blockparty

This Friday celebrating start ups in SF w/food trucks at lunch time.

Come meet Engine Advocacy – startups' voice in government.
Bring your friends, enjoy great food, and learn about becoming
an Engine member.

Engine's Startup Block Party
February 15, 2013
11:00 am – 2:00 pm
Bluxome St., between 4th and 5th

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jeff Hui

[SF] Fireworks provided by Colin!!!

Jeff Hui
Wednesday, February 13, 2013

Events

Thursday: Thursday night pair exchange

In addition to the regular Tuesday event. Same time, 6:15 – 9:00.

Friday: Block Party

http://engine.is/blockparty

next Friday celebrating start ups in SF w/food trucks at lunch time.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jeff Hui

[SF] Where’s Select 1?

Jeff Hui
Tuesday, February 12, 2013

Events

Tuesday: Ruby Meetup

Meet after work to go there:

http://www.sfruby.info/events/96446412/

Thursday: Thursday night pair exchange

In addition to the regular Tuesday event. Same time, 6:15 – 9:00.

Friday: Block Party

http://engine.is/blockparty

next Friday celebrating start ups in SF w/food trucks at lunch time.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Andrew Fader

The simplest thing that could possibly work in Tetris

Andrew Fader
Monday, February 11, 2013

At Pivotal we practice a form of Agile software development descended from the original Extreme Programming (XP) created by Kent Beck et al. XP codifies many of our core practices including pair programming, test-driven development, iteration planning, and stand-up. XP also has a very strong emphasis on flat hierarchies and frequent communication. Because of its values and engineering guidelines, XP allows for high-quality software to be produced and shipped extremely quickly. XP values working software over extensive specifications or documentation, so-called “big design up front.” This is so the product can be iterated on quickly, both in the business and the technical sense.

Opinions differ as to which of XP’s practices is the most valuable in accomplishing this. One of my personal favorites is simplicity and clarity in code and design. Simplicity is a difficult thing to pin down. Occam’s Razor, one of the earliest and most popular statements of the parsimony principle, suggests we form a hypothesis with the least “plurality,” or the fewest assumptions or entities possible. Since then people have rephrased this idea as “keep it simple, stupid” (KISS) or probably the most elegant, “less is more.” My favorite statement is St. Exupéry’s:

“It seems that perfection is reached not when there is nothing left to add, but when there is nothing left to take away.”

XP offers us its own guidance on simplicity and writing simple code. It has two simply stated tenets on simplicity: “do the simplest thing which can possibly work,” and the related “you ain’t gonna need it” (YAGNI). Ward Cunningham, another father of XP, explains the first concept as:

“What’s possible? What is the simplest thing we could say in code, so that we’ll be talking about something that’s on the screen, instead of something that’s ill-formed in our mind. Once we get something on the screen, we can look at it. If it needs to be more, we can make it more.”

YAGNI is an answer to the temptation to prematurely optimize: “Always implement things when you actually need them, never when you just foresee that you need them.” Yet, XP also tells us we should “refactor mercilessly,” and Cunningham has long been a proponent of object-oriented design patterns. There is some tension there and it depends on the project and situation.

Clojure creator Rich Hickey tells us in his 2011 talk that the easiest thing isn’t always the most simple, and the simplest design isn’t always immediately apparent. This is a veiled jab at object-oriented programming in favor of functional languages. Obviously object orientation leads to many more “entities” than functional design, assuming entities are objects. Yet most programmers will tell you that objected-oriented design is “easier” than functional design. Perhaps this is merely because they are more familiar with OOP from past experience. However, many would also argue that functional code is quite complex. Code is communication, so a good design is easily parsed (by humans) and understood. That might mean favoring OOP conventions over a more functional style. In Ruby we have a number of functional-inspired techniques that allow for some middle ground to follow the principle of least astonishment.

Let’s look at a case study. Some months ago, I worked on a Ruby implementation of Tetris in my spare time. My goal was to have a working implementation in the shortest time possible, to win a bet that a working game of Tetris would take more than a few days. I settled on Gosu, a C++ 2D game development library that provides graphics, sound, and many other features in a pure Ruby wrapper. The game is on Github. After bundling, you should be able to run it with ‘ruby game_window.rb,’ and try prefacing that with bundle exec if it doesn’t work right away. You will need to have a number of dependencies installed, see the Gosu documentation for more.

I assume the reader is familiar with the rules of Tetris. One of the first things I did was create the shapes for the pieces. Tetris has 7 pieces. All somewhat resemble letters: I the 4×1 stick, J and its mirror L, S and its mirror Z, O the square box, and T. I knew in my head what these pieces looked like, and could easily draw them. So, I created a relative X,Y coordinate system and a draw method. For example, the I piece was [[0,0],[1,0],[2,0],[3,0]].

Now that I had pieces, I needed rotation. I knew what the rotation should look like, but I was not entirely sure how to implement the concept in code. Without researching the question much, I decided to hard-code my values. This seems “dirty” or “ugly,” but it is in keeping with Cunningham’s urging to put something on the screen now and iterate on it later. It was the simplest thing that could possibly provide a working implementation of the game. I also knew that there was a bounded number of possible pieces and rotations in the game, and no need to generalize further. Furthermore, I wasn’t working with a team, didn’t need to maintain the code going forward, and had to win a bet. So I created a large case statement of hashes that looked like this:

def shape
   case @type
   when :I
      {0 => [[1,0],[2,0],[3,0]],
       1 => [[0,-1],[0,-2],[0,-3]],
       2 => [[-1,0],[-2,0],[-3,0]],
       3 => [[0,1],[0,2],[0,3]] }

The pieces, when generated, would randomly assign themselves a type from the list, and a rotation starting at 0. The current_shape method would call to the shape hash method with the current rotation to get the current shape. When the player pressed up, the game would increment the rotation by 1 or reset it back to 0 if it had reached 3. This is not a bad “simplest thing” solution because it is fairly easy to understand what it is doing, and hopefully easy to refactor it into something a bit more elegant. You can see this early commit here. Feel free to checkout that version of the code and run it as well (git checkout 04d590d114cdd564f54491b77339c6ac24bb1693). It will generate a random Tetris piece and then crash. The next commit, ebfcc34e461d30321edf7293f8dc3de95fa2af2b, has semi-functional rotation using the hash method.

I was able to finish the Tetris game with this hard-coded implementation and left it alone for some months. However, in the back of my head, the hard-coded solution was bothering me, and I wanted to implement it using a rotation matrix, a concept I dimly recalled from math class.

Good tests are the most important requirement for refactoring confidently, since they provide a known basis that your refactor preserved the correct behavior and did not break anything. I had been sloppy the first time around and hadn’t written a test for the method that contained the massive case statement, which later became a class method with a type parameter. So here it is:

it "I" do
   Piece.shape(:I)[0].should == [[1,0],[2,0],[3,0]]
   Piece.shape(:I)[1].should == [[0,-1],[0,-2],[0,-3]]
   Piece.shape(:I)[2].should == [[-1,0],[-2,0],[-3,0]]
   Piece.shape(:I)[3].should == [[0,1],[0,2],[0,3]]
end

This was green, as you’ll note it is quite similar to the implementation above. For my refactor I wanted to change the interface of the shape method to have 2 parameters instead of returning a hash, so my test would look like

Piece.shape(:I,0).should == [[1,0],[2,0],[3,0]]

but would otherwise remain the same. The case statement would remain, but would only return the 0 rotation, after which I would perform some sort of matrix transformation.

Wikipedia tells us that the rotation matrix for 90 degrees counterclockwise is:

rotation matrix

After some Googling I settled on an implementation like this:

rotation.times do
   shape = shape.map{|arr|(Matrix[arr] * Matrix[[0,-1],[1,0]]).to_a.flatten}
end

Although the tests passed for the I, J, and L shapes, the other piece tests did not. The O shape actually moved around its axis of rotation even though in my hard-coded version, I had it remain stationary. I had also previously suspected a bug in the implementation of the S or Z shapes, since they seemed to be roughly the same, even though they should have been mirror images. More than likely my known “true” values were simply off. Playing the game confirmed that the rotation was functional and acted as intended. You can see the commit at GitHub.

I was further able to refactor away the rotation variable, generate the shape at object initialize time, and apply the rotation upon receiving player input (commit). This optimizes the number of rotations. Previously, each rotation would start at 0 and progress to a maximum of 3. So if I rotated from 2 to 3, the old code would actually calculate the interim steps 0 to 1 and 1 to 2 as well. The new stateful version will only perform one matrix transformation per rotation.

This change also allowed me to rewrite the test in a much more object-oriented and end-to-end way, as follows:

let(:piece) { Piece.new(window, grid, type) }
describe "I" do
   let(:type) { :I }
      it "rotates" do
         piece.shape.should == [[1,0],[2,0],[3,0]]
         piece.rotate
         piece.shape.should == [[0,-1],[0,-2],[0,-3]]
         piece.rotate
         piece.shape.should == [[-1,0],[-2,0],[-3,0]]
         piece.rotate
         piece.shape.should == [[0,1],[0,2],[0,3]]
       end
   end
end

I think this is a reasonable showcase of a balance between refactoring and simplicity. My initial implementation was pretty ugly, but it allowed me to continue making progress. After getting the simplest thing out the door and hitting my deadline, I went back to refactor the technological debt I had accrued.

Also, I am not going to need it, but the solution is now generalized enough that I could add additional pieces. For example:

   [[1,0],[2,0],[2,1],[2,2],[2,3],[3,0],[4,0],[5,0],[5,1],[5,2],[5,3]]


Additional Tetris piece

Some would argue that the new design is actually simpler. It's fewer lines of code, fewer branches in logic, it uses a well-established algorithm, it's more elegant. Sure, the refactored version is a vastly improved design, but "simple" isn't about lines of code or branches in logic. "Simple" is about complexity of implementation. For example, XP tells us about the "rule of three": refactor out duplication only on the third occurrence of duplicate logic, not the second. The implication is that duplication is more lines, but "simpler" to write.

What "simple" definitely is not about is elegance. The hard-coded solution was simpler because it had fewer levels of abstraction and required less of a cognitive load to understand than the matrix manipulation: the difference between basic Cartesian coordinates versus a result obtained using linear algebra. Math, even pre-calculus, is often quite elegant but quite abstract and therefore more complex than a simple table of values. Why does the rotation matrix work? Well, to understand that, you'll need to understand its generalized form, and quickly this solution becomes quite slow and complicated to implement, especially if it's late at night and you're having trouble remembering trigonometry.
rotation matrix general

It's clear that according to XP's philosophy, the hard-coded solution is the preferred first step. Kent Beck outlines the benefit of doing the easiest simple thing first:

  • You get done sooner
  • Your work is easier to communicate
  • Duplication is obvious, so the needs and means for refactoring are clearer
  • Tests are easier to write
  • The code is easier to performance tune (Or, at least, there will be more scope for tuning performance)
  • You feel less stress, which enhances all of the above

The key benefit of a simple solution is that you get it done faster so you can iterate on it. It's a first pass used to enable continued progress. Perhaps this principle should be called "do the easiest thing to make the tests pass," "do the ugliest, dirtiest thing first," "do what comes to mind first and stop thinking so hard," or maybe just "be as agile as possible." Agile, of course, primarily means "quick."

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jeff Hui

[SF] The Year of the Snake

Jeff Hui
Monday, February 11, 2013

Events

Friday: Block Party

http://engine.is/blockparty

next Friday celebrating start ups in SF w/food trucks at lunch time.

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

“expect errors”

Phil Goodwin
Friday, February 8, 2013

Helps

"expect errors" when compiling Ruby with clang

Compiled Ruby with clang and the compile output contained a warning to "expect errors". Has anyone experienced these alleged errors?

One member or our audience said that they had compiled the same way and not experienced any problems.

Interestings

Update your rack gem

Nasty remote execution vulnerability.

rack.github.com

parallel_tests prepare task does not drop tables

If you're using parallel_tests, be aware that, unlike rake db:test:prepare, the rake parallel:prepare task does not purge the databases before it loads the schema. You'll only notice this if you're dropping tables – the dropped tables will stay forever in the parallel databases.

We have a fork that works properly. (Pull request coming soon.)
https://github.com/pivotal-gemini/parallel_tests

Events

02/15: Block Party

http://engine.is/blockparty

next Friday celebrating start ups in SF w/food trucks at lunch time.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
George Dean

A Stately Resque

George Dean
Thursday, February 7, 2013

Helps

ActiveRecord save race condition in Resque

We have a Rails app that is saving a new ActiveRecord object, and then immediately afterwards, enqueueing a Resque job that looks up that record by its ID. Sometimes, the lookup inside the resque job fails – it claims no such row with that ID exists.

If we put the lookup into a loop that catches that exception and retries the exact same lookup, it always eventually succeeds, usually after 1-2 seconds.

The ID exists on the ActiveRecord object before the job is enqueued, which (I think) means that the save transaction has completed. But the resque job is using a different database connection, so maybe there's some weird caching going on? But here Google has failed us.

Any ideas? We could leave it in a loop that catches the exception, sleeps 1 second, and retries, but: ugh.

Some ideas from the audience:
There is a connection object that can be queried about transaction states.
Wait for transaction count increment/decrement?
Could be a problem with the way that sqlite fakes nested transactions.

Best practices for individual users on GitHub

Usually we have a single GitHub account for a project that contains a key for each of the machines being used on a project. On our project we want to use a separate account for each person on the project. Is there a way to do this without a lot of trouble shuffling SSH keys around?

Pivotal Git Scripts may have some tools for this.
You can also use HTTPS URLs and enter username/password on each commit.

Interestings

Lobot – Now with per-project chef recipes

If you need to write your own chef recipes to install your project's dependencies, you can add a cookbooks directory to the root of your project. Make sure to delete the cookbook_paths section from your lobot.yml (to use the default values), or add ./chef/project-cookbooks to the cookbook_paths section.

So, to have a bacon recipe, you should have cookbooks/pork/recipes/bacon.rb file in your repository.

Stately – A font of the US states

http://intridea.github.com/stately/

For all those times you need a vector representation of the USA and to color the states separately.

Apiary – Public API documentation

http://apiary.io/

Takes a well formed file and generates really usable REST API documentation. Integrates with Github for collaboration

Events

Thursday: Inaugural Thursday Night Pair Exchange tonight

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
George Dean

Test automation for iOS and smooth jazz

George Dean
Wednesday, February 6, 2013

Interestings

Appium – test automation tool for native and hybrid mobile apps

Does anyone have any experience with it?

Appium is an open source test automation tool for native and hybrid iOS apps.

  • Use Ruby, Java, Javascript etc.. to write your tests.

  • You don't have to recompile your app or modify it in any way because Appium's automation is based on Apple's UIAutomation library

http://appium.io

Smooth Jazz Nyan Cat Formatter hits 0.1.3

http://rubygems.org/gems/smooth-jazz-nyan-cat-formatter

With some display fixes. Coming eventually, configure your own music and cat!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (86)
  • 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 agile Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. ...
  10. 79
  11. →
  • 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 >