Monthly Archives: August 2012

Interestings

Poltergeist – Kinda like the devil

Poltergeist is a gem that replaces capybara-webkit and handles iframes better supposedly. The unfortunate side-effect of using it is that it modifies how exception handling works even within your controller actions. This was incredibly hard to debug. We recommend not using it for a while.

Rails time columns always trigger change

If you have a nil time column and you set it to nil, model.changed? now returns true.

After finding that we had a few images checked into our project’s repository but that were not referenced in the project, I wanted to write a script to quickly see if there were any other unused assets.

This was a one-off script, so it probably won’t suit everyone’s needs, but here’s how we approached the problem:

First, we needed to get a list of the files that git was tracking in our image directory. While you could use ls for that, I wanted to be sure that we weren’t going to list any files that git was ignoring, so we started with git ls-files, whose output will look something like this if called as git ls-files ./img:

img/foo.png
img/bar.png

(For the sake of the example, we’ll assume that foo.png is referenced in the project and bar.png isn’t.)

The next thing we want to do is to see if those filenames are referenced anywhere in the code. At this point, I wasn’t sure if they would be referenced by a relative or absolute path, so I knew I wanted to just search for e.g. foo.png. I like to check my work with an intermediate command, so the next command we tried out was

for FILE in $(git ls-files ./img); do
echo $(basename "$FILE")
done

(basename gives you everything after the last slash of its input — in this case, just the raw filename.) And when we ran that command, we saw the expected output:

foo.png
bar.png

Now that we know we are correctly extracting the desired part of the path, we can check whether that filename is referenced anywhere in the code. git grep works enough like regular grep, but it only searches tracked files in the working tree (if you call it without a commit-ish), so we don’t have to worry about excluding the .git directory or .gitignored files.

If we call git grep foo.png manually, we will see some output like

src/index.html: <img src="../img/foo.png"/>

and git grep bar.png will have no output. But it isn’t the output we care about so much as the exit status (noting that git grep will return non-zero when no results are found) — so let’s run our command again, and verify that we will only remove the expected files:

Last week, we made a slight tweak to how velocity is calculated in Pivotal Tracker, to handle team strength overrides in a simpler, more explainable way. As a result, if your project has an adjusted team strength in a recent iteration, you may be seeing a slightly different velocity.

Details of how velocity is calculated, and how team strength affects it, are at the end of this post.

This seems like a good opportunity, though, to step back a bit, and revisit the velocity concept in Tracker and why it (still) matters. Read on, even if you’re an old hat to agile and Tracker!

What is Velocity?

First, let’s re-define what velocity is. Christian Niles, our iOS engineer, recently gave it an eloquent description (inspired by his recent relaxed strolls through the streets of Paris):

“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.

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.”

It’s About the Conversation

Yes, velocity does give you a glimpse into the future, in the form of more realistic estimates of when milestones will be hit, at least compared to wishful due dates. It’s obviously just an approximation, though, and the velocity number itself is ultimately not very meaningful outside the context of a given project.

What’s really valuable are the conversations that story estimation encourages within development teams (and their product owners). Conversations that uncover all kinds of assumptions and hidden scope, and give the product owner the insight to make value decisions at every step (is that 5 point feature really worth it, is there a simpler alternative?), which all leads to leaner, better product, and a more direct path to the finish line.

Having a crisp, prioritized backlog of estimated stories, and a steady velocity, lets you have really constructive conversations with your stakeholders when facing that inevitable change to requirements. Dragging those new stories into the backlog gives you immediate feedback about how the scope increase will affect the future timeline and planned releases, and allows you to make tradeoff decisions (“ok, let’s move these other stories down so we can still make that milestone”).

These conversations are where all the important tactical decisions are made, and there will be many, as you keep learning as a team, and the world keeps changing on you. Each one takes you closer and closer to winning the battle (and shipping great software).

Consistency is Everything

Steady state allows you to predict, at least roughly, when your project will hit important milestones. This gives your business the ability to plan ahead and to make meaningful tradeoff decisions (usually scope vs time), as you discover more scope (and you always do). Predictability is rare in the software industry, and only comes when you get your project to that zen-like state of steady, consistent pace, measured by low volatility (of velocity).

Achieving low volatility takes an ongoing effort, but the practices that collectively yield it are worth the effort on their own merit. Break down large features into small stories (that fit into a single iteration), estimate as a team, maintain a constant ratio of features to bugs and chores every iteration, deliver stories continuously, and have your product owner highly involved, available, and accepting those stories daily.

Managing Team Fluctuations

Unless you’ve got a team of cyborgs, or perfected cloning technology, chances are there will be weeks when a big subset of the team is sick (yes, that achilles heel of pair programming), on vacation, at a conference, or it’s just the usual between the holidays lull with a skeleton crew.

The team strength feature allows you to plan for that (or account for it retroactively), in terms of velocity. For example, if half of your team leaves for a conference one iteration, you might set your the team strength of that iteration to 50%. Likewise, if your team works all weekend to prepare for launching your product, you would set the team strength to 140% (since they worked 7 days instead of a normal 5 day work week).

You can also adjust the length of a single iteration, for situations such as the big end of year holidays. Or you can use it to effectively put your project on hold, by combining iteration length override with a team strength of 0%.

Just the Formula, Please

How velocity is calculated is fairly straightforward, it’s the sum of all ‘normalized’ points completed over a given set of iterations (based on project settings), divided by the combined length of all those iterations, in weeks. ‘Normalized’ points are the number of points the team would have completed in an iteration at 100% team strength.

The formula above always returns velocity per week. The project velocity Tracker displays is always multiplied by the default iteration length, and rounded down to the nearest integer. For example, if your iterations are 2-weeks long by default, Tracker will multiply the per-week velocity by 2.

Learning More

We’ve got quite lot of detailed information about velocity and related topics in the Tracker FAQ, as well as the Getting Started guide. In particular, take a few minutes to watch the Introduction to the Concepts video.