레이블이 프로젝트분석인 게시물을 표시합니다. 모든 게시물 표시
레이블이 프로젝트분석인 게시물을 표시합니다. 모든 게시물 표시

2025년 12월 22일 월요일

누적 플로우 다이어그램: 번다운이 보여주지 못하는 진실


프로젝트 상태를 한눈에 파악하고 싶으신가요?

번다운 차트? 좋습니다.
번업 차트? 더 좋습니다.
하지만 **누적 플로우 다이어그램(CFD)**을 모른다면,
프로젝트의 절반만 보고 있는 겁니다.

CFD는 프로젝트의 건강 상태를 X-ray처럼 투시합니다.
병목이 어디 있는지, 일이 어디서 막히는지,
그리고 언제 끝날지까지 한 장의 그래프로 보여줍니다.

오늘은 이 강력한 도구를 제대로 활용하는 법을 알아봅시다.

CFD가 뭐길래?

간단히 말해, 시간에 따른 작업 상태의 누적 그래프입니다.

작업 수
100 |                    ■■■■■■■■■ Done
    |               ■■■■■░░░░░░░░ Testing
    |          ■■■■■░░░░░░░░░░░░░ In Progress
    |     ■■■■■░░░░░░░░░░░░░░░░░░ To Do
    |■■■■■░░░░░░░░░░░░░░░░░░░░░░░ Backlog
  0 |________________________________
    Day 1   5   10   15   20   25   30

각 색깔 띠의 높이가 해당 상태의 작업 수를 나타냅니다.

CFD가 알려주는 5가지 비밀

1. WIP(진행 중 작업) 한눈에 파악

def analyze_wip(cfd_data, day):
    """특정 날짜의 WIP 계산"""
    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 "⚠️ WIP 과다! 병목 발생 중"
    else:
        return "✅ 적정 WIP 유지 중"

띠가 넓어진다 = WIP가 증가한다 = 위험 신호

2. 병목 지점 즉시 발견

// 병목 패턴 감지
const bottleneckPatterns = {
  testing_bottleneck: {
    symptom: 'Testing 띠가 계속 넓어짐',
    cause: 'QA 리소스 부족',
    solution: '테스트 자동화 또는 QA 인력 추가',
  },

  review_bottleneck: {
    symptom: 'Review 띠가 두꺼워짐',
    cause: '코드 리뷰 지연',
    solution: '리뷰어 추가 또는 페어 프로그래밍',
  },
};

특정 띠가 계속 넓어진다면, 그 단계가 병목입니다.

3. 처리 속도(Throughput) 측정

# CFD의 기울기 = 처리 속도
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"

# 예시: 10일간 50개 완료 = 5 tasks/day

Done 라인의 기울기가 가파를수록 팀이 빠르게 일하고 있습니다.

4. 리드 타임 예측

CFD에서 수평선을 그으면 리드 타임을 알 수 있습니다.

    |     ■■■■■■■■■■■■■■■■■■■ Done
    |  ■■■░░░░░░░░░░░░░░░░░░░ Testing
    | ■░░░░░░░░░░░░░░░░░░░░░░ In Progress
    |■━━━━━━━━━━━━━━━━━━━━━━━> 이 작업의 여정
    |░░░░░░░░░░░░░░░░░░░░░░░░ To Do
    └────────────────────────
     ↑시작                  ↑완료
     └──── 15일 (리드 타임) ───┘

5. 프로젝트 완료 시점 예측

def predict_completion(cfd_data):
    """현재 속도로 언제 끝날까?"""

    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)

    # 불확실성 고려
    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
    }

CFD 패턴 읽기: 건강한 팀 vs 문제 있는 팀

건강한 CFD

이상적인 패턴:
- 각 띠가 일정한 두께 유지
- Done 라인이 꾸준히 상승
- 전체적으로 평행선 형태

문제 있는 CFD 패턴들

1. 계단 패턴 (Staircase)

    |      ■■■■■
    |      ■    ■■■■■
    | ■■■■■         ■■■

원인: 일괄 처리 (배치 작업)
해결: 지속적인 흐름으로 전환

2. 평평한 Done 라인

    |─────────────────── Done이 안 올라감

원인: 완료가 안 되고 있음
해결: 블로커 제거, Definition of Done 재정의

3. 팽창하는 띠

    |     ▲ 점점 넓어지는 Testing 구간
    |    ■■■
    |  ■■░░░■■
    | ■░░░░░░░■

원인: 특정 단계 병목
해결: 해당 단계 리소스 보강

실전: CFD 구현하기

간단한 CFD 생성 코드

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) {
    // 각 상태를 누적으로 변환
    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() {
    // 띠 너비가 증가하는 구간 감지
    const warnings = [];

    this.states.forEach((state) => {
      if (this.isBandWidening(state)) {
        warnings.push({
          state: state,
          message: `${state} 단계에 작업이 쌓이고 있습니다`,
        });
      }
    });

    return warnings;
  }
}

Excel에서 CFD 만들기

엑셀로도 쉽게 만들 수 있습니다:

날짜    | 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

→ 누적 영역 차트로 시각화

CFD 활용 팁

1. 매일 업데이트

CFD는 매일 업데이트해야 의미가 있습니다.
자동화하면 더 좋고요.

2. 팀과 함께 분석

매주 금요일 CFD 리뷰:

- 이번 주 병목은 어디였나?
- 처리 속도가 변했나?
- 다음 주 예측은?

3. 다른 지표와 함께 보기

weekly_metrics = {
    "cfd_analysis": analyze_cfd(),
    "velocity": calculate_velocity(),
    "cycle_time": measure_cycle_time(),
    "burndown": check_burndown()
}

# 종합적인 건강 점수
health_score = calculate_project_health(weekly_metrics)

Little's Law와 CFD

CFD에서 Little's Law를 직접 볼 수 있습니다:

평균 리드 타임 = WIP / 처리량

예: WIP 20개, 일일 처리량 4개
→ 평균 리드 타임 = 20/4 = 5일

CFD에서 세로 거리가 WIP, 기울기가 처리량입니다.

마무리: CFD는 프로젝트의 심전도

의사가 심전도로 심장 상태를 보듯,
PM은 CFD로 프로젝트 상태를 봅니다.

번다운 차트가 "얼마나 남았나"를 보여준다면,
CFD는 "어떻게 흘러가고 있나"를 보여줍니다.

둘 다 필요하지만, CFD가 더 많은 것을 알려줍니다.

내일부터 CFD를 그려보세요.
프로젝트의 숨겨진 문제들이 한눈에 보일 겁니다.


실시간 CFD와 고급 프로젝트 분석이 필요하신가요? Plexo를 확인해보세요.