Want to understand project status at a glance?
Burndown chart? Good.
Burn-up chart? Better.
But if you don't know Cumulative Flow Diagram (CFD),
You're only seeing half the project.
CFD X-rays the project's health status.
Where bottlenecks are, where work gets stuck,
And even when it will end, all in one graph.
Today, let's learn how to properly utilize this powerful tool.
What is CFD?
Simply put, it's a cumulative graph of task status over time.
Task Count
100 | ■■■■■■■■■ Done
| ■■■■■░░░░░░░░ Testing
| ■■■■■░░░░░░░░░░░░░ In Progress
| ■■■■■░░░░░░░░░░░░░░░░░░ To Do
|■■■■■░░░░░░░░░░░░░░░░░░░░░░░ Backlog
0 |________________________________
Day 1 5 10 15 20 25 30
The height of each colored band represents the number of tasks in that status.
5 Secrets CFD Tells
1. WIP (Work In Progress) at a Glance
def analyze_wip(cfd_data, day):
"""Calculate WIP for specific date"""
in_progress = cfd_data[day]['in_progress']
testing = cfd_data[day]['testing']
review = cfd_data[day]['review']
total_wip = in_progress + testing + review
if total_wip > team_size * 2:
return "⚠️ Excessive WIP! Bottleneck occurring"
else:
return "✅ Maintaining appropriate WIP"
Band widening = WIP increasing = Danger signal
2. Immediate Bottleneck Discovery
// Bottleneck pattern detection
const bottleneckPatterns = {
testing_bottleneck: {
symptom: 'Testing band keeps widening',
cause: 'QA resource shortage',
solution: 'Test automation or add QA personnel',
},
review_bottleneck: {
symptom: 'Review band thickening',
cause: 'Code review delay',
solution: 'Add reviewers or pair programming',
},
};
If a specific band keeps widening, that stage is the bottleneck.
3. Throughput Measurement
# CFD slope = Throughput
def calculate_throughput(cfd_data, start_day, end_day):
completed_start = cfd_data[start_day]['done']
completed_end = cfd_data[end_day]['done']
days = end_day - start_day
throughput = (completed_end - completed_start) / days
return f"{throughput:.1f} tasks/day"
# Example: 50 completed in 10 days = 5 tasks/day
The steeper the Done line slope, the faster the team works.
4. Lead Time Prediction
Drawing a horizontal line in CFD shows lead time.
| ■■■■■■■■■■■■■■■■■■■ Done
| ■■■░░░░░░░░░░░░░░░░░░░ Testing
| ■░░░░░░░░░░░░░░░░░░░░░░ In Progress
|■━━━━━━━━━━━━━━━━━━━━━━━> This task's journey
|░░░░░░░░░░░░░░░░░░░░░░░░ To Do
└────────────────────────
↑Start ↑Complete
└──── 15 days (Lead Time) ───┘
5. Project Completion Prediction
def predict_completion(cfd_data):
"""When will it end at current velocity?"""
remaining_work = cfd_data['backlog'] + cfd_data['todo']
current_velocity = calculate_weekly_velocity()
weeks_needed = remaining_work / current_velocity
completion_date = today + timedelta(weeks=weeks_needed)
# Consider uncertainty
best_case = completion_date - timedelta(weeks=weeks_needed * 0.2)
worst_case = completion_date + timedelta(weeks=weeks_needed * 0.3)
return {
"expected": completion_date,
"best_case": best_case,
"worst_case": worst_case
}
Reading CFD Patterns: Healthy Team vs Problematic Team
Healthy CFD
Ideal Pattern:
- Each band maintains constant thickness
- Done line steadily rising
- Overall parallel line form
Problematic CFD Patterns
1. Staircase Pattern
| ■■■■■
| ■ ■■■■■
| ■■■■■ ■■■
Cause: Batch processing
Solution: Switch to continuous flow
2. Flat Done Line
|─────────────────── Done not rising
Cause: Not completing
Solution: Remove blockers, redefine Definition of Done
3. Expanding Band
| ▲ Testing area keeps widening
| ■■■
| ■■░░░■■
| ■░░░░░░░■
Cause: Specific stage bottleneck
Solution: Strengthen resources for that stage
Practice: Implementing CFD
Simple CFD Generation Code
class CumulativeFlowDiagram {
constructor(tasks) {
this.tasks = tasks;
this.states = ['Backlog', 'Todo', 'InProgress', 'Testing', 'Done'];
}
generateData() {
const dates = this.getDateRange();
const data = [];
dates.forEach((date) => {
const dayData = {
date: date,
counts: this.getTaskCountsByState(date),
};
data.push(dayData);
});
return this.cumulativeSum(data);
}
cumulativeSum(data) {
// Convert each state to cumulative
return data.map((day) => {
let cumulative = 0;
const result = { date: day.date };
this.states.forEach((state) => {
cumulative += day.counts[state];
result[state] = cumulative;
});
return result;
});
}
detectBottlenecks() {
// Detect sections where band width increases
const warnings = [];
this.states.forEach((state) => {
if (this.isBandWidening(state)) {
warnings.push({
state: state,
message: `Tasks accumulating in ${state} stage`,
});
}
});
return warnings;
}
}
Making CFD in Excel
You can easily make it in Excel:
Date | Backlog | Todo | InProgress | Testing | Done
--------|---------|------|------------|---------|------
Day 1 | 50 | 0 | 0 | 0 | 0
Day 2 | 45 | 5 | 0 | 0 | 0
Day 3 | 40 | 8 | 2 | 0 | 0
Day 4 | 35 | 10 | 3 | 2 | 0
Day 5 | 30 | 12 | 4 | 2 | 2
→ Visualize as stacked area chart
CFD Utilization Tips
1. Update Daily
CFD must be updated daily to be meaningful.
Automation is even better.
2. Analyze with Team
Weekly Friday CFD Review:
- Where was this week's bottleneck?
- Did processing speed change?
- Next week's prediction?
3. View with Other Metrics
weekly_metrics = {
"cfd_analysis": analyze_cfd(),
"velocity": calculate_velocity(),
"cycle_time": measure_cycle_time(),
"burndown": check_burndown()
}
# Comprehensive health score
health_score = calculate_project_health(weekly_metrics)
Little's Law and CFD
You can see Little's Law directly in CFD:
Average Lead Time = WIP / Throughput
Example: WIP 20, daily throughput 4
→ Average Lead Time = 20/4 = 5 days
In CFD, vertical distance is WIP, slope is throughput.
Conclusion: CFD is the Project's EKG
Just as doctors see heart status with EKG,
PMs see project status with CFD.
If burndown charts show "how much is left",
CFD shows "how is it flowing."
Both are needed, but CFD tells more.
Start drawing CFD from tomorrow.
Hidden project problems will be visible at a glance.
Need real-time CFD and advanced project analysis? Check out Plexo.

Top comments (0)