본문 바로가기

일정·의존성·위험

작업 선행 관계와 임계 경로를 계산하고 위험의 가능성·영향·대응·발동 조건을 기록합니다.

네 작업의 기간을 더하면 5단위지만 병렬로 수행할 수 있는 작업이 있습니다. 반대로 모두 동시에 시작할 수는 없습니다. 의존성은 어떤 작업이 다른 결과를 먼저 필요로 하는 관계입니다.

가장 이른 종료 계산

A 정책 합의 1, B 코어 구현 2, C 안내 작성 1, D 통합 검토 1의 가상 단위를 사용합니다. B와 C는 A 뒤에, D는 B와 C 뒤에 시작합니다. 실제 교재 제작 기간 예측이 아닌 계산 연습입니다.

duration은 작업의 가상 소요 시간입니다. 처음에는 각 작업에 전담 작업자 한 명이 해당 기간 내내 참여하고 B와 C에는 서로 다른 작업자를 배치할 수 있다고 가정합니다. 이 가정에서만 기간 합 1+2+1+1=5를 사람·시간 단위의 노력 합으로 읽습니다. 대기·휴무·인수 비용은 생략합니다. 작업마다 인원이 다르거나 일부 시간만 참여하면 기간 합과 노력 합은 같지 않습니다.

분기 작업을 모두 기다리는 합류가 완료를 결정한다

선행 작업이 없는 A를 진행한다. 두 선행 작업이 끝난 뒤 D를 진행한다. 각 단계의 값과 전환 이유를 비교합니다.

SOFTWARE ENGINEERING · READING CLUB

분기 작업을 모두 기다리는 합류가 완료를 결정한다

화살표는 선행 제약입니다. 자원이 충분하면 B와 C는 함께 시작하며, D는 둘의 완료를 기다립니다.

분기 작업을 모두 기다리는 합류가 완료를 결정한다A정책1단위 뒤 B코어2단위와 C안내1단위가 병렬입니다. D통합1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원 충분 가정에서 A B D 경로4단위, 노력합5단위입니다. A 정책1단위 · 0→1B 코어2단위 · 1→3C 안내1단위 · 1→2D 통합1단위 · 3→4
분기 작업을 모두 기다리는 합류가 완료를 결정한다A정책1단위 뒤 B코어2단위와 C안내1단위가 병렬입니다. D통합1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원 충분 가정에서 A B D 경로4단위, 노력합5단위입니다. A 정책1단위 · 0→1B 코어2단위 · 1→3C 안내1단위 · 1→2D 통합1단위 · 3→4

강조된 A→B→D의 기간은 4단위, A→C→D는 3단위입니다. B와 C의 배치 위치는 직렬 수행을 뜻하지 않습니다. B·C를 같은 한 사람만 맡으면 5단위가 되는 계산은 본문에서 따로 추적합니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 t0 정책 시작부터 t3→4 합류까지 진행합니다.
관계도의 보충 설명
전체 도표의 표기·관계·조건
구분전체 도표의 내용
관계 설명A 정책 1단위 뒤 B 코어 2단위와 C 안내 1단위가 병렬입니다. D 통합 1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원이 충분하다는 가정에서 A B D 경로는 4단위, 노력 합은 5단위입니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
t0 정책 시작

선행 작업이 없는 A를 진행한다.

  • 작업·시각 1: A [0,1]
  • 작업·시각 2: B,C,D 대기
  • A 시작
t1 병렬 시작

A가 끝나면 B와 C를 함께 시작한다.

  • 작업·시각 1: B [1,3]
  • 작업·시각 2: C [1,2]
  • B,C 실행
t2 한 갈래 완료

C가 끝나도 D는 B를 기다린다.

  • 작업·시각 1: C 완료
  • 작업·시각 2: B 실행
  • 작업·시각 3: D 대기
  • C만 완료
t3→4 합류

두 선행 작업이 끝난 뒤 D를 진행한다.

  • 작업·시각 1: D [3,4]
  • 작업·시각 2: 기간 4
  • 작업·시각 3: 노력 합 5
  • 프로젝트 완료; 공유 작업자 별도 사례는 기간 5

분기 작업을 모두 기다리는 합류가 완료를 결정한다

선행 작업이 없는 A를 진행한다. 두 선행 작업이 끝난 뒤 D를 진행한다. 각 단계의 값과 전환 이유를 비교합니다.

SOFTWARE ENGINEERING · READING CLUB

분기 작업을 모두 기다리는 합류가 완료를 결정한다

화살표는 선행 제약입니다. 자원이 충분하면 B와 C는 함께 시작하며, D는 둘의 완료를 기다립니다.

분기 작업을 모두 기다리는 합류가 완료를 결정한다A정책1단위 뒤 B코어2단위와 C안내1단위가 병렬입니다. D통합1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원 충분 가정에서 A B D 경로4단위, 노력합5단위입니다. A 정책1단위 · 0→1B 코어2단위 · 1→3C 안내1단위 · 1→2D 통합1단위 · 3→4
분기 작업을 모두 기다리는 합류가 완료를 결정한다A정책1단위 뒤 B코어2단위와 C안내1단위가 병렬입니다. D통합1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원 충분 가정에서 A B D 경로4단위, 노력합5단위입니다. A 정책1단위 · 0→1B 코어2단위 · 1→3C 안내1단위 · 1→2D 통합1단위 · 3→4

강조된 A→B→D의 기간은 4단위, A→C→D는 3단위입니다. B와 C의 배치 위치는 직렬 수행을 뜻하지 않습니다. B·C를 같은 한 사람만 맡으면 5단위가 되는 계산은 본문에서 따로 추적합니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 t0 정책 시작부터 t3→4 합류까지 진행합니다.

관계도의 보충 설명

전체 도표의 표기·관계·조건
구분전체 도표의 내용
관계 설명A 정책 1단위 뒤 B 코어 2단위와 C 안내 1단위가 병렬입니다. D 통합 1단위는 둘 다 끝나야 시작합니다. 선행 변은 A B, A C, B D, C D 네 개입니다. 자원이 충분하다는 가정에서 A B D 경로는 4단위, 노력 합은 5단위입니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
t0 정책 시작

선행 작업이 없는 A를 진행한다.

  • 작업·시각 1: A [0,1]
  • 작업·시각 2: B,C,D 대기
  • A 시작
t1 병렬 시작

A가 끝나면 B와 C를 함께 시작한다.

  • 작업·시각 1: B [1,3]
  • 작업·시각 2: C [1,2]
  • B,C 실행
t2 한 갈래 완료

C가 끝나도 D는 B를 기다린다.

  • 작업·시각 1: C 완료
  • 작업·시각 2: B 실행
  • 작업·시각 3: D 대기
  • C만 완료
t3→4 합류

두 선행 작업이 끝난 뒤 D를 진행한다.

  • 작업·시각 1: D [3,4]
  • 작업·시각 2: 기간 4
  • 작업·시각 3: 노력 합 5
  • 프로젝트 완료; 공유 작업자 별도 사례는 기간 5

간트 차트는 작업을 시간축의 막대로 표현합니다. 네트워크 계획은 선행 관계를 표현하고 임계 경로는 여유 없이 전체 완료를 결정하는 경로입니다. 이 예시는 A→B→D가 4단위로 가장 길고 C에는 1단위 여유가 있습니다. 자원이 충분하다는 가정을 제거하면 병렬 실행도 달라집니다.

examples/ch8.mjs를 저장하고 실행합니다.

import assert from "node:assert/strict";

// Durations are toy planning units, not estimates for a real project.
const tasks = [
  { id: "A", duration: 1, after: [] },
  { id: "B", duration: 2, after: ["A"] },
  { id: "C", duration: 1, after: ["A"] },
  { id: "D", duration: 1, after: ["B", "C"] },
];
const finish = new Map();
for (const task of tasks) {
  if (task.after.some((id) => !finish.has(id))) throw new Error("tasks must be topologically ordered");
  const start = Math.max(0, ...task.after.map((id) => finish.get(id)));
  finish.set(task.id, start + task.duration);
  console.log(task.id, start, finish.get(task.id));
}
assert.equal(finish.get("D"), 4);
console.log("total effort units", tasks.reduce((sum, task) => sum + task.duration, 0));

const optimistic = 2, likely = 4, pessimistic = 8;
console.log("PERT teaching estimate", (optimistic + 4 * likely + pessimistic) / 6);

결과는 A 0→1, B 1→3, C 1→2, D 3→4이며 노력 단위 합은 5입니다. 코드는 작업을 선행 작업보다 뒤에 배치한 순서를 전제로 합니다. 선행 작업이 없으면 오류를 냅니다. 순환 의존성을 자동으로 해결하거나 자원 배치를 최적화하는 일정 도구는 아닙니다.

Map은 작업 ID와 종료 시각을 짝지어 저장합니다. has는 이미 계산했는지 확인하고, get은 그 시각을 꺼내며, set은 새 종료 시각을 기록합니다. after.map(...)은 선행 작업들의 종료 시각 목록을 만들고 Math.max(0, ...목록)은 그중 가장 늦은 시각을 선택합니다. reduce는 각 기간을 누적해 더하며, 노력으로 해석하는 인력 가정은 앞에 따로 적었습니다.

PERT의 전통적인 3점 가중 추정은 (낙관 + 4×보통 + 비관) / 6을 사용합니다. 예제의 2·4·8은 계산용 값이며 마지막 출력은 약 4.33입니다. 가능성 분포를 그렇게 가정한 추정이지 확정 완료 시각이나 실제 평균 관측값이 아닙니다. CPM의 고정 기간 계산과 통계적 가정을 구분합니다.

전진·후진 계산으로 여유까지 추적한다

앞 코드의 finish는 각 반복에서 {A:1}, {A:1,B:3}, {A:1,B:3,C:2}, {A:1,B:3,C:2,D:4}처럼 누적됩니다. C를 계산할 때 B의 종료 시각 3을 사용하지 않는 이유는 C의 선행 목록이 A뿐이기 때문입니다. D는 두 선행 결과를 모두 기다려 max(3,2)=3에서 시작합니다.

ES/EF는 가장 이른 시작/종료, LS/LF는 전체 완료 시각 4를 늦추지 않는 가장 늦은 시작/종료입니다. 앞에서 뒤로 ES=max(선행EF), EF=ES+기간을 구합니다. 뒤에서 앞으로는 마지막 작업의 LF를 완료 시각 4로 두고 LF=min(후행LS), LS=LF−기간을 구합니다. 총여유는 LS−ES입니다. 동일 시간축·자원이 충분하다는 가정을 유지해야 합니다.

작업전진 근거ESEF후진 근거LSLF총여유
A선행 없음01min(B LS 1,C LS 2)=1010
BA EF 113D LS 3130
CA EF 112D LS 3231
Dmax(B EF 3,C EF 2)=334프로젝트 완료 시각 4340

후진 순서는 D→C→B→A입니다. C를 1단위 늦춰 2에 시작해 3에 끝내도 D는 3에 시작할 수 있습니다. 여유가 0인 A→B→D는 이 조건에서 임계 경로입니다. 기간이 같은 일을 여러 사람이 맡는다고 이 표의 duration을 자동으로 나누지 않습니다.

같은 선후 관계에서 자원 때문에 기다리는 경우

B와 C가 같은 작업자 editor를 사용하고 B부터 맡는다고 정합니다. 작업을 중간에 끊지 않는다는 가정도 추가합니다. 선행 작업 완료 시각과 자원 사용 가능 시각의 큰 값에서 시작합니다.

작업선행 완료로 가능한 시각배정 자원 사용 가능실제 시작실제 종료
A0001
B1013
C1334
D4045

C는 A가 끝나도 작업자가 B를 하는 동안 기다립니다. D의 시작도 4로 바뀝니다. 이 네 작업에서는 B/C가 모두 A 뒤·D 앞에 있고 한 사람이 둘을 해야 하므로 1+2+1+1=5가 필요한 하한이자 이 배정으로 달성한 완료 기간입니다. 일반적인 큰 그래프에 이 고정 순서를 적용하면 항상 최적이라는 뜻은 아닙니다. 자원 제약을 넣은 후에는 원래 여유 표를 그대로 재사용하지 않습니다.

전진·후진과 자원 표를 만드는 실행 코드는 docs/cs-textbooks/software-engineering-lab/deepening.mjs의 schedule 및 scheduleOneWorkerPerResource입니다. 첫 함수는 입력을 위상 순서로 구성하고 누락된 선행·순환을 거절합니다. 둘째는 그 순서에서 자원별 한 작업자의 사용 가능 시각을 누적하는 고정 우선순위 모델이며 최적화기가 아닙니다. 저장소 최상위에서 아래 명령을 실행합니다.

node docs/cs-textbooks/software-engineering-lab/run-deepening.mjs
node --test docs/cs-textbooks/software-engineering-lab/deepening.test.mjs

첫 출력의 duration은 4, 공유 작업자 출력의 duration은 5입니다. C의 기간을 3으로 바꾸면 충분한 자원에서는 A→C→D가 완료 시각 5를 결정하고 B의 여유는 1로 바뀝니다. 모든 duration은 가상 시간 단위입니다.

위험과 이슈

위험은 아직 일어나지 않은 불확실한 사건이고 이슈는 이미 해결이 필요한 문제입니다. 위험 기록에는 가능성, 영향, 대응, 담당, 발동 조건을 남깁니다.

위험영향대응담당 역할관찰·발동 조건
기한까지 취소 정책을 확정하지 못함안내·코어·테스트 재작업초기 수락 사례로 합의업무 정책 담당정책 검토 기한 경과
저장 계약 불일치명단 복구 실패버전·유효성 통합 실험저장 계약 담당복원 실패 또는 중복 ID
외부 서비스 지연일정·업무 중단제외 범위·대체 흐름 합의외부 연동 담당계약 응답 기한 경과

현재 취소 정책이 미확정이라는 사실은 해결해야 할 이슈입니다. 향후 합의 기한을 넘겨 안내·구현을 재작업하게 될 가능성은 위험으로 기록합니다. 이미 기한을 넘겨 재작업이 필요해졌다면 그때는 이슈로 전환합니다.

가능성과 영향의 점수를 곱해 우선순위를 보기도 하지만 서열 점수의 산술만으로 피해량을 정확히 계산했다고 주장하지 않습니다. 회피·완화·전가·수용 같은 대응은 어떤 비용과 잔여 위험이 생기는지 함께 적습니다. 위험을 수용해도 담당과 관찰 조건은 남습니다.

독립 문제: 사람 한 명만 있다면

예제의 B와 C를 같은 사람이 수행해야 합니다. 전체 기간과 임계 경로 설명은 어떻게 달라질까요? C 기간이 1에서 3으로 늘어나는 경우도 각각 판단하세요.

힌트

코드의 계산은 선행 관계만 보고 자원 제약을 보지 않습니다.

해설

한 사람이 B와 C를 순서대로 하면 A 1 + B 2 + C 1 + D 1 = 5단위가 필요합니다. 자원이 충분하고 C가 3이라면 A→C→D가 5단위로 완료를 결정합니다. 한 사람만 있고 C가 3이라면 합계 7단위입니다. 같은 선행 관계에서도 자원 가정과 기간이 바뀌면 완료가 달라집니다.

추가 문제: 기간은 같고 인원이 다른 경우

B에는 두 사람이 2시간 단위 내내 참여하고 나머지는 각 한 사람이라고 가정합니다. B 기간은 여전히 2이며 병렬 C와 선행 관계도 그대로입니다. 완료 기간과 노력 합을 각각 계산하세요. B 인원을 늘렸다는 이유만으로 B 기간을 1로 바꿀 수 있는지도 설명합니다.

힌트와 해설

완료 기간은 선행 관계의 A→B→D에 따라 여전히 4입니다. 노력은 A의 1×1, B의 2×2, C의 1×1, D의 1×1을 더해 7 사람·시간 단위입니다. 두 사람의 참여로 기간이 줄었다는 관측이나 작업 분할 근거가 없으므로 B 기간을 임의로 1로 바꾸지 않습니다. 기간·참여 인원·참여 비율을 별도로 기록해야 다른 계획과 비교할 수 있습니다.

일정표는 계획의 현재 가정입니다. 실제 관찰과 위험 변화가 생기면 범위·자원·순서를 검토하고 새 근거를 남깁니다.