Comparing progress across projects that name their workflow states differently

Map every workflow state to one of five categories so WIP, throughput and cycle time compare across projects. A worked example, plus the edge cases.

6 min read

Three projects with their own workflow states, each state colour-coded to one of five shared categories.

Give three teams a tracker and you get three workflows. One project moves work through "Todo, In progress, In review, Done". Another uses "Next up, Building, QA, Released". A third has "Ready, Doing, Deployed". Each is reasonable, and each team will resist renaming its states to match the others.

That is fine until someone asks a question across all three: how much is in progress, what share of this quarter's work is finished, how long does a piece of work take from start to finish. Answering by state name means a growing list of special cases. The fix is older than any particular tool. Keep the names free, and map every state to one of a small, fixed set of categories that code is allowed to read.

The flow metrics need two points

The Kanban Guide defines four flow metrics, and all of them depend on two points in the workflow:

  • WIP: "The number of work items started but not finished."
  • Throughput: "The number of work items finished per unit of time."
  • Work item age: the time from start to now, for items not yet finished.
  • Cycle time: "The elapsed time between when a work item started and when a work item finished."

The guide leaves it to each team to decide where "started" and "finished" are. Within one project that decision lives in people's heads. Across projects it has to live in data, or the numbers are not comparable.

Five categories are enough

A set that covers almost every software workflow:

CategoryMeaningCounts as
BacklogCaptured, not committed toNot started
UnstartedCommitted to, not begunNot started
StartedSomeone is working on itWIP
CompletedFinished, by the team's definitionFinished
CanceledWill not be doneExcluded

The split between backlog and unstarted is the one teams skip and later miss. "Someone mentioned it once" and "we agreed to do this next" are different promises. Merging them makes every plan look larger than the team ever committed to.

Canceled is its own category for a similar reason. A canceled item is closed, but it was not delivered, and folding it into completed inflates both throughput and progress.

A worked example

Three projects, three workflows, mapped once:

WebMobileAPICategory
BacklogIdeasTriageBacklog
TodoNext upReadyUnstarted
In progressBuildingDoingStarted
In reviewQA(none)Started
DoneReleasedDeployedCompleted
CanceledWon't doDroppedCanceled

Now take a snapshot. These counts are made up for the example:

ProjectBacklogUnstartedStartedCompletedCanceled
Web3085223
Mobile126496
API942150

Some questions are now one query each:

Items in progress across the portfolio
11
Web's progress on committed work
63%
Mobile's progress if canceled counted as done
47% to 60%
  • Work in progress across the portfolio: 5 + 4 + 2 = 11 items started and not finished.
  • Progress on committed work: completed divided by everything committed and not canceled. For Web that is 22 / (8 + 5 + 22) = 63%. Leave the backlog out, or every new idea makes the project look further behind.
  • What canceled does to the number: count Mobile's six canceled items as finished and its progress jumps from 9 / 19 = 47% to 15 / 25 = 60% without a single extra thing shipping.

None of these needed to know that Mobile calls its review state "QA" or that API has no review state at all.

Rules that keep the categories honest

Code reads the category, never the name

A report that checks state.name == "Done" works until the first team renames "Done" to "Shipped", and then quietly stops counting anything. Progress bars, cycle time, end-of-sprint rollover and importers should all branch on the category. Names are for people.

A review state is started, not completed

"In review", "QA" and "Ready to deploy" are tempting to call done, because the work feels done. Decide what "finished" means for your metrics, usually "a customer can use it", and map everything before that point to started. Cycle time that stops at code review looks good and predicts nothing.

Recategorizing a state rewrites history

Every project needs a default state

New items have to land somewhere. A project should always have exactly one default state, usually in the backlog category. The safe way to change it is to make another state the default, never to clear it and leave new work with nowhere to go.

Decide how reopened work counts

An item that goes from completed back to started has two possible cycle times: from first start to final finish, or only the last stretch. Either is defensible. Pick one, write it down, and compute it from the history of category changes rather than from the current state. If the history records category transitions with timestamps, both versions are easy to compute later.

Categories outside the team

Categories also help when work is shown to people outside the team, such as customers watching a public roadmap. A roadmap that displays internal state names leaks vocabulary nobody outside understands ("Blocked on infra", "Needs spec") and has to change every time a team renames something.

Map categories to a handful of public statuses instead:

CategoryPublic roadmap
Backlog or unstartedPlanned
StartedIn progress
CompletedShipped
CanceledNot shown, or "Won't do"

If a public request is linked to the internal task, the roadmap can follow the task with nobody moving cards by hand. When the task starts, the request reads "In progress", and when it completes, "Shipped". That is also the natural moment to tell the people who asked, which is a topic for another article.

Checklist

  • A fixed set of categories, about five, defined once for the whole workspace.
  • Every state in every project maps to exactly one category; names stay free.
  • Separate backlog from unstarted, and canceled from completed.
  • Reports, rollovers and imports read categories, never names.
  • Review and QA states count as started unless a customer can use the work.
  • Changing a state's category is a recorded event, not a silent edit.
  • One default state per project, always.
  • Cycle time is computed from recorded category transitions, with a written rule for reopened work.
  • Public statuses come from categories, not from internal state names.