개발 현장에서 작업 완료 시간을 추정하는 일이 왜 어려운지, 그리고 이를 데이터 기반과 통계적으로 더 잘 수행하는 법을 다루는 심도 깊은 분석.
작업 완료 시간을 예측하는 것은 매우 중요한 일입니다. 하지만 이 작업은 많은 엔지니어와 소프트웨어 개발자들에게 큰 고통을 안겨주며, 개발팀과 경영진, 타 부서 및 고객 간에 상당한 마찰을 일으킵니다.
이유는 대부분의 사람들이 아직도 추정에 대해 잘못 이야기하고 있기 때문입니다.
아래는 실제로 있었던 이야기입니다.1
경험 많은 개발자 팀이 수년에 걸쳐 개발된 성숙한 소프트웨어 스택을 완전히 새로 다시 만드는 작업을 맡게 되었습니다. 기존 아키텍처는 한계에 다다랐고 회사의 성장을 방해하고 있었죠. 완전히 새로운 재설계가 필요했으며, 표면적으로는 하위 호환성을 유지하되 내부적으로는 완전히 달라야 했습니다. 모두가 어려운 일임을 알았지만, 팀은 모든 대안을 충분히 고려했고 이것이 최선임을 결정했습니다.
마케팅팀은 새 소프트웨어가 언제 출시될지 알고 싶어 했습니다. 개발팀은 최소 기능 제품(MVP)을 위한 로드맵을 짜고, 작업량을 계획하고, MVP까지 도달하는 데 걸릴 시간: 6개월이라고 추정했습니다.
결과적으로 2년 만에 출시됐습니다.
호프스태터의 법칙: 예상보다 항상 오래 걸린다. 호프스태터의 법칙까지 고려하더라도 마찬가지다.
— 더글러스 호프스태터
이런 일이 큰 문제였다는 건 말할 필요도 없습니다. 하지만 문제는 2년이라는 개발 시간이 아니었습니다. 회사는 지속 가능한 수익이 있었고, 긴 인큐베이션 기간 뒤에 기술적 도약이 충분히 가치 있을 것이라 믿었습니다.
진짜 피해는 추정치 자체에서 발생했습니다. 마케팅팀은 이 추정치를 ‘약속’으로 받아들였고, 곧바로 고객들에게 출시 일정을 알리기 시작했습니다. 판매 문의가 밀려들었고, 일부 고객은 그들의 고객사를 대상으로 별도로 계획을 세우기 시작했습니다. 마감일이 다가오고 제품이 준비되지 않자, 대대적인 수습이 필요했습니다.
고객도, 마케팅팀도, 회사도 불만이었고, 개발팀은 비난의 표적이 되었습니다.
무엇이 잘못된 걸까요?
이 팀은 정말 뛰어나고 생산적이며 잘 관리되는 효과적인 팀이었습니다. 제가 만난 개발자 중 가장 유능한 분들이었고, 팀으로서 각자의 합보다 훨씬 뛰어난 결과를 내는 기계 같았습니다. 누구도 더 빠르게, 더 잘 해낼 수 있었다고 생각하지 않습니다.
프로젝트 일정 지연 경험이 있다면 아마 “스코프 크립(scope creep)”을 떠올릴 겁니다. 즉, 프로젝트 중간에 새로운 작업이나 요구사항이 계속 추가되어 일정이 늘어나는 현상이죠. 실제로 그런 요인도 있었지만, 이번에는 “스코프 발견(scope discovery)”이 더 적합했습니다. 향후 필요를 충족할 기반을 새로 마련하려다 보니 과정에서 추가로 배우는 것이 항상 있기 마련입니다.
이미 말했듯, 개발자는 추정치를 ‘단순한 예측’ 정도로 여겼으나, 마케팅팀은 이를 ‘확약’으로 받아들였습니다. 전사적으로 용어를 명확히 하는 것이 신뢰 회복의 첫걸음이었습니다. 더 근본적인 문제는, 누구도 그 불확실성을 제대로 감안해서 추정하지 못했다는 점입니다. 개발자 본인도 마찬가지였죠.
IT 업계라면 이 이야기가 익숙할 겁니다. 추정한 일정이 실제로는 [너무 많이] 어긋나고, 개발팀은 곤경에 처하며, 스트레스를 받은 엔지니어들은 결국 "크런치" 타임에 시달리게 됩니다.
이런 사태는 Fibonacci 수, Story point, Planning poker, 간트 차트, 회고 등 여러 도구와 방법론을 써도 피하기 어렵습니다. 심지어 추정을 완전히 포기한 팀도 본 적이 있습니다. 희망을 가지세요!
여기에서 이야기가 전환점을 맞습니다. 팀은 위기를 성장의 기회로 만들기로 했습니다.
팀은 새롭게 과학적으로 추정을 개선해보기로 했습니다. 즉, 이전 추정과 실제 결과를 비교하는, 아마도 그 어느 회사보다 정밀한 데이터를 수집하기 시작했습니다. 그 데이터는 공유할 수 없지만,2 명확한 패턴을 설명드릴 수 있습니다.
2시간으로 추정된 작업들의 실제 소요 시간은 아래와 같았습니다:

5시간 추정 작업은 아래와 같습니다:

13시간 작업은 이렇게 나옵니다:

무엇이 눈에 띄시나요?
첫 번째로, 2시간 작업의 다수가 10시간이 걸린 것이 눈에 띄었습니다. 평균 또한 1.6배 정도 낙관적으로 잡혀 항상 스프린트 일정이 밀렸죠.3
팀원들은 예상보다 추정이 멀리 벗어난 점에 실망했지만, 데이터를 본 저는 오히려 이 추정이 굉장히 잘된 것이라는 인상을 받았습니다. 그만큼 개발자들이 자신이 맡은 작업에 대해 뛰어난 직감을 가지고 있었기 때문입니다.
특이한 점은, 추정치가 얼마이든 모든 그래프가 거의 똑같은 모양이라는 것입니다. 축의 단위를 지우면 구별할 수 없을 정도지요(비닝 크기만 다름).4 측정된 소요 시간을 추정치로 정규화하면, 모두 정확히 같은 분포를 가집니다. 즉, 개발자의 추정치는 완벽하진 않지만 무의미하지 않고, 어떤 분포의 스케일 파라미터 역할을 합니다.

그리고...
Jaynes에 따르면 확률분포는 인식의 상태와 대응한다고 합니다. 이번 분석을 통해, 숙련된 소프트웨어 개발자가 아직 시작 안 한 작업에 대해 가지는 인식 상태를 정확히 확인할 수 있었습니다. 비록 이 분포에 긴 꼬리가 있지만, 일관성이 놀랍습니다!
여러 꼬리가 긴 분포 중에도, 데이터에 의심스러울 만큼 잘 맞고 파라미터도 적은 게 있습니다. 바로 로그정규분포입니다. 게다가 모양 파라미터가 1, 위치파라미터 0인 아주 심플한 로그정규분포입니다. 이때 조절 파라미터는 단 하나, 스케일 파라미터 m이며, 바로 추정 완료 시간과 일치합니다. 그리고 이 분포의 평균은 m × 1.6이 됩니다.

즉, 숙련된 엔지니어의 추정치가 m일 때, 실제 소요 시간의 확률분포는 아래와 같습니다:

연구 결과 숙련 엔지니어가 자신이 맡은 작업을 신중히 생각할 때, 중앙값은 매우 정확하게 맞추는 것으로 나타났습니다. 믿기 어려울 정도로요.
문제는, 아무도 중앙값에 관심이 없다는 것입니다!
추정치는 본질적으로 '[확률분포]'이지만, 대개 소통하거나 혼자 생각할 때 [단순 수치]로 환산해 버립니다. 이 과정에서 중요한 뉘앙스가 사라집니다. 하나의 수치로 확률분포를 요약하는 방법은 유일하지 않기 때문에 오해가 생깁니다.
예시로, 이 글을 쓰는 데 4시간 걸릴 거라 개인적으로 예측했습니다.5
경영자도, 마케팅팀도, 고객도 추정치에 불확실성이 함께한다고 압니다. 하지만 각자 '하나의 숫자'를 원할 때는 _서로 다른 통계 요약_을 기대합니다. 각자의 질문에 맞는 답을 주는 게 효과적인 소통입니다.
마케팅팀이 추정치를 요구한다면, 그것을 약속할 수 있는 확실한 시간, 즉 99% 확률로 끝날 시간(99퍼센타일)을 원합니다. 즉, "4시간"이라고 들으면 바로 그 값이 99퍼센타일이라고 오해합니다. 숫자를 하나만 요청했고, 숫자 하나만 받았으니까요. 누구도 확률분포를 그려보며 대화하지 않았기에 생긴 일입니다.
스프린트 매니저라면 보통 _평균_을 원합니다. 할당한 작업이 다 평균적으로 소화되어 전체 일정 예측에 효과적이기 때문이죠.

이 표는 리스크 감수 여부(정확성 vs. 확실성)에 따라 추정치를 단일 숫자로 요약할 간단한 규칙을 줍니다.6
물론 보수적으로 잡아 Deal을 놓치는 게 더 리스크라면 10배 곱셈은 과할 수 있습니다. 어느 것을 선택하건, 상황에 따라 가장 적절히 균형 잡힌 답을 내는 건 각자의 몫입니다. 여러분에게 더 두려운 건 Deal 미스입니까, 아니면 마감 미스입니까?
이 결과가 모든 팀, 모든 프로젝트에 유효할까요? 아닐 수도 있습니다. 외부 벤더에서 장비를 주문하는 작업에는 지나친 낙관이 섞일 수 있습니다. 너무 익숙한 반복 작업에는 훨씬 더 정확한 추정이 가능합니다. 하지만 어느 정도의 탐색적 특성을 지닌 소프트웨어 프로젝트에서라면 훌륭한 출발점이 될 수 있습니다.
저 혼자만 이 현상을 봤다고 자신하진 않습니다. 이 독립적 분석도, 제가 공유하는 사내 분석과 일치합니다. 비슷한 결과를 다른 곳에서도 자주 목격합니다. 어쩌면 시스템적 원인이 있을까요?
정규분포(Gaussian)는 간단한 임의과정을 반복적으로 합산해 자연계 곳곳에서 발견됩니다. 로그정규분포는 이와 유사하게 곱하기 연산을 반복할 때 생깁니다.7
많은 작업이 작은 하위 작업들의 묶음이라면, 단순히 더해진다면 정규분포(종모양)를 따릅니다. 그러나 소프트웨어 개발에서는 버그를 해결하거나 기능을 작성할 때, 한 번에 해결되는 경우도, 여러 번 시행착오를 겪는 경우도 있죠. 코드리뷰 및 재수정 등 여러 단계가 반복될 수 있습니다. 이런 "for" 루프들은 곱좌수가 랜덤인 반복을 만들고, 쉽게 로그정규곡선을 만듭니다.8
또 무언가를 고치다 보면, 그 전에 먼저 고쳐야 할 것들이 발견되고, 실제로는 훨씬 큰 얼음산의 빙산의 일각인 경우도 생깁니다.
JIRA같은 관리 도구에서는 작업 단위를 "에픽", "스토리" 등 층위별로 정해두지만, 실제로 복잡한 프로젝트의 전체 작업 관계를 그리면 프랙탈처럼 미세하게 계속 뻗어나가는 구조임을 알게 됩니다.9

기술 업무에 흔한 로그정규분포는 이런 프랙탈스러운 구조와 잘 들어맞으며, 각 작업 아래에는 어디까지 이어질지 모르는 미지의 뿌리가 숨어 있음을 암시합니다. 얼마나 깊은지 알아내려면 파봐야 합니다.
이 글은 전문 엔지니어링 조언을 목적으로 하지 않습니다. 진지하게 엔지니어링 컨설팅을 원할 경우 저에게 연락해 주세요.
[1] 팀과 회사의 익명성을 위해 세부사항은 일부 생략, 변경되었습니다. 동의하에 공유합니다.
[2] 데이터 품질이 좋았던 이유는 특별한 보상 구조, 세금신고 때문에 매우 상세한 기록 요구 등 복합적 이유에서입니다. 실제 데이터는 거의 5분 단위로 정확하며, 미팅 등으로 자리를 비울 때 따로 기록됐습니다. 원본은 비공개이지만, 이 글의 메세지에는 충분합니다.
참고로 이 데이터는 실제로 작업한 '노동 시간' 기준입니다. 달력상의 소요 시간을 추정하고 싶다면, 작업에 총 투입되는 실제 시간을 따로 산정해야 합니다.
[3] 낙관성 1.6배는 개발자가 Hofstadter의 법칙을 염두에 두고 일부러 보정했음에도 여전했습니다.
[4] 여기선 실제로 당시 사용된 히스토그램을 그렸지만, 히스토그램은 bin size에 따라 인상이 쉽게 변하므로 제 취향은 아닙니다. 누적 분포함수(cdf)로도 비슷한 모양이 나옵니다.

확률밀도를 정말 그리고 싶으면 cdf의 도함수가 되지만, 이는 본래의 noisy 데이터로 돌아가는 일입니다. binning 대신 스무딩 필터로 노이즈를 줄이면 더욱 분명한 신호를 얻을 수 있습니다.
[5] 4는 Fibonacci 수가 아니지만, 추정 배경의 확률분포를 이해하는 것이 훨씬 더 중요합니다. 피보나치나 의미 있는 자리수에 맞추는 건 실제 오차 막대(에러 바)를 주는 것보다 의미 없습니다.
(실제로 글쓰기는 12시간이 걸렸습니다.)
[6] 평균이 1.6배인 이유? 분포의 평균/중앙값은 exp(½), 약 1.65배입니다.
[7] 참고로 로그정규분포는 여러 개 합산하더라도 꽤 오랜 동안 거의 lognormal 형태를 유지하다, 많은 수가 합산될 때에야 아주 천천히 정규분포로 수렴합니다.
[8] 대부분의 프로젝트 계획에서 "…그리고 두 번째 시도도 해야 할 것"이라고 발표하는 경우는 드뭅니다. GERT라는 (비인기) 방법론은 이런 재시도를 고려할 수 있도록 되어 있습니다.
[9] 모든 하위 작업의 연결 관계를 프로젝트 관리 소프트웨어상 그리기란 어렵고, 이 때문에 거의 대부분의 팀은 프로젝트를 거대한 의존 그래프로 한눈에 보는 경험이 없습니다. 그래도 몇 번쯤은 시도해볼 가치가 있습니다. 그게 실제 기술 작업의 모양을 파악하고 왜 계획한 일정대로 흘러가지 않는지 깨닫게 해주니까요.