Two failure modes bracket most internal platform efforts. The first is the gatekeeping platform: every deployment requires a ticket, the platform team is a permanent queue, and product teams route around it. The second is the abandoned platform: a well-engineered abstraction nobody adopted, because using it was harder than the thing it replaced.
The version that works treats the platform as a product with internal customers who are free to ignore it. That constraint is what forces the platform to be genuinely good, because adoption has to be earned rather than mandated.
A golden path is a default, not a rule
The paved road should cover the common case completely: a new service gets a repository, a pipeline, a deployment, observability, alerting, secrets management and an on-call configuration, from one command, in minutes. Everything standard is standard because nobody had to choose, not because a policy prohibited choosing.
And there must be an escape hatch. A team with a genuinely different requirement should be able to leave the path, with the understanding that they own what they take on. Platforms without an exit become gatekeepers by construction, and the first team with an unusual need will build a shadow platform that eventually becomes everyone's problem.
# What a product team should have to write to get a production service.
# Everything else — pipeline, dashboards, alerts, secrets, on-call, network
# policy, cost tags — is generated from it.
apiVersion: platform/v1
kind: Service
metadata:
name: inspection-api
owner: field-platform-team # drives on-call routing and access
spec:
language: python
tier: production # sets SLO defaults, backup policy, review gates
resources:
database: { engine: postgres, size: medium }
queue: { name: inspections }
endpoints:
- path: /api/inspections
public: true
slo: { availability: 99.9, latency_p95_ms: 300 }
# Escape hatch, used deliberately and visibly:
# spec.custom: true -> the team owns the pipeline and the alerting,
# and the platform stops generating them. Not forbidden. Just explicit.Measure adoption, not coverage
- Track voluntary adoption as the primary metric. If teams choose it, it is good; if you had to mandate it, you have a compliance exercise.
- Measure time from empty repository to production traffic. It is the number that tells you whether the paved road is actually paved.
- Keep the abstraction shallow enough to see through. Engineers need to debug what runs, and a platform that hides the underlying system makes incidents worse.
- Version the platform contract and support old versions for a stated period; forcing a migration on every team simultaneously destroys trust quickly.
- Staff it as a product team, with someone doing user research on their own colleagues. Most platform failures are product failures.
If teams have to be told to use the platform, it is not a platform. It is a policy with a deployment pipeline attached.
One honest scoping note: this is not worth building for three teams. Below a certain size, a shared template repository and a good README deliver most of the benefit for none of the cost, and a dedicated platform team is capacity you do not have. The economics change somewhere around five to eight product teams, when the same problems are being solved independently often enough that solving them once is genuinely cheaper.