Internal Developer Platform

The Ratio That Forces a Platform

The platform team had six engineers and a shared inbox. Two years earlier the inbox had been a reasonable way to work. The company had gone from sixty engineers to two hundred, nobody had noticed a specific day on which the inbox stopped working, and now the oldest unanswered request was nine weeks old.


The Problem at Scale

The usual explanation is that the platform team is understaffed. That framing is wrong in a way that matters, because it suggests the problem is a shortage of hours and the fix is more hours.

The actual property is that a request queue with an arrival rate above its service rate does not get slowly worse. It diverges. There is no level of heroics that stabilises it, and the nine week old ticket is not evidence of a busy team, it is evidence of a queue that has been unstable for some time.

  λ    requests arriving per week
  D    platform hours to serve one request
  C    platform hours actually available per week

  ρ = λ x D / C

  ρ < 1    the queue drains, waits are bounded
  ρ ≈ 1    waits grow large and erratic
  ρ > 1    the backlog grows without limit
KEY CONCEPT

A platform is not built because self service is a nicer way to work. It is built because the ticket queue has become unstable, and the only two ways to stabilise a queue are to raise capacity or to lower the service time per request. Hiring raises capacity linearly and demand grows with engineering headcount, so hiring buys time rather than a fix. Self service drives the platform hours per request toward zero, which is the only lever that changes the shape of the curve rather than its position.


How It Works

Put your own numbers in

The arithmetic is worth doing honestly, because the answer is usually further past one than anyone expects.

  200 developers
  x 0.4 requests per developer per week    = 80 requests/week
  x 2.0 platform hours per request         = 160 hours/week

  6 platform engineers
  x 25 interruptible hours each            = 150 hours/week

  ρ = 160 / 150 = 1.07

At ρ slightly above one the team is not visibly failing. Everybody is busy, most things eventually get done, and the backlog grows by a few hours every week. That is the state most platform teams are in when somebody first says the word platform, and it is why the problem is usually described as a staffing problem.

Two details make the real number worse than the naive one.

Interruptible hours are not working hours. An engineer with twenty five hours of ticket capacity is not doing thirty five hours of project work in the remaining time. Context switching between a reconciliation bug and a namespace request costs both.

Request cost is not uniform. The distribution has a long tail, and the tail is where the hours go.

  namespace creation        20 minutes    high volume
  new service onboarding     4 hours      moderate volume
  a database with a
    compliance question     12 hours      rare, and it eats a week

Demand scales with headcount, capacity does not

This is the part that makes hiring a temporary answer.

  developers      λ        needed platform hours
  ------------------------------------------------
  60              24/wk    48
  200             80/wk    160
  400            160/wk    320

Every new engineering hire adds demand. Every platform hire adds capacity. If the company is growing engineering faster than platform, and it always is, then ρ climbs regardless of what you do about staffing.

Which means the only durable move is to attack D, the hours per request.

What self service actually changes

  before     request -> human reads it -> human does it -> reply
  after      request -> policy evaluates it -> system does it

D does not go to zero. It goes to the amortised cost of maintaining the automated path, spread across all the requests that path serves.

  D_manual     2.0 hours per request, every request
  D_self       build cost B, plus maintenance M per week,
               divided across λ requests

So the break even is a volume question, and it has an answer:

  worth automating when    λ x D_manual  >  M + B/horizon

  80 requests/wk x 2.0 h  = 160 h/week saved
  maintenance of the path =  20 h/week
  build cost              = 400 h, over a 2 year horizon
                          =   4 h/week

One hundred sixty against twenty four. That is not a close call, and it is also why automating the twelve hour compliance request, which arrives four times a year, is usually the wrong first move despite being the most painful one.

The ratio nobody states

Published platform to developer ratios vary widely and are mostly not comparable, because they depend entirely on how much is self service already. The useful form of the question is not what ratio other companies run. It is what ρ your own queue is running at, which you can compute this afternoon from your ticket system.


Building and Operating It

Measure the queue before arguing about headcount.

#!/usr/bin/env python3
# Utilisation of the platform team as a queue. Above 1.0 the backlog
# grows without bound, which is a different problem from being busy
# and has a different fix.
DEVELOPERS      = 200
REQ_PER_DEV_WK  = 0.4
HOURS_PER_REQ   = 2.0      # measure this, do not estimate it
ENGINEERS       = 6
INTERRUPTIBLE   = 25       # not 40, and not 35

demand   = DEVELOPERS * REQ_PER_DEV_WK * HOURS_PER_REQ
capacity = ENGINEERS * INTERRUPTIBLE
rho      = demand / capacity

print(f"demand   {demand:6.0f} h/week")
print(f"capacity {capacity:6.0f} h/week")
print(f"rho      {rho:6.2f}  {'DIVERGING' if rho >= 1 else 'stable'}")
print(f"engineers needed to reach rho=0.7: {demand / (0.7*INTERRUPTIBLE):.1f}")

Then find which request types are worth the build.

-- Volume times cost, not cost alone. The painful request that
-- arrives four times a year is rarely the right first target, and
-- it is almost always the one people want to automate.
SELECT request_type,
       count()                        AS volume,
       avg(hours_spent)               AS avg_hours,
       count() * avg(hours_spent)     AS total_hours
FROM platform_requests
WHERE created_at > now() - INTERVAL 90 DAY
GROUP BY request_type
ORDER BY total_hours DESC;

Track arrival rate against engineering headcount, since that is the trend that decides whether you are ahead.

# Requests per developer per week. If this is flat while headcount
# grows, demand is growing linearly and capacity is not.
sum(rate(platform_requests_total[7d])) * 604800
  / max(engineering_headcount)

And watch queue age rather than queue depth.

# Depth is a function of how big the company is. Age is a function
# of whether the queue is stable, which is the thing you care about.
max(time() - platform_request_created_timestamp{status="open"}) / 86400
PRO TIP

Compute this from your ticket system before you write a platform proposal. A number like 1.07 is far more persuasive to a director than an argument about developer experience, because it says the backlog grows every week regardless of effort and it says exactly how many hires would be needed to avoid building anything. That second figure is usually large enough to make the build decision for you, and it is the one nobody has calculated.


Tradeoffs and Decision Framework

LeverEffect on ρDurability
Hire platform engineersLowers it linearlyTemporary, demand grows with headcount
Reduce request scopeLowers demandUnpopular, and usually reappears
Self service the top request typesLowers D sharplyDurable, with a maintenance cost
Self service the rare expensive requestBarely moves ρFeels good, does little
SignalWhat it means
ρ below 0.7A platform may not be justified yet
ρ near 1.0Everyone busy, backlog quietly growing
ρ above 1.0Diverging; no amount of effort stabilises it
Oldest ticket age rising monthlyConfirms divergence independently

Three questions before proposing a platform. What is ρ, computed from real ticket data rather than estimated. Which request types carry the volume times cost, since that is what to automate first. And how fast is engineering headcount growing, because that sets how quickly any staffing fix expires.

Default: measure hours per request from the ticket system, compute ρ, automate in descending order of volume times cost, and treat hiring as the thing that buys time to build rather than as the fix.


Failure Modes and Common Mistakes

Calling it a staffing problem. An unstable queue is a different condition from a busy team.

Estimating hours per request. Measure it; the estimate is always low.

Counting forty hours of capacity. Interruptible capacity is far less, and context switching costs both sides.

Automating the most painful request first. Rare and expensive is worse value than frequent and cheap.

Ignoring that demand scales with headcount. Hiring moves ρ down and growth moves it back up.

Building a platform at ρ well below one. You have added a system to maintain and solved nothing.

KNOWLEDGE CHECK

A platform team computes that demand is 160 hours per week against 150 hours of capacity, giving a utilisation of 1.07. What does that number actually tell them?

INTERVIEW QUESTION

How would you decide whether your organisation needs a platform team, or just needs to hire?