DEV Community

전규현 (Jeon gyuhyeon)
전규현 (Jeon gyuhyeon)

Posted on

Risk-Based Buffer: Managing Uncertainty with Numbers

"When will this project end?"

"Um... 6 weeks with 20% buffer."

Wait, why 20%?

"Just... experience?"

Let's set buffers with calculation, not guesswork.

The Buffer Dilemma

How do you set project buffer?

Most do this:

  • "Always add 30%"
  • "Was late last time, so 50%"
  • "Important project, so 100%"
  • "Just feeling..."

Result? Too little = project delay, too much = resource waste and Parkinson's Law.
The right amount? No one knows.

Risk Score System

Measuring risk enables buffer calculation.

class RiskBasedBuffer {
  calculateBuffer(baseEstimate, risks) {
    // Weight by risk factor
    const factors = {
      new_tech_usage: { weight: 3, score: risks.newTech },
      team_lack_experience: { weight: 3, score: risks.teamExp },
      unclear_requirements: { weight: 3, score: risks.unclear },
      complexity: { weight: 2, score: risks.complexity },
      dependency: { weight: 2, score: risks.dependency },
      change_probability: { weight: 2, score: risks.changeProb },
    };

    // Calculate risk score (0-100)
    let totalRisk = 0;
    let maxRisk = 0;

    for (const factor in factors) {
      const f = factors[factor];
      totalRisk += f.weight * f.score;
      maxRisk += f.weight * 10;
    }

    // Calculate buffer from risk ratio
    const riskRatio = totalRisk / maxRisk;
    const bufferPercentage = 10 + riskRatio * 60; // 10-70%

    return {
      baseEstimate,
      bufferPercentage: Math.round(bufferPercentage),
      bufferDays: Math.round((baseEstimate * bufferPercentage) / 100),
      totalEstimate: baseEstimate + Math.round((baseEstimate * bufferPercentage) / 100),
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Real Application Example

Let's compare two projects.

High-Risk Project: Blockchain Payment System

const highRiskProject = {
  base_estimate: 60, // days

  risks: {
    newTech: 8, // First blockchain adoption
    teamExp: 9, // No team experience
    unclear: 7, // Spec incomplete
    complexity: 7, // Distributed system
    dependency: 6, // Multiple external APIs
    changeProb: 8, // Changes frequently
  },

  // Calculation result:
  // Risk score: 67/100
  // Recommended buffer: 50% (30 days)
  // Final expected: 90 days
};
Enter fullscreen mode Exit fullscreen mode

Low-Risk Project: Admin Page CRUD

const lowRiskProject = {
  base_estimate: 30, // days

  risks: {
    newTech: 1, // Familiar stack
    teamExp: 1, // Rich experience
    unclear: 2, // Clear spec
    complexity: 2, // Simple CRUD
    dependency: 1, // Independent
    changeProb: 2, // Almost none
  },

  // Calculation result:
  // Risk score: 15/100
  // Recommended buffer: 15% (5 days)
  // Final expected: 35 days
};
Enter fullscreen mode Exit fullscreen mode

If both used "20% from experience"?
Blockchain project would fail, CRUD would waste resources.

Dynamic Buffer Management

Buffer isn't set once and done.
Must track consumption daily and analyze patterns.

class DynamicBufferManager {
  constructor(totalBuffer) {
    this.totalBuffer = totalBuffer;
    this.consumed = 0;
    this.projectProgress = 0;
  }

  updateStatus(progress, bufferUsedToday) {
    this.projectProgress = progress;
    this.consumed += bufferUsedToday;

    const consumptionRate = this.consumed / this.totalBuffer;
    const idealRate = this.projectProgress;

    // Danger if buffer consumption faster than progress
    if (consumptionRate > idealRate * 1.5) {
      return {
        status: '🔴 Danger',
        action: ['Root cause analysis', 'Review scope', 'Add resources'],
      };
    } else if (consumptionRate > idealRate * 1.2) {
      return {
        status: '🟡 Warning',
        action: ['Reassess risk', 'Review schedule adjustment'],
      };
    }

    return {
      status: '🟢 Normal',
      remainingBuffer: this.totalBuffer - this.consumed,
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Monte Carlo Simulation

For more sophisticated predictions, run simulations.

import random

def monte_carlo_buffer(tasks, iterations=1000):
    """Calculate appropriate buffer through 1000 simulations"""

    results = []

    for _ in range(iterations):
        total_time = 0

        for task in tasks:
            # Each task random between best/worst case
            best_case = task["estimate"] * 0.7
            worst_case = task["estimate"] * 2.0

            # Simulate with PERT distribution
            simulated = random.triangular(
                best_case,
                worst_case,
                task["estimate"]
            )
            total_time += simulated

        results.append(total_time)

    # Analyze results
    results.sort()
    p50 = results[500]  # 50% probability
    p90 = results[900]  # 90% probability

    recommended_buffer = p90 - p50

    return {
        "base": p50,
        "buffer_90": recommended_buffer,
        "confidence_90": p90
    }

# Usage example
tasks = [
    {"name": "Design", "estimate": 5},
    {"name": "Development", "estimate": 15},
    {"name": "Testing", "estimate": 8}
]

result = monte_carlo_buffer(tasks)
print(f"50% probability: {result['base']:.0f} days")
print(f"90% probability: {result['confidence_90']:.0f} days")
print(f"Recommended buffer: {result['buffer_90']:.0f} days")
Enter fullscreen mode Exit fullscreen mode

Buffer Consumption Pattern Analysis

Tracking why buffer is consumed enables improvement for next project.

class BufferConsumptionTracker {
  recordConsumption(day, consumed, reason) {
    this.history.push({ day, consumed, reason });

    // Pattern analysis
    const triggers = this.identifyTriggers();

    if (triggers[0].reason === 'Requirement Change') {
      console.log('⚠️ Requirements freeze needed');
    } else if (triggers[0].reason === 'Technical Issue') {
      console.log('⚠️ Technical validation strengthening needed');
    }
  }

  identifyTriggers() {
    // Aggregate buffer consumption by cause
    const reasons = {};
    this.history.forEach((h) => {
      reasons[h.reason] = (reasons[h.reason] || 0) + h.consumed;
    });

    // Return top 3 causes
    return Object.entries(reasons)
      .sort((a, b) => b[1] - a[1])
      .slice(0, 3)
      .map(([reason, days]) => ({ reason, days }));
  }
}
Enter fullscreen mode Exit fullscreen mode

Real Case: Payment System Renewal

A real case from a fintech company.

Initial Plan (Empirical Buffer)

  • Expected: 3 months + 20% = 3.6 months
  • Actual: 5.5 months (Failed!)

Re-planning After Risk Analysis

Risk Assessment:
- PCI Compliance: 9 points
- Legacy Integration: 8 points
- Real-time Processing: 7 points
- Lack Security Experience: 8 points

Risk Score: 72/100
Recommended Buffer: 55%
New Expected: 4.65 months
Enter fullscreen mode Exit fullscreen mode

Result

  • Actual: 4.5 months (Success!)
  • Buffer Usage: 85%

Risk-based buffer saved the project.

Checklist

When introducing risk-based buffer:

  • [ ] Define risk factors (technology, team, requirements)
  • [ ] Evaluate each factor 0-10 points
  • [ ] Calculate score with weights applied
  • [ ] Calculate buffer ratio (10-70%)
  • [ ] Track daily buffer consumption
  • [ ] Reassess risk weekly
  • [ ] Set trigger points
  • [ ] Analyze buffer consumption causes
  • [ ] Improve based on patterns

Conclusion

Risk-based buffer is "calculation" not "feeling."

Uncertainty can't be eliminated, but can be measured and prepared for.

Try risk-based buffer in your next project.
It will be the first step to managing projects with data, not guesswork.


Need systematic project management? Check out Plexo.

Top comments (0)