Delivery Forecast via Burn-up

Purpose

Burn Up chart shows the current project performance, overall tendency and predicts future performance. The forecast for scope and a project completion date is based on data obtained from the past iterations.

If a project or release doesn't have a certain scope planned upfront, the "Forecast" provided by this chart may not be applicable  - it can even show "infinite" forecast (meaning a project/release will never end).

How it helps

This chart works best for a "fixed scope" setup: either a release with the scope planned upfront or a whole project of a "fixed price" type.

Prerequisites

  1. All the work (e.g. Stories) is created as items in the backlog;

  2. All items are estimated (e.g. in Story Points or t-shirt scores);

  3. All items are "ready for development" i.e. passing the definition-of-ready.

This means, with the above conditions met, the delivery forecast will be accurate and valuable.

On the other hand, sometimes, when projects start (even fixed price ones), a team might not have a full backlog, or estimations in place, or stories passing a definition-of-done criteria. This might be a continuous process of Stories creation, refinement and estimations. For example, a kanban board of a BA team gives the "output" as stories ready for development for the scrum board of the Development team - this can be considered as a scope creep in PERF interpretation. At the same time, control of a total estimate per feature is important - to make sure the planned threshold isn't exceeded. So, in this example the Burn Up will be less relevant, unfortunately. 


Then, this chart helps highlight the following:

  1. Actual velocity of a team is enough or lower than expected to deliver the planned amount of work on time, i.e. till the planned "End Date" of a respective project or release. There are some ways to prevent this situation:

    1. cut scope to deliver on an agreed delivery date with the current velocity

    2. consider an extension of the team - so that the velocity might be enough to develop more features within the same time frame compared to the current velocity

    3. shift a delivery date to deliver the same scope on time with the current velocity

    4. predicts future performance

  2. Amount of work is increased in an unplanned manner over time. It may happen if stakeholders regularly add something to the backlog while a team works on the initial scope to be delivered by a defined date). In this context Burn Up helps to highlight the following:

    1. review and agree a change management process

      1. to avoid unplanned features being added into the planned scope

      2. maintain the total committed effort: if a higher priority thing is added then something less critical is removed

    2. cut scope to deliver on an agreed delivery date with the current velocity

    3. consider an extension of the team - so that the velocity might be enough to develop more features within the same time frame compared to the current velocity

    4. shift a delivery date to deliver the same scope on time with the current velocity

    5. shows the current project performance, overall tendency

  3. Shows whether project completion is on schedule 

  4. Shows team delivery speed over the past iterations 

  5. Shows planned vs actual performance

  6. Shows approximate delay in forecast towards reaching release date or any other milestone 

  7. Shows amount of scope completed

  8. Shows cost of value, i.e. completed items or story points per week 

  9. Shows whether the actual velocity of a team is enough to deliver the planned amount of work on time

  10. Shows amount of actual scope creep 

How it works

Chart overview

Chart can be viewed at various slices of a project -

  1. a whole Project

  2. a selected Release

  3. a selected Sprint

Assumptions

1 Burn Up is available only for Active and Closed sprints (which contain start and end dates), not future ones. 

2 Burn Up is available only for Releases/Versions with both start (not future date) and end dates set, otherwise chart doesn't know how to represent an expected timeline for the scope of work in this Release.

3 If Release doesn't have any issues or all issues were added after theirs closer, than this Release is not displayed in Burn-up releases list.

Additionally, it is possible to see data in the chart measured in

  • work items (i.e. a natural amount of stories, for example),

  • story points,

  • original hours, 

  • actual hours. 

To switch between these options click the gear icon on the right side of the chart.



Lines (data series) are as follows: 

  • Completed amount of work (green columns) - a cumulative sum of delivered efforts (SP/hours/items) by days or weeks on the chart. By "delivered" is meant a state when items achieved the "Done" state (e.g. in JIRA, which can be easily configurable for a particular project at the "Workflow" step in JIRA configuration).

  • Completion forecast (orange) - predicted efforts (in SP/hours/items) required to complete a required amount of scope within a project or a selected release. Completion forecast is based on available historical progress of a project and projected till the moment when the whole scope is covered based on a current team performance, which sometimes can be in the future, meaning a delay in delivery. 

  • Planned performance trend (lilac) - an ideal performance trend. The calculated line ends at the cross of Scope line (blue) and Project end date vertical line;

  • Scope line (blue) - a sum of items estimations (based on selected options - SP/hours/items) at the end of iteration date on iteration basis;

  • Scope forecast line (blue dashes) - a linear approximation of scope increase based on average scope changes.

  • Logged time (dark green line) - the total amount of logged time in Hours - appears when the chart is measured in actual or original hours.

By clicking on a Completed amount of work (green columns) a pop up appears with the following information got from the task tracking system:

  • Issue ID;

  • Type;

  • Priority;

  • Summary;

  • Completion date (date when the issue was moved into "Done" status (status from "Done" bucket in Project Settings>Data Sources>Task Tracking System>Workflows).

By clicking on a Scope line (blue) a pop up appears with the following information got from the task tracking system:

  • Issue ID;

  • Type;

  • Priority;

  • Summary;

  • Completion state (Done - if issue is in "Done" status or Incompleted, if issue is included in Scope but are has not been in the Done status yet ("Done" is a bucket according to Project Settings>Data Sources>Task Tracking System>Workflows)

  • Creation date.

  Chart with the logged timeline:

The summary section above the chart contains the following information:

  • Forecast predicts the ability of the project to finish on time. Could be turned off in the settings. 

    • In case the variance is more than 90 days and less than 360, the forecast has the measurement unit in months.

    • In case the variance is less than 90 days, the forecast has the measure unit in days.

  • Scope Completed shows the percentage of completed tasks in the project. 
    Delivered scope (green column) / Total Scope (blue line) *100%. This calculation takes into account last iteration values.

  • Remaining vs. Total Effort, items shows the amount of logged remaining efforts vs. total logged effort. 
    Remaining effort - (last blue dot value - last green column value). Total effort - last blue dot value. This calculation takes into account the last iteration values.

  • Delivered vs. Planned, items shows the number of delivered items vs. planned on the current date. 
    Delivered - last green column value. Planned - value of purple dotted line on last green column.

Top Problems Metric Identifies 

  1. Uncontrolled scope volatility

  2. Not ready for development backlog is taken into work

  3. Poor dependencies execution

  • no standards and unified JIRA workflow, so stories do not reach "Done" state

  • completed items are not accepted by Product Owner, so they are considered as not done

Calculation

View in

Completed amount of work (green columns)

Scope line (blue)

Planned performance trend (lilac)

Logged time (dark green line)

Completion forecast   (orange) 

Scope is fixed (blue dashed)

Scope creep is included (blue dashed)

Work Items

a cumulative count of Work Items in Completed state (per definition of your workflows)

a count of items available by this date regardless their status

Line between 2 dots:

  • 1-st dot Axis X and Axis Y cross - coordinates (0;0)

  • 2-nd dot Scope line and Project end date vertical line 

Project end date is taken from Project Settings



n/a

To know the exact date:

Current week number + (Scope value for today - Completed value for today)/Average velocity.

Average is calculated as an amount of completed work for N periods. N periods is taken from Project settings>Scope management> Calculation depth for average team velocity estimation.

In general, completed line is described as a function y=kx+b, where

k - average velocity for N periods. N periods is taken from Project settings>Scope management> Calculation depth for average team velocity estimation

x - an order number of the current week/day

y -  value of completed for this week/day.

Knowing that, b is calculated.

1 Find a linear function for scope line:

y=kx+b, where

  • k - average scope creep for N periods. N periods is taken from Project settings>Scope management> Calculation depth for average team velocity estimation

  • x - an order number of the current week/day

  • y -  value of scope for this week/day

Knowing that, b is calculated.

2 Find a linear function for completed line

3 Equate the function got for completed and got for scope.

4 Find the x. x is a forecast date.

If axis X in weeks it's the date of Sunday on this week.

If axis X in days it's the date of this day.

Story Points

a cumulative sum of Story Points across items in Completed state including sub items (per definition of your workflows)

a sum of Story Points in all items including sub items available by this date regardless their status

n/a

Original Hours

a cumulative sum of Person hours (as Original Estimate) in items including sub items in Completed state (per definition of your workflows)

a sum of items including sub items Original Estimates for all issues

total amount of Logged time for items including sub items in person hours by this date

Actual Hours

a cumulative sum of Person hours (as Logged time) in items including sub items in Completed state (per definition of your workflows) 

a sum of Logged Time for all issues including sub items

total amount of Logged time for items including sub items in  person hours by this date

 

Calculation notes

When Average Velocity is set in weeks, the latest completed week is taken into account not the current. In other words a velocity value for the last 7 days starting from Sunday of the last completed week is taken into account.

Logged time is according to a time stamp (Date Started) when you started this unit of work (not time when log was done). For example, You are logged time for 05/25/2021 but did it on 05/26/2021. Actual Hours will shows it for 05/25/2021

PerfQL

WITH last_sprint AS ( SELECT id, start_date, finish_date FROM Sprint WHERE state = 'ACTIVE' ORDER BY start_date DESC LIMIT 1 ), scope AS ( SELECT id, key, created, sprints FROM Ticket tw ), snapshots AS ( SELECT * FROM ticket_snapshots(ARRAY(SELECT key FROM scope), 'day') AS tw ), days AS ( SELECT generate_series( (SELECT date_trunc('day', start_date) FROM last_sprint), (SELECT date_trunc('day', finish_date) FROM last_sprint), '1 day' ) AS start ), snapshot_on_day AS ( SELECT snapshots.id, snapshots.key AS key, max(snapshots.snapshot_created) AS created, days.start AS day FROM snapshots JOIN days ON date_trunc('day', snapshots.snapshot_created) <= days.start GROUP BY snapshots.id, snapshots.key, days.start ), done_by_sprint AS ( SELECT DISTINCT snapshot_on_day.id, snapshot_on_day.key, snapshot_on_day.day AS start FROM snapshots sn INNER JOIN snapshot_on_day ON sn.key = snapshot_on_day.key AND sn.snapshot_created = snapshot_on_day.created JOIN last_sprint ls ON ls.id = any(sn.sprints) WHERE is_done(sn) ), done AS ( SELECT count(key) AS done_count, start FROM done_by_sprint GROUP BY start ), created_by_sprint AS ( SELECT key, tw.id, created, days.start, ls.id AS sprint_id FROM scope tw JOIN days ON date_trunc('day', created) <= days.start JOIN last_sprint ls ON ls.id = any(tw.sprints) ), aggregated_created_with_history_by_sprint AS ( SELECT key, cbs.id, cbs.start FROM created_by_sprint cbs INNER JOIN TicketHistory twh ON cbs.id = twh.workitem_id AND twh.field = 1 AND twh.sprint LIKE concat('%', cbs.sprint_id) WHERE (twh.start < (SELECT start_date FROM last_sprint)) OR (cbs.start = (SELECT date_trunc('day', start_date) FROM last_sprint) AND date_trunc('day', twh.start) < cbs.start) OR (cbs.start > (SELECT date_trunc('day', start_date) FROM last_sprint) AND date_trunc('day', twh.start) <= cbs.start) UNION ALL SELECT key, cbs.id, cbs.start FROM created_by_sprint cbs LEFT JOIN TicketHistory twh ON cbs.id = twh.workitem_id AND twh.field = 1 WHERE twh.workitem_id IS NULL AND ( CASE WHEN ((date_trunc('day', cbs.created) = (SELECT date_trunc('day', start_date) FROM last_sprint)) AND (date_trunc('day', cbs.created) = cbs.start) ) THEN false ELSE true END) ), created AS ( SELECT count(distinct key) AS created_count, start FROM aggregated_created_with_history_by_sprint GROUP BY start ) SELECT to_char(created.start , 'YYYY-MM-DD') AS startdate, created.created_count AS "Scope", CASE WHEN done.start > now() THEN NULL ELSE coalesce(done.done_count, 0) END AS "Completed" FROM created LEFT OUTER JOIN don

--------DRILL DOWN---------

Scope

WITH ticket_ids AS ( SELECT id FROM aggregated_created_with_history_by_sprint WHERE to_char(date_trunc('day', start), 'YYYY-MM-DD') = clicked_x_value ) SELECT CASE WHEN url is not null THEN '[' || key || '](' || url || ')' ELSE t.key END AS "Issue Id", type AS "Type", priority AS "Priority", summary AS "Summary", CASE WHEN is_done(t) THEN 'Done' ELSE 'Incomplete' END AS "Completion state", to_char(t.created, 'Mon') || ' ' || to_char(t.created, 'DD YYYY') AS "Creation date" FROM ticket t JOIN ticket_ids ti ON t.id = ti.id ORDER BY t.key DESC, t.created DESC;

Completed

WITH ticket_ids AS ( SELECT id FROM done_by_sprint WHERE to_char(date_trunc('day', start), 'YYYY-MM-DD') = clicked_x_value ) SELECT DISTINCT CASE WHEN t.url is not null THEN '[' || t.key || '](' || t.url || ')' ELSE t.key END AS "Issue Id", t.type AS "Type", COALESCE(t.priority, '') AS "Priority", t.summary AS "Summary", to_char(t.done_date, 'Mon') || ' ' || to_char(t.done_date, 'DD YYYY') AS "Completion date" FROM ticket t JOIN ticket_ids ti ON ti.id = t.id LEFT JOIN snapshots sn ON t.id = sn.id WHERE is_done(sn) ORDER BY "Completion date" DESC, "Issue Id" DESC;

 

Data Source 

Data for the metric can be collected from a task tracking system (Jira/Rally/TFS/etc.).