홈시리즈멘토링

© 2026 정기창. All rights reserved.

본 블로그의 콘텐츠는 CC BY-NC-SA 4.0 라이선스를 따릅니다.

☕후원하기소개JSON Formatter러닝 대기질개인정보처리방침이용약관

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

☕후원하기
소개|JSON Formatter|러닝 대기질|개인정보처리방침|이용약관

공수 산정 (4) 재사용할 코드가 63시간어치 있었는데 견적은 28% 올랐습니다

정기창·2026년 7월 22일

어떤 외주 건의 견적을 다시 잡으면서 스스로에게 남은 질문이 하나 있었습니다.

"내 모노레포에 이미 비슷한 게 많은데, 재사용하면 그만큼 빨라지지 않나?"

그럴듯한 질문이었습니다. 인증도 잡큐도 커넥터 레지스트리도 이미 여러 번 만들어 봤으니까요. 같은 것을 또 만들 이유가 없다면 견적은 내려가야 맞습니다. 그래서 추측으로 답하지 않기로 하고 코드베이스를 실사했습니다. 파일과 줄 번호까지 근거를 대야 자산으로 인정하는 규칙을 걸어 두고, 재사용할 수 있는 것을 전부 찾았습니다.

찾았습니다. 63시간어치.

  • 인증 모듈 — 이미 네 번 복제해서 이번이 다섯 번째라 사실상 복붙이었습니다
  • 커넥터 플러그인 레지스트리 — 완성형이 이미 운영 중이었습니다
  • 기여도 가중치 테이블 — 알고리즘 버전 태그와 멱등 upsert 선례가 있었습니다
  • 쿼터 가드 — 조건부 UPDATE로 TOCTOU를 회피한 구현이 있었습니다

63시간은 결코 작은 숫자가 아닙니다. 그러니 견적이 내려가야 정상입니다. 그런데 이 범위의 견적은 오히려 28% 올랐습니다.

28%에는 원인이 둘 있었습니다

먼저 정리해 둘 것이 있습니다. 이 28%는 1편에 적은 그 28%와 같은 숫자입니다. 축소 범위 견적이 107시간에서 137시간으로 올라간 그 차이입니다.

같은 숫자인데 원인은 둘이었습니다. 1편에서 다룬 것은 출발점이 잘못돼 있었다는 쪽입니다. 107시간은 작업량을 재서 나온 값이 아니라 예산을 시급 하한으로 나눈 값이었고, 그러니 애초에 추정이 아니었습니다. 이 글에서 다룰 것은 다른 쪽입니다. 제대로 다시 쟀을 때 왜 하필 위로 벌어졌는가. 재사용 자산을 63시간어치나 반영하고도 올랐다면 그 이유는 따로 설명돼야 합니다.

뜯어보니 세 가지였습니다. 그리고 셋 다 제가 재사용 자산이라는 것에 대해 갖고 있던 생각을 바꿨습니다.

① 자산이 몰린 곳은 전체에서 비중이 작은 영역이었습니다

인증, 레지스트리, 잡큐. 자산은 실재했고 이 항목들은 실제로 싸졌습니다. 다만 이 영역이 애초에 전체에서 차지하는 비중이 작았습니다.

절감액이 작았던 게 아니라 절감이 일어난 자리가 작았습니다. 이 둘은 다릅니다. 63시간을 아꼈다는 사실과 그 63시간이 전체에서 몇 퍼센트인가는 별개의 이야기이고, 견적을 움직이는 건 후자입니다.

② 견적이 튀는 곳은 grep 결과가 전부 "선례 0"이었습니다

견적이 크게 잡힌 항목들을 하나씩 검색해 봤습니다. 쿼리 레벨 테넌트 스코프 강제, 점수 요인 정의, 인용 파싱, 부호 있는 기여도 분해. 전부 선례가 없었습니다.

여기서 구조가 보였습니다. 한 번도 안 해본 것이니 견적이 크게 잡힌 것이고, 한 번도 안 해봤으니 재사용할 자산도 없는 것입니다. 같은 이유가 양쪽에 동시에 작용합니다. 비중이 큰 곳에는 재사용 이득이 아예 없었고, 재사용 이득이 있는 곳은 비중이 작았습니다. 그래서 총량이 올랐습니다.

돌이켜 생각해보면 이건 당연한 구조였습니다. 재사용 자산이 있다는 건 그 영역을 이미 여러 번 지나왔다는 뜻이고, 여러 번 지나온 영역은 애초에 무섭지 않습니다. 견적을 튀게 만드는 건 언제나 처음 가는 곳입니다.

③ 자산은 전부 '이식'이지 '복사'가 아니었습니다

찾아낸 자산은 다른 DB, 다른 레포에 있었습니다. 파일을 통째로 가져다 붙일 수 있는 게 아니라 옮겨 심어야 하는 것들이었습니다. 그러면 절감의 실체는 무엇이었을까요.

코드가 아니라 "이미 밟은 함정을 다시 안 밟는다"였습니다. 멱등 upsert를 어디서 놓치는지 알고 TOCTOU가 어느 순간에 열리는지 알고 있다는 것 — 절감되는 건 타이핑이 아니라 재발견입니다. 그리고 그건 63시간만큼 크지 않았습니다.

그리고 그 버그가 제 레포에 이미 있었습니다

실사 과정에서 예상하지 못한 것을 하나 발견했습니다. 부끄럽지만 적어 두는 게 맞다는 생각이 들었습니다.

이 프로젝트의 요구사항 중에 "모든 점수는 원시 데이터까지 역추적 가능해야 한다"가 있었습니다. 블랙박스 점수를 금지하겠다는 뜻입니다. 그런데 제 코드베이스의 어떤 점수 서비스를 들여다보니 —

  • 저장하는 값은 원본인데 산식이 쓰는 값은 로그 변환을 거친 값이었습니다. 둘이 달랐습니다.
  • 곱셈 요인 다섯 개 중 두 개는 아예 저장되지 않았습니다.

결과적으로 저장된 요인을 아무리 분해해도 그 점수를 재구성할 수 없었습니다. 이 프로젝트가 금지하려던 바로 그 "블랙박스 점수"가 제 레포에 실재하고 있었습니다.

애석하게도 남의 얘기가 아니었던 셈입니다. 다만 이 발견에는 쓸모가 있었습니다. 이 버그 클래스가 실제로 쓰기 쉽다는 증거였으니까요. "역추적 가능하게 만드는 데 왜 그렇게 시간이 드느냐"는 질문에 저는 이제 제 레포를 예로 들 수 있습니다. 조심하지 않으면 이렇게 됩니다, 그리고 저는 조심하지 않았습니다.

정리하며

이번 실사에서 남은 것은 세 가지입니다.

첫째, 재사용 자산은 추측하지 말고 실사해야 합니다. 흥미로운 건 실사의 효과가 "견적이 내려간다"가 아니라 "견적이 정확해진다"라는 점입니다. 내려갈 수도 있고 올라갈 수도 있습니다. 저는 올라갔습니다.

둘째, "선례 0"인 곳이 견적이 튀는 곳입니다. grep이 아무것도 잡지 못하는 영역을 찾아내는 작업이 그대로 리스크 지도가 됩니다. 이건 견적을 넘어서 쓸 데가 있는 도구라는 생각이 들었습니다.

셋째, 재사용의 실체는 코드가 아니라 함정 목록입니다. 그리고 함정 목록은 코드보다 훨씬 얇습니다. "예전에 만들어 봤으니 금방 하죠"라고 말할 때 제가 실제로 팔고 있던 것이 무엇이었는지 이번에 알았습니다.

다음 편에서는 범위를 다시 전체로 넓히겠습니다. 이 규모를 발주처가 규정한 90일에 넣으려면 몇 명이 필요한지, 그리고 그 인원을 실제로 넣으면 어떻게 되는지 계산해 보겠습니다.

공수 산정재사용 자산소프트웨어 견적코드베이스 실사리스크 관리모노레포

관련 글

공수 산정 (1) 예산에 맞춰 범위를 줄였는데, 그 범위도 예산에 안 맞았습니다

예산이 고정된 외주에서 "이 예산이면 여기까지 됩니다"를 계산해 제시하는 건 옳은 접근입니다. 그런데 예산을 시급 하한으로 나눈 107시간에 맞춰 범위를 줄인 뒤, 같은 범위를 예산과 무관하게 다시 재니 137시간이었습니다. 28% 차이가 어디서 왔는지의 기록입니다.

관련도 92%

공수 산정 (2) 기능점수는 왜 42% 낮게 나왔나 — 표준이 스스로 예고한 한계

단일 방법의 견적은 그 방법의 편향을 상속합니다. 입력이 하나도 겹치지 않는 네 가지 방법으로 같은 프로젝트를 독립 산정했더니 두 방법이 2.4% 차로 수렴했고, 법정 FP 산식만 42% 낮았습니다. 「대가산정 가이드」 자신의 조항으로 FP가 낮게 나오는 네 가지 원인을 짚어봅니다.

관련도 89%

공수 산정 (3) AI 가속을 견적에 반영하는 법 — 암달의 법칙이 정한 공수의 바닥

"AI로 하면 빠르잖아요"에 일괄 30% 할인으로 답하면 근거 없는 협상이 됩니다. 작업을 압축 등급으로 쪼개면 암달의 법칙이 그대로 드러납니다 — 가속 가능한 60%를 전부 0으로 만들어도 418시간이 바닥으로 남습니다. 전제를 안 밝히면 같은 범위가 8.8배로 벌어지는 이유까지 짚었습니다.

관련도 89%