7 분 소요


스태프 엔지니어가 업무 추정하는 방법: 뻥튀기 없는 현실적인 접근법

“이거 얼마나 걸려요?”

10년 넘게 개발하면서 가장 많이 들은 질문이다. 그리고 솔직히 말하면, 아직도 정확하게 답하기 어렵다. 하지만 시니어에서 스태프 엔지니어로 올라오면서 깨달은 게 있다. 정확한 추정은 불가능하지만, 덜 틀리는 방법은 있다.

추정이 어려운 진짜 이유

대부분의 개발자가 추정을 못하는 이유는 낙관주의 때문이 아니다. 알려지지 않은 것을 알 수 없기 때문이다. 이걸 “unknown unknowns”라고 부르는데, 프로젝트 시작 시점에는 어떤 문제가 터질지 예측 자체가 불가능하다.

# 주니어의 추정
def estimate_task():
    coding_time = 2  # 일
    return coding_time  # 결과: 2일

# 스태프 엔지니어의 추정
def estimate_task():
    coding_time = 2
    code_review_cycles = 1.5  # 리뷰 2-3회 왕복
    unexpected_bugs = 1
    meeting_overhead = 0.5
    dependency_on_others = 1  # 다른 팀 대기
    buffer = (coding_time + code_review_cycles + 
              unexpected_bugs + meeting_overhead + 
              dependency_on_others) * 0.2
    return sum([coding_time, code_review_cycles, 
                unexpected_bugs, meeting_overhead, 
                dependency_on_others, buffer])  # 결과: 7.2일

차이가 보이는가? 실제 코딩 시간은 전체의 30%도 안 된다.

내가 사용하는 3단계 추정 프레임워크

1단계: 작업 분해 (Work Breakdown)

모든 태스크를 최대 4시간 단위로 쪼갠다. 하루짜리 태스크는 없다. “로그인 기능 구현”이 아니라 이렇게 분해한다:

## 로그인 기능 추정
- [ ] DB 스키마 설계 및 마이그레이션 (2h)
- [ ] 비밀번호 해싱 유틸리티 (1h)
- [ ] 로그인 API 엔드포인트 (2h)
- [ ] JWT 토큰 생성/검증 (2h)
- [ ] 프론트엔드 로그인 폼 (2h)
- [ ] API 연동 및 상태 관리 (2h)
- [ ] 에러 핸들링 (로그인 실패, 네트워크 오류) (1.5h)
- [ ] 단위 테스트 (2h)
- [ ] 통합 테스트 (1.5h)
- [ ] 코드 리뷰 대응 (2h)

합계: 18시간 = 약 2.5일 (순수 개발 시간)

2단계: 불확실성 계수 적용

경험상 다음 계수를 곱한다:

상황 계수
익숙한 기술 스택 + 명확한 요구사항 1.5x
새로운 기술 또는 모호한 요구사항 2.0x
레거시 시스템 수정 2.5x
외부 API/시스템 연동 2.5x
위 조건 2개 이상 해당 3.0x

로그인 기능이 새로운 인증 시스템이라면: 2.5일 × 2.0 = 5일

3단계: 팀 컨텍스트 추가

def final_estimate(base_days: float, team_context: dict) -> float:
    estimate = base_days
    
    # 코드 리뷰 대기 시간
    if team_context['team_size'] > 5:
        estimate += 1  # 큰 팀은 리뷰 대기가 길다
    
    # 회의 오버헤드
    estimate += base_days * 0.1  # 스탠드업, 기획 미팅 등
    
    # 온콜/인터럽트
    if team_context['on_call_rotation']:
        estimate += base_days * 0.15
    
    # 의존성
    estimate += len(team_context['blocking_teams']) * 0.5
    
    return round(estimate, 1)

# 예시
context = {
    'team_size': 8,
    'on_call_rotation': True,
    'blocking_teams': ['인프라팀', 'QA팀']
}
print(final_estimate(5, context))  # 7.8일

추정 안티패턴: 이건 하지 마라

“일단 해보고 알려드릴게요”

최악이다. PM이나 매니저 입장에서 이건 “난 모른다”와 같다. 차라리 범위를 제시해라.

❌ "해봐야 알 것 같아요"
✅ "최소 3일, 최대 2주입니다. 3일 후에 더 정확한 추정 드릴게요."

압박에 굴복하기

“그거 3일이면 되지 않아요?”라는 질문에 “네…“라고 대답하면 망한다.

❌ "네, 열심히 해볼게요" (그리고 야근)
✅ "3일은 기능만 나오고 테스트 없이 가는 겁니다. 
    품질 보장하려면 5일 필요합니다. 어떻게 할까요?"

버퍼를 숨기기

버퍼는 당당하게 명시해라. 숨기면 나중에 설명하기 더 어렵다.

## 프로젝트 타임라인
- 개발: 5일
- 테스트: 2일
- 버퍼 (예상치 못한 이슈): 1.5일
- **총 추정: 8.5일**

추정 정확도를 높이는 실전 팁

과거 데이터 활용

-- 비슷한 규모의 과거 태스크 조회
SELECT 
    task_name,
    estimated_hours,
    actual_hours,
    actual_hours / estimated_hours as accuracy_ratio
FROM task_history
WHERE complexity = 'medium'
    AND tech_stack LIKE '%Python%'
ORDER BY created_at DESC
LIMIT 10;

내 평균 accuracy_ratio가 0.6이면, 추정치에 1.67을 곱해야 한다.

스파이크(Spike) 활용

복잡한 태스크는 추정 전에 1-2시간 탐색 시간을 먼저 달라고 해라.

## 스파이크 결과 보고
- 탐색 시간: 2시간
- 발견된 위험 요소:
  1. 레거시 인증 시스템과 호환성 이슈
  2. 데이터베이스 스키마 변경 필요 (마이그레이션)
- 수정된 추정: 5일 → 8일

신뢰 구간으로 커뮤니케이션

단일 숫자 대신 범위를 제시해라.

"50% 신뢰도: 5일 (모든 게 잘 풀리면)
80% 신뢰도: 8일 (일반적인 상황)
95% 신뢰도: 12일 (레거시 문제 터지면)"

결론: 추정은 약속이 아니라 대화다

스태프 엔지니어로서 배운 가장 중요한 건 이거다: 추정은 정확한 예측이 아니라 지속적인 커뮤니케이션 도구다.

첫 추정이 틀려도 괜찮다. 중요한 건:

  1. 왜 틀렸는지 분석하고
  2. 이해관계자에게 빠르게 공유하고
  3. 다음 추정에 반영하는 것

“2주요”라고 말하고 4주 걸리면 신뢰를 잃는다. “2-4주인데, 1주 후에 다시 확인해 드릴게요”라고 말하면 프로페셔널이다.

추정 잘한다고 승진하진 않지만, 못하면 확실히 신뢰를 잃는다. 그리고 스태프 레벨에서 신뢰 잃으면 끝이다.

How I Estimate Work as a Staff Software Engineer: A No-BS Approach

“How long will this take?”

After 10+ years of engineering, this is still the question I hear most. And honestly? I still can’t answer it accurately. But here’s what I’ve learned climbing from senior to staff: Perfect estimation is impossible, but being less wrong is achievable.

Why Estimation Is Actually Hard

Most developers don’t fail at estimation because they’re optimistic. They fail because you can’t know what you don’t know. We call these “unknown unknowns,” and at project kickoff, predicting which problems will blow up is literally impossible.

# Junior's estimate
def estimate_task():
    coding_time = 2  # days
    return coding_time  # Result: 2 days

# Staff engineer's estimate
def estimate_task():
    coding_time = 2
    code_review_cycles = 1.5  # 2-3 review rounds
    unexpected_bugs = 1
    meeting_overhead = 0.5
    dependency_on_others = 1  # waiting on other teams
    buffer = (coding_time + code_review_cycles + 
              unexpected_bugs + meeting_overhead + 
              dependency_on_others) * 0.2
    return sum([coding_time, code_review_cycles, 
                unexpected_bugs, meeting_overhead, 
                dependency_on_others, buffer])  # Result: 7.2 days

See the difference? Actual coding time is less than 30% of the total.

My 3-Step Estimation Framework

Step 1: Work Breakdown

Break every task into 4-hour maximum chunks. There’s no such thing as a “1-day task.” Instead of “implement login feature,” break it down like this:

## Login Feature Estimate
- [ ] DB schema design and migration (2h)
- [ ] Password hashing utility (1h)
- [ ] Login API endpoint (2h)
- [ ] JWT token generation/validation (2h)
- [ ] Frontend login form (2h)
- [ ] API integration and state management (2h)
- [ ] Error handling (failed login, network errors) (1.5h)
- [ ] Unit tests (2h)
- [ ] Integration tests (1.5h)
- [ ] Code review iterations (2h)

Total: 18 hours = ~2.5 days (pure dev time)

Step 2: Apply Uncertainty Multipliers

From experience, I apply these multipliers:

Situation Multiplier
Familiar stack + clear requirements 1.5x
New technology OR vague requirements 2.0x
Legacy system modifications 2.5x
External API/system integration 2.5x
2+ conditions above 3.0x

If the login feature involves a new auth system: 2.5 days × 2.0 = 5 days

Step 3: Add Team Context

def final_estimate(base_days: float, team_context: dict) -> float:
    estimate = base_days
    
    # Code review queue time
    if team_context['team_size'] > 5:
        estimate += 1  # larger teams have longer review queues
    
    # Meeting overhead
    estimate += base_days * 0.1  # standups, planning, etc.
    
    # On-call/interrupts
    if team_context['on_call_rotation']:
        estimate += base_days * 0.15
    
    # Dependencies
    estimate += len(team_context['blocking_teams']) * 0.5
    
    return round(estimate, 1)

# Example
context = {
    'team_size': 8,
    'on_call_rotation': True,
    'blocking_teams': ['infra-team', 'qa-team']
}
print(final_estimate(5, context))  # 7.8 days

Estimation Anti-Patterns: Don’t Do These

“Let me try it first and I’ll let you know”

The worst. From a PM’s perspective, this equals “I have no idea.” Give a range instead.

❌ "I'll need to dig in before I can tell you"
✅ "Minimum 3 days, maximum 2 weeks. I'll have a refined estimate after 3 days."

Caving to Pressure

When someone asks “Can’t you do this in 3 days?”, saying “Yes…” is a trap.

❌ "Sure, I'll do my best" (followed by overtime)
✅ "3 days gets you the feature without tests. 
    5 days if you want quality. Which do you prefer?"

Hiding Your Buffer

State your buffer explicitly. Hiding it makes explanations harder later.

## Project Timeline
- Development: 5 days
- Testing: 2 days  
- Buffer (unexpected issues): 1.5 days
- **Total Estimate: 8.5 days**

Practical Tips for Better Accuracy

Use Historical Data

-- Query similar past tasks
SELECT 
    task_name,
    estimated_hours,
    actual_hours,
    actual_hours / estimated_hours as accuracy_ratio
FROM task_history
WHERE complexity = 'medium'
    AND tech_stack LIKE '%Python%'
ORDER BY created_at DESC
LIMIT 10;

If my average accuracy_ratio is 0.6, I need to multiply estimates by 1.67.

Use Spikes

For complex tasks, ask for 1-2 hours of exploration time before committing to an estimate.

## Spike Results Report
- Exploration time: 2 hours
- Discovered risks:
  1. Compatibility issues with legacy auth system
  2. Database schema changes required (migration)
- Revised estimate: 5 days → 8 days

Communicate with Confidence Intervals

Instead of single numbers, give ranges.

"50% confidence: 5 days (if everything goes perfectly)
80% confidence: 8 days (typical scenario)
95% confidence: 12 days (if legacy issues surface)"

Conclusion: Estimation Is a Conversation, Not a Promise

The most important thing I’ve learned as a staff engineer: Estimation isn’t about accurate prediction—it’s a continuous communication tool.

Being wrong on your first estimate is fine. What matters is:

  1. Analyzing why you were wrong
  2. Sharing updates with stakeholders quickly
  3. Incorporating learnings into future estimates

Say “2 weeks” and take 4? You’ve lost trust. Say “2-4 weeks, I’ll update you in a week”? That’s professional.

Good estimation won’t get you promoted, but bad estimation will definitely cost you credibility. And at staff level, losing credibility is game over.

댓글남기기