cd ~/gh-pm-lab source pm-lab/env.sh
1무엇의 크기를 재는가
완료 날짜를 예측하려면 남은 일의 크기와 일하는 속도가 필요하다. 크기를 재는 방법은 네 가지로 나눌 수 있다.
| 방법 | 단위와 표준 | 누가, 언제 잴 수 있는가 | 척도와 주의할 점 |
|---|---|---|---|
| 기능 점수(function point) | IFPUG 방법(ISO/IEC 20926:2009). 입력, 출력, 조회, 내부·외부 파일을 세고 복잡도로 가중한다 | 훈련받은 측정자. 요구사항이 정해진 뒤 | 조직과 시스템 사이에 비교할 수 있도록 규칙을 표준으로 정했다. 계약과 생산성 비교에 쓰인다. 측정에 시간이 든다 |
| COSMIC 기능 크기 | COSMIC 방법(ISO/IEC 19761:2011). 데이터 이동(입력, 출력, 읽기, 쓰기)마다 1점 | 훈련받은 측정자. 기능 요구사항이 정해진 뒤 | 실시간 소프트웨어에도 쓴다. 복잡한 알고리즘의 크기는 재지 못한다 |
| 스토리 포인트(story point) | 팀이 정한 상대 크기(1, 2, 3, 5, 8 등) | 팀. 언제든 | 팀마다 단위가 달라 팀 사이에 비교할 수 없다. 배수 규칙을 지키지 않으면 순서 척도다(A1) |
| 업무 수 | 완료 조건이 있는 업무 이슈 1건 | 누구나. 이슈를 만들면 바로 | 업무 크기의 흔들림은 처리량의 흔들림에 들어간다. 업무를 쪼개는 방식이 바뀌면 단위가 바뀐다 |
실습 15의 몬테카를로 예측은 업무 수를 크기로, 주별 처리량을 속도로 썼다. 업무 크기를 따로 추정하지 않아도 되는 대신, 업무를 쪼개는 방식이 과거와 같다는 가정이 들어간다.
23점 추정과 PERT
업무마다 추정을 받는다면 값 하나보다 세 값을 받는다. 이를 3점 추정(three-point estimation)이라고 한다. 낙관 값 a, 가장 그럴듯한 값 m, 비관 값 b다. 1950년대 말 미 해군 폴라리스 계획에서 쓰고 맬컴(D. G. Malcolm) 등이 1959년 Operations Research에 발표한 PERT(Program Evaluation and Review Technique)는 업무 기간을 베타 분포로 보고 기대값 (a + 4m + b) ÷ 6, 표준편차 (b − a) ÷ 6을 쓴다. Launchpad 업무 6건의 추정 공수(schedule.tsv의 hours)를 m으로 두고, a와 b를 받았다고 가정해 계산한다.
awk -F'\t' 'NR > 1 { e = ($2 + 4 * $3 + $4) / 6; sd = ($4 - $2) / 6; se += e; sv += sd * sd; sm += $3
printf "%s 기대값 %.1fh, 표준편차 %.1fh\n", $1, e, sd }
END { printf "합계: m의 합 %.0fh, 기대값의 합 %.1fh, 표준편차 %.1fh, 정규 근사 85%% %.1fh\n", sm, se, sqrt(sv), se + 1.036 * sqrt(sv) }' <<'EOF'
key a m b
LP-01 8 12 24
LP-02 16 24 48
LP-03 24 32 64
LP-04 12 20 40
LP-05 12 16 32
LP-06 6 8 16
EOF
LP-01 기대값 13.3h, 표준편차 2.7h LP-02 기대값 26.7h, 표준편차 5.3h LP-03 기대값 36.0h, 표준편차 6.7h LP-04 기대값 22.0h, 표준편차 4.7h LP-05 기대값 18.0h, 표준편차 3.3h LP-06 기대값 9.0h, 표준편차 1.7h 합계: m의 합 112h, 기대값의 합 125.0h, 표준편차 10.8h, 정규 근사 85% 136.1h
가장 그럴듯한 값을 더한 112h는 실습 14의 BAC와 같다. 비관 값이 가장 그럴듯한 값에서 더 멀리 떨어져 있으므로 기대값의 합은 125.0h로 커진다. 합의 85%(136.1h)는 업무들이 서로 독립이고 합이 정규 분포에 가깝다고 보고 기대값 + 1.036 × 표준편차로 구했다. 이 가정에는 두 가지 약점이 있다. 한 업무가 늦어지는 원인(정책 결정 지연, 사람의 부재)은 다른 업무도 함께 늦추므로 업무들은 독립이 아니고, 독립을 가정하면 합의 표준편차가 작게 나온다. 또 추정하는 사람이 비관 값을 충분히 비관적으로 적지 않는다. 실습 14에서 Launchpad의 완료 시 예상 총공수(EAC)는 147h로, 이 계산의 85%(136.1h)보다도 컸다.
3계획 오류와 참조 집단
카너먼(D. Kahneman)과 트버스키(A. Tversky)는 1979년 글 “Intuitive prediction: Biases and corrective procedures”에서 계획 오류(planning fallacy)라는 이름을 붙였다. 사람은 비슷한 일이 과거에 대부분 늦었다는 것을 알면서도, 지금 하는 일에 대해서는 계획대로 진행되는 경우를 떠올려 낙관적으로 추정한다. 그들이 제안한 교정은 이 일의 세부(내부 관점, inside view)에서 출발하지 않고, 비슷한 일들의 실제 결과 분포(외부 관점, outside view)에서 출발하는 것이다.
플뤼비에르(B. Flyvbjerg)는 2006년 Project Management Journal에 실은 글에서 이 교정을 프로젝트에 쓰는 참조 집단 예측(reference class forecasting)을 세 단계로 정리했다. (1) 비슷한 과거 사업의 집단을 고른다. (2) 그 집단의 결과 분포(예: 계획 대비 실제 기간의 비)를 구한다. (3) 새 사업을 그 분포 안에 놓아 원하는 확신 수준에 맞는 기간을 정한다. 테틀록(P. Tetlock)과 가드너(D. Gardner)의 『Superforecasting』(2015)도 예측을 외부 관점에서 시작해 내부 관점으로 고치라고 권한다. Orbit 팀에게 참조 집단은 자기 팀의 지난 마일스톤이다. 그 기록이 다음 단계의 파일이다.
4예측 기록과 구간 적중률
키트의 samples/a-forecast-history.tsv는 Orbit 팀이 2025년 8월부터 남긴 마일스톤 예측 기록이다(합성 데이터). 마일스톤마다 시작하는 날 두 예측을 남겼다. “팀 추정”은 업무마다 받은 3점 추정을 합친 날짜와 마감일을 지킬 확률에 대한 팀의 판단이고, “처리량 MC”는 최근 12주 처리량으로 돌린 몬테카를로 결과다. 작업 폴더로 복사해 앞으로의 예측도 이 파일에 쌓는다.
cp github-pm-starter-kit/samples/a-forecast-history.tsv pm-lab/forecast-history.tsv sed -n '4,8p' pm-lab/forecast-history.tsv
id milestone method forecast_on remaining p10 p50 p90 deadline p_deadline actual added M01-E M01 팀 추정 2025-08-04 30 2025-08-18 2025-08-19 2025-08-22 2025-08-22 0.85 2025-08-22 2 M01-T M01 처리량 MC 2025-08-04 30 2025-08-21 2025-08-22 2025-08-26 2025-08-22 0.59 2025-08-22 2 M02-E M02 팀 추정 2025-08-25 26 2025-09-04 2025-09-08 2025-09-10 2025-09-05 0.60 2025-09-11 0 M02-T M02 처리량 MC 2025-08-25 26 2025-09-09 2025-09-10 2025-09-12 2025-09-05 0.00 2025-09-11 0
| 열 | 뜻 |
|---|---|
forecast_on, remaining | 예측한 날과 그때 남은 업무 수 |
p10, p50, p90 | 그 날짜까지 끝낼 확률이 10%, 50%, 90%라고 말한 날. P10~P90이 80% 구간이다 |
deadline, p_deadline | 이해관계자가 정한 마감일과, 그날까지 끝낼 확률이라고 말한 값 |
actual, added | 실제로 끝난 날, 예측한 뒤 끝날 때까지 더해진 업무 수. 아직 진행 중이면 빈칸 |
예측이 보정되어 있다(calibrated)는 것은 말한 확률과 실제 빈도가 맞는다는 뜻이다. “90% 확률로 이날까지”라고 말한 예측 열 개 중 아홉 개쯤은 그날까지 끝나야 하고, 열 개 모두 끝났다면 너무 비관적으로 말한 것이다. forecast-check.sh로 기록 전체를 점검한다.
결과를 아는 예측 24건(마일스톤 12개 × 2) 중 P90까지 끝난 것은 11건(46%)이다. 90%라고 말한 날짜가 절반도 지켜지지 않았다. 방법별로 나누면 차이가 크다.
| 숫자 | 기대 | 처리량 MC | 팀 추정 |
|---|---|---|---|
| P50까지 끝남 | 50% | 4/12 (33%) | 0/12 (0%) |
| P90까지 끝남 | 90% | 8/12 (67%) | 3/12 (25%) |
| P10~P90 사이 | 80% | 7/12 (58%) | 3/12 (25%) |
| 위 비율의 95% 신뢰구간 | 32%~81% | 9%~53% | |
| 실제 − P50 중앙값 | 0일 | 1.5일 | 8일 |
팀 추정은 12번 모두 P50보다 늦게 끝났고, 실제 완료일이 P50보다 중앙값으로 8일 늦었다. 계획 오류가 기록에 그대로 보인다. 처리량 MC는 덜 틀렸지만 역시 늦는 쪽으로 빗나갔다. 12건은 적은 수라 80% 구간 적중률의 95% 신뢰구간(confidence interval, 윌슨 방법)이 32%~81%로 넓다. 80%에 맞는지 아닌지를 이 기록만으로 단정할 수는 없지만, P50까지 끝난 비율이 4/12이고 빗나간 방향이 한쪽이라는 것은 말할 수 있다.
5브라이어 점수와 보정표
날짜 구간과 별도로, “마감일까지 끝낼 확률”처럼 한 사건의 확률로 말한 예측은 브라이어 점수(Brier score)로 잰다. 기상학자 브라이어(G. W. Brier)가 1950년 Monthly Weather Review에 제안한 점수로, 말한 확률 p와 결과 o(일어나면 1, 아니면 0)의 차이를 제곱해 평균한다. 0이 완벽하고, 늘 50%라고 말하면 0.25다. 위 출력에서 두 방법 모두 마감을 지킨 비율은 42%(12건 중 5건)였다.
| 묶음 | 말한 확률의 평균 | 브라이어 점수 | 기준 점수 | 기술 점수 |
|---|---|---|---|---|
| 처리량 MC | 61% | 0.288 | 0.243 | -0.19 |
| 팀 추정 | 83% | 0.401 | 0.243 | -0.65 |
기준 점수는 매번 실제 비율(42%)을 말했을 때의 점수이고, 기술 점수(skill score)는 1 − 브라이어 점수 ÷ 기준 점수다. 두 방법 모두 기술 점수가 음수다. 마일스톤마다 따로 계산한 확률이, 지난 결과의 비율을 그대로 말한 것보다 못했다. 보정표를 보면 이유가 보인다. 팀 추정은 11번 “80~100%”(평균 85%)라고 말했고 그중 5번만 마감을 지켰다. 처리량 MC도 “80~100%”(평균 95%)라고 말한 4번 중 2번만 지켰다. 확률을 높게 말할수록 틀렸을 때 점수를 크게 잃는다.
늘 “50%”라고 말하는 예측은 보정이 잘 되어 있을 수 있지만 쓸모가 없다. 브라이어 점수는 보정(말한 확률과 실제 빈도가 맞는가)과 분별(일어날 일과 일어나지 않을 일에 다른 확률을 말했는가)을 함께 반영한다. 적중률표는 어느 쪽으로 틀렸는지를, 브라이어 점수는 얼마나 틀렸는지를 보여 준다.
6참조 집단 보정과 범위 증가
출력의 “참조 집단 보정” 절은 플뤼비에르의 두 번째 단계다. 보정 계수 = (실제 완료일 − 예측한 날) ÷ (P50 − 예측한 날)이다. 처리량 MC의 계수는 중앙값 1.06, 80% 분위수 1.41이다. 새 처리량 MC 예측의 P50 기간에 1.41을 곱하면, 이 팀의 지난 12번 중 80%가 그 안에 끝났을 기간이 된다. 팀 추정의 80% 계수는 1.82로, 팀이 말한 P50 기간의 거의 두 배를 잡아야 했다.
처리량 MC가 늦는 쪽으로 빗나간 이유로 짐작할 수 있는 것 하나가 출력의 “범위 증가” 절에 있다. 마일스톤 12개에서 예측한 뒤 더해진 업무가 예측 때 남은 업무의 중앙값 15%, 80% 분위수 21%였다. 실습 15의 시뮬레이션은 남은 업무가 줄기만 한다고 가정했다. 마지막 줄의 --growth 값은 마일스톤마다 주당 더해진 업무 수이며, 다음 단계에서 시뮬레이션에 넣는다.
7몬테카를로 예측 고치기
Orbit 팀은 2026-09-07(월)에 다음 마일스톤 M14를 시작한다. 남은 업무는 45건, 이해관계자가 정한 마감일은 2026-10-09(금)이다. 처리량은 Orbit 로그의 주별 처리량을 쓴다. A2의 xmr.sh --tsv가 주별 값을 둘째 열에 준다. 키트의 forecast-scope.sh는 forecast.sh와 같은 난수 생성기를 쓰고, 세 가지를 더했다.
| 옵션 | 하는 일 | 값을 정하는 근거 |
|---|---|---|
--window N | 처리량 목록의 최근 N주만 뽑는다 | 관리도에서 공정이 안정된 기간(A2) |
--split LOW-HIGH | 시행마다 남은 업무에 LOW~HIGH 사이의 배수를 곱한다 | 지난 마일스톤에서 업무가 쪼개진 비율 |
--growth 목록 | 시뮬레이션의 매주 더해지는 업무 수를 목록에서 뽑는다 | forecast-check.sh의 마지막 줄 |
마지막 주는 남은 업무 ÷ 그 주 처리량으로 요일까지 나눠, 완료를 작업일 단위로 센다(forecast.sh는 주 단위로 센다). 네 가지 가정으로 차례로 돌린다.
| 가정 | P50 | P85 | 마감일까지 끝낼 확률 |
|---|---|---|---|
| 전체 27주 처리량 (실습 15의 방식) | 10-08(목) | 10-14(수) | 71% |
최근 12주 (--window 12) | 10-07(수) | 10-12(월) | 83% |
| 최근 12주 + 범위 증가 | 10-12(월) | 10-15(목) | 50% |
| 최근 12주 + 범위 증가 + 분할 1.0~1.2배 | 10-14(수) | 10-21(수) | 22% |
전체 27주에는 A2의 처리량 관리도에서 신호였던 3월 2일 주(1건)와 기록 초기의 3월 9일 주(4건)가 들어 있어, 최근 12주만 쓸 때보다 마감 확률이 12%p 낮다. 범위 증가를 넣으면 83%가 50%로 떨어진다. 지난 기록에서 범위 증가는 실제로 있었던 일이므로, 이 차이는 실습 15의 방식이 빠뜨린 몫이다. 분할 배수 1.0~1.2는 지난 기록에 근거가 없는 가정이며, 업무가 쪼개질 때 결과가 얼마나 민감한지 보려고 넣었다. 근거 없는 가정은 예측에 넣지 않고, 민감도로만 보고한다.
참조 집단 보정으로도 확인한다. 최근 12주 예측의 P50(10-07)은 시작일에서 30일 뒤다. 처리량 MC의 80% 보정 계수 1.41을 곱한다.
awk 'BEGIN { printf "%.0f\n", 30 * 1.41 }'
date -u -d "2026-09-07 + 42 days" +%F 2>/dev/null || date -u -j -v+42d -f %F 2026-09-07 +%F
42 2026-10-19
참조 집단으로 보정한 80% 날짜는 10월 19일이다. 범위 증가를 넣은 시뮬레이션의 P85(10월 15일)보다 늦고, 최근 12주만 쓴 시뮬레이션의 P85(10월 12일)보다는 더 늦다. 두 교정 모두 실습 15의 방식보다 늦은 날짜를 가리킨다.
처리량 몬테카를로는 업무를 건수로만 보고, 업무 사이의 선후 관계를 쓰지 않는다. 일정 위험 분석(schedule risk analysis, SRA)은 일정망(실습 13의 주경로 계산)의 업무마다 기간 분포를 주고, 선후 관계를 따라 완료일 분포를 시뮬레이션한다. 휼렛(D. Hulett)의 『Practical Schedule Risk Analysis』(2009)가 이 방법을 정리했다. 업무 수가 많고 서로 독립에 가까우면 처리량 방법이, 업무 수가 적고 주경로가 분명하면 SRA가 맞는다. 두 방법 모두 입력 분포가 과거와 같다는 가정 위에 있으므로, 이 모듈의 보정 기록으로 결과를 점검한다.
8예측을 기록하고 보정하는 운영
예측은 내놓을 때 기록해야 나중에 보정할 수 있다. --record는 표 대신 예측 기록 형식의 한 줄을 출력한다. 방법 이름을 바꿔 새 방식의 예측을 따로 묶는다.
기록한 예측은 결정 기록 댓글(실습 10)로 마일스톤의 운영 이슈에도 남긴다. 숫자와 함께 가정을 적어야, 마일스톤이 끝난 뒤 어느 가정이 틀렸는지 찾을 수 있다.
gh issue comment "$PM_SPRINT_URL" --body-file - <<'EOF' **결정 기록** - 일시: 2026-09-07 10:30 - 결정: M14 완료 예측을 P50 10-12(월), P85 10-15(목), 10-09 마감까지 50%로 보고한다. 마감을 지키려면 범위를 줄이는 안을 함께 올린다. - 이유: 최근 12주 처리량과 지난 12개 마일스톤의 주당 범위 증가로 시뮬레이션했다(forecast-scope.sh, 시드 42). 참조 집단 보정(P50 기간 × 1.41)으로는 80% 날짜가 10-19다. - 가정: 처리량 분포가 6~8월과 같다. 업무 분할은 넣지 않았다(분할 1.0~1.2배면 마감 확률 22%). - 결정자: PM - 관련: pm-lab/forecast-history.tsv의 M14-20260907 EOF
마일스톤이 닫히면 실제 완료일과 더해진 업무 수를 기록의 빈칸에 채운다. 마일스톤의 닫힌 날짜는 REST API의 closed_at에 있다. 더해진 업무 수는 마일스톤의 이슈 중 생성 시각이 예측한 날 뒤인 이슈의 수다.
gh api "repos/$PM_REPO/milestones?state=closed" --jq '.[] | [.title, .closed_at] | @tsv' gh issue list -R "$PM_REPO" --milestone "M14" --state all --limit 500 --json createdAt \ --jq '[.[] | select(.createdAt > "2026-09-07")] | length'
마일스톤이 끝날 때마다 forecast-check.sh를 다시 돌려 결과를 위키(실습 17)의 예측 보정 페이지에 붙인다. 적중률과 보정 계수가 바뀌면 팀의 추정 규칙도 고친다.
날짜를 말하기 전에 팀과 사전 부검(pre-mortem)을 한다. 클라인(G. Klein)이 2007년 Harvard Business Review에 소개한 방법이다. “M14가 10월 9일을 크게 넘겨 끝났다”고 이미 일어난 일처럼 말하고, 참석자가 각자 2분 동안 그 이유를 적은 뒤 하나씩 돌아가며 말한다. 나온 이유는 예측의 입력과 위험 등록부로 옮긴다.
| 사전 부검에서 나온 이유 (예) | 옮길 곳 |
|---|---|
| QA에서 결함이 몰려 업무가 늘었다 | --growth 값을 지난 기록의 큰 쪽으로 바꿔 민감도를 본다 |
| 정책 결정이 늦어 engineering 업무가 막혔다 | 위험 등록부(실습 16). 막힘 대기를 매주 확인한다(실습 28의 개선안 A) |
| 10월 초 연휴로 처리량이 줄었다 | 연휴 주의 처리량을 낮춰 넣은 시뮬레이션을 하나 더 돌린다 |
팀의 추정 규칙은 이 모듈의 결과를 한 장으로 적은 것이다.
**팀의 추정 규칙** (2026-09-07 정함) - 날짜 예측은 처리량 몬테카를로로 한다. 업무별 3점 추정은 업무를 나누고 순서를 정하는 데 쓰고, 합쳐서 날짜를 만들지 않는다 - 표본: 처리량 관리도에서 신호가 없는 최근 12주. 신호가 난 주는 원인을 확인한 뒤 뺄지 정한다 - 범위 증가: forecast-check.sh의 --growth 값을 넣는다. 분할 배수는 근거가 생길 때까지 민감도로만 보고한다 - 말하는 값: P50과 P85, 마감일까지 끝낼 확률. 날짜 하나만 말하지 않는다 - 기록: 예측할 때마다 forecast-scope.sh --record로 pm-lab/forecast-history.tsv에 더하고, 같은 내용을 결정 기록 댓글로 남긴다 - 보정: 마일스톤이 닫힐 때 actual과 added를 채우고 forecast-check.sh를 돌려 위키에 붙인다. P90까지 끝난 비율이 3분기 연속 80% 아래면 표본과 범위 증가 가정을 다시 정한다 - 사전 부검: 마일스톤 시작 회의에서 10분
막히면
| 증상 | 확인과 해결 |
|---|---|
오류: 열이 없다: ... | 첫 줄(# 줄 다음)이 열 이름이어야 하고, 열 구분은 탭이다. 스프레드시트에서 저장했다면 탭 구분 텍스트로 저장했는지 확인한다 |
오류: 날짜 형식이 맞지 않는 줄 | 날짜는 2026-09-07 형식이다. 스프레드시트가 2026. 9. 7.로 바꿨을 수 있다 |
--window(12)가 처리량 목록의 주 수(8)보다 크다 | 처리량 목록이 짧다. flow-metrics.sh --weeks를 늘리거나 --window를 줄인다 |
범위 증가가 처리량보다 커서 ... 끝나지 않는 시행 | 주당 더해지는 업무가 처리하는 업무보다 많다. 이 경우 날짜 예측보다 범위 결정이 먼저다 |
date: invalid date | macOS에서는 date -j -v+42d -f %F 2026-09-07 +%F를 쓴다. 위 명령은 두 방식을 차례로 시도한다 |
- 기능 점수, COSMIC, 스토리 포인트, 업무 수의 척도와 쓰는 곳을 구분했다.
- PERT로 업무 6건의 기대값과 합의 85%를 계산하고, 독립 가정의 약점을 설명할 수 있다.
- 예측 기록으로 두 방법의 구간 적중률과 브라이어 점수를 계산하고, 어느 쪽으로 틀렸는지 말할 수 있다.
- 참조 집단 보정 계수로 새 예측의 80% 날짜를 계산했다.
- 표본 기간, 범위 증가, 분할을 바꿔 M14의 마감 확률이 어떻게 달라지는지 확인했다.
- M14 예측을 기록 파일과 결정 기록 댓글로 남기는 방법을 알고, 팀의 추정 규칙을 적었다.
마치며...
예측은 확률로 말하고, 기록하고, 결과와 맞춰 볼 때 고칠 수 있다. Orbit의 지난 예측은 두 방법 모두 늦는 쪽으로 빗나갔고, 팀 추정은 12번 모두 P50보다 늦었다. 처리량 몬테카를로에 지난 기록의 범위 증가를 넣자 M14의 마감 확률은 83%에서 50%로 내려갔고, 참조 집단 보정도 같은 쪽을 가리켰다. 다음 모듈에서는 개선을 적용한 뒤 달라진 숫자 중 개선 때문인 부분을 대조군과 시계열로 떼어 내고, 끝나지 않은 사례를 버리지 않고 분포를 추정한다.