Chapter 5 · Part II: AI-Native Systems, Agentic Workflows, and Platform Engineering
Platform Engineering and Internal Developer Platforms
A platform is an interface problem wearing infrastructure clothing. Its users are engineers, its product is the shortest correct path to production, and its success is measured in their output rather than in its own uptime. This chapter covers the abstraction, the environment lifecycle, the governance, and the metrics.
In this chapter
5.1 Control Plane Abstractions
An internal developer platform sits between application teams and the infrastructure. Its purpose is to reduce the amount an engineer must know in order to ship safely.
The number to hold in mind is cognitive load. Deploying a service on raw Kubernetes requires a working understanding of Deployments, Services, Ingress, ConfigMaps, Secrets, ServiceAccounts, network policies, resource requests, probes, pod disruption budgets, horizontal autoscalers, and the several controllers that interpret them. That is a reasonable amount for one specialist and an unreasonable amount for every engineer in an organization.
Adoption of the response is now broad. Reported figures for 2026 put the share of organizations above 500 engineers running a dedicated platform team at around 78 percent, up from roughly 43 percent in 2023.
The abstraction is the product
A platform's core artifact is the interface that application teams write against. Getting it right is a product design problem, and three failure modes recur.
The leaky abstraction hides the infrastructure until something breaks, and then the engineer must understand both the abstraction and everything underneath it. The over-constrained abstraction covers the common case and offers no path for the team whose requirement is legitimate and unusual, so that team builds its own platform. The thin abstraction is a wrapper that renames the underlying concepts without removing any of them, which adds a layer and removes no load.
The pattern that avoids all three is a progressive interface. The default path requires almost nothing. Each escape hatch is available, explicit, and supported rather than forbidden.
# Level 1: the default path. This is the whole file for most services.
apiVersion: platform.example.com/v1
kind: Service
metadata:
name: order-api
annotations:
platform.example.com/owner: team-orders
spec:
language: go
port: 8080
resources: medium # a named size, not millicores and mebibytes
dependencies:
- postgres: orders-db # provisioned, connected, credentials rotated
- kafka-topic: orders-events
# Level 2: an override, still declarative, still within the platform.
scaling:
min: 3
max: 40
metric: requests-per-second
target: 200
# Level 3: the escape hatch. Raw Kubernetes, merged by the controller.
overlays:
- target: Deployment
patch:
spec:
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
Two design rules make that structure work in practice.
Make the escape hatch visible and measured. Every use of level three is a signal that the abstraction has a gap, so record which teams use it and for what. A cluster of similar overlays is a feature request with evidence attached. A platform team that forbids overlays instead gets a shadow platform.
Keep the abstraction declarative and reconciled. The platform interface is a custom resource, and a controller reconciles it continuously, for the reason Volume II gives for level-driven reconciliation: a missed event, a manual change, or a partial failure all resolve on the next pass. An imperative platform that generates configuration once has no answer when reality drifts.
The portal is not the platform
A developer portal is the human interface: the service catalog, the documentation, the templates, the scorecards, and the links. The plugin-based catalog model that Backstage popularized is the dominant pattern.
The portal is not the platform, and conflating them is a common and expensive mistake. A portal with nothing behind it is a directory of links that goes stale. A platform with no portal is a set of APIs that nobody discovers. The portal's value comes from being backed by a real control plane, and the platform's value comes from being discoverable.
The service catalog is the portal's foundation, because it answers the questions that consume an organization's time. What services exist, who owns each one, what depends on it, where its runbook is, what its health is, and how to reach the team. An accurate catalog is worth more than any other portal feature, and accuracy comes from generating it from the platform's own state rather than from asking teams to keep a page updated.
Build the platform for the service you have most of
A platform that handles every case equally well handles none of them with a simple interface. Identify the shape that makes up the majority of services, which in most organizations is a stateless HTTP service with a database and a message topic, and make that path require almost no configuration. Everything else gets a documented escape hatch. A platform that cuts the time to production for 80 percent of services from two weeks to one hour succeeded, even if the remaining 20 percent still take two weeks.
5.2 Automated Environment Lifecycle Management
Shared long-lived environments are where delivery slows down. A staging environment that everyone shares is a queue, a source of interference between unrelated changes, and a permanent source of ambiguity about what is actually deployed.
Ephemeral environments replace it. Each pull request gets its own environment, created on open and destroyed on merge or close.
What ephemeral means in practice
An environment is the application, its dependencies, its configuration, and some data. Each part has a different answer.
The application deploys from the pull request's built image, tagged with the commit digest. That part is straightforward.
Dependencies divide by cost. A lightweight dependency such as a database or a cache runs as a real instance inside the environment. A heavyweight or external dependency such as a payment provider or a partner API is stubbed with a recorded contract. A shared dependency that cannot be duplicated, such as a large data warehouse, is accessed read-only with a per-environment credential.
Data is the part that determines whether the environment is useful. Empty databases make an environment useless for review. Production data makes it a compliance incident. The workable answer is a seeded, anonymized, and small dataset, generated from a fixture definition that lives in version control alongside the schema, so that it evolves with the schema rather than rotting.
PR opened
|
+-> build image, tag by commit digest ~3 min
+-> provision namespace, quota, network policy ~10 s
+-> provision dependencies from templates ~60 s
| postgres (real, 1 replica, seeded)
| kafka topics (real, short retention)
| payment provider (stub, recorded contract)
+-> deploy, wait for readiness ~90 s
+-> run smoke tests ~60 s
+-> comment the URL on the PR total ~6 min
|
PR updated -> rebuild and redeploy in place
|
PR merged or closed
+-> destroy everything, unconditionally
|
SAFETY NETS, because the destroy step will sometimes not run:
* every resource carries a TTL label, and a sweeper destroys
anything past it regardless of PR state
* a hard namespace quota caps the blast radius of a leak
* a cost report per environment, attributed to the PR author
* a daily reconciliation between live namespaces and open PRs
Figure 5.1 The ephemeral environment lifecycle, with its guards.
The safety nets are not optional, and the reason is specific. The destroy step runs in a webhook handler, and webhook handlers miss events. Without a time-to-live sweeper, an organization accumulates orphaned environments until someone notices the cloud bill, which is typically a quarter later.
Drift and why it persists
Infrastructure drift is the difference between the declared state and the actual state. It arrives through emergency manual changes, through console edits, through a second tool managing the same resource, and through a provider changing a default.
Three controls address it in increasing order of strength.
Detection runs a plan on a schedule and reports differences. It is easy to adopt and it produces a report that people stop reading, because a permanently non-empty drift report is the same as no report.
Prevention removes the ability to make manual changes, by restricting console and API write access to the automation identity. It is effective and it needs a break-glass path, because the emergency that motivated the manual change will recur.
Continuous reconciliation removes drift by correcting it. A controller compares desired and actual state continuously and converges, so a manual change is reverted within a reconciliation interval. This is what Kubernetes does natively and what infrastructure-as-code tools do when run in a controller mode rather than in a pipeline.
The trap in continuous reconciliation is worth naming. A controller that reverts a change made during an incident will revert the fix, repeatedly, while the engineer wonders why it is not taking effect. Every reconciler needs a documented suspend mechanism, and the incident runbook needs to say how to use it.
Table 5.1: environment strategies compared
| Strategy | Provision time | Cost | Isolation | Fidelity |
|---|---|---|---|---|
| Shared long-lived staging | none, always on | low | none | high |
| Per-team long-lived | none, always on | medium | per team | high |
| Per-pull-request ephemeral | 5 to 15 min | medium, if swept | complete | medium to high |
| Local with containers | 1 to 3 min | none | complete | low to medium |
| Preview on production traffic, shadowed | minutes | low | read-only | highest |
The fidelity column is where ephemeral environments lose, and it is worth being honest about the reason. An ephemeral environment has a small dataset, a single replica, no realistic traffic, and stubbed external dependencies. It catches interface errors, configuration errors, and obvious regressions. It does not catch a performance problem at scale, a data-dependent bug, or a failure mode that needs concurrency. Those need production traffic, which is why progressive delivery is a complement rather than a competitor.
5.3 Governance, Scorecards, and Golden Paths
A platform that offers a good default and permits anything else gets a good default used by the teams that do the right thing anyway. Governance is how the default becomes the norm without becoming a gate that teams route around.
Golden paths
A golden path is a supported, opinionated route to production for a common case. It is a template plus a pipeline plus a runtime plus documentation, and its defining property is that it is genuinely easier than the alternative.
That property is the whole design constraint. A golden path that is safer and slower loses. A golden path that is safer and faster wins without any enforcement, because engineers take the path of least resistance and the platform's job is to make the least resistance also the most correct.
A path that works has four parts. A template that generates a working service with tests, a pipeline, observability, and a runbook already wired. A pipeline that is maintained centrally so that teams inherit improvements rather than copying them. A runtime that provides the production defaults, which means health checks, resource requests, network policy, and telemetry, without the team configuring them. And documentation that is a task-oriented guide rather than a reference manual.
The measure of a golden path is adoption rate. A path used by 20 percent of new services is not a golden path, it is a suggestion, and the reason is almost always that it is missing a capability that teams need.
Scorecards
A scorecard evaluates each service against a set of checks and publishes the result. It makes an organization-wide standard visible per service, and it turns an abstract policy into a concrete list for one team.
The checks that produce change share three properties: they are automatically evaluated, they are owned, and they are fixable. A check that needs a human to assess it does not scale. A check on a service with no owner goes nowhere. A check that a team cannot fix without a quarter of work produces resentment rather than action.
Table 5.2: a scorecard that changes behavior
| Category | Check | Source |
|---|---|---|
| Ownership | has an owning team and an on-call rotation | catalog, paging system |
| Ownership | runbook exists and was updated in 180 days | documentation store |
| Reliability | SLO defined, with alerting on burn rate | monitoring configuration |
| Reliability | readiness and liveness probes configured correctly | cluster state |
| Reliability | pod disruption budget exists | cluster state |
| Security | no critical reachable vulnerability | scanner plus reachability |
| Security | image signed, provenance attached | admission controller |
| Security | no static long-lived credential in use | identity system |
| Delivery | deploys through the standard pipeline | pipeline telemetry |
| Delivery | deployed within the last 30 days | deployment history |
| Cost | resource requests within 2x of measured use | metrics |
| Data | data classification recorded, retention set | catalog |
Two rules make a scorecard land rather than irritate. Roll it out in reporting mode long before anything depends on it, so that teams see their position and improve without pressure. And tie enforcement to the level of the change rather than to a global cutoff: a service below a threshold cannot onboard a new critical dependency, rather than cannot deploy at all. A scorecard that blocks deployment on day one is a scorecard that gets an exemption process within a week.
Policy as code
Policy engines evaluate rules against resources at admission time, in the pipeline, and in continuous audit. The same policy must run at all three, because each catches a different class.
In the pipeline, a violation is caught before it reaches the cluster and the feedback lands where the engineer is working, which is the cheapest place to fix it. At admission, the policy is authoritative and catches anything applied by another route. In continuous audit, the policy catches resources that predate it or that drifted.
Two practical rules follow. Write the policy once and run it in all three places, because three policy definitions diverge. And make every denial say what to do: a message naming the rule, the offending field, and the correct value turns a blocked deployment into a two-minute fix rather than a support ticket.
The platform team becomes the bottleneck it was created to remove
The failure mode is predictable. Teams cannot do something, so they ask the platform team, which does it for them. The queue grows, the platform team becomes an operations team, and the abstraction stops improving because nobody has time. The exits are structural: every request handled manually more than three times becomes self-service, the platform team's work is measured in capabilities shipped rather than tickets closed, and the request queue is visible to leadership as a product backlog. A platform team with a growing ticket queue is a platform that is not finished.
5.4 Developer Experience Metrics
A platform is measured by its effect on the engineers who use it, not by its own availability. That requires metrics, and choosing the wrong ones does active harm.
The three families
DORA measures software delivery performance. Its current model uses deployment frequency, change lead time, change fail rate, failed deployment recovery time, and rework rate. The metrics are well validated and they describe the delivery system rather than any individual.
SPACE covers what DORA omits: satisfaction, performance, activity, communication, and efficiency. It is a framework rather than a metric set, and its contribution is the insistence that any single dimension is misleading on its own.
Platform-specific metrics describe the platform as a product: golden path adoption, self-service ratio against ticket volume, time to first deployment for a new engineer, and an internal net promoter score. These lack academic validation and they are the ones that tell a platform team whether it is succeeding.
Table 5.3: metrics worth collecting, and what each one reveals
| Metric | Reveals | Healthy direction |
|---|---|---|
| Deployment frequency | batch size and pipeline friction | higher |
| Change lead time, commit to production | end-to-end delivery friction | lower |
| Change fail rate | quality of the delivery system | lower |
| Failed deployment recovery time | rollback and detection capability | lower |
| Time to first commit, new engineer | onboarding friction | lower |
| Time to first production deploy, new engineer | end-to-end platform quality | lower |
| Time to provision a new service | golden path quality | lower |
| Golden path adoption rate | whether the default is genuinely easier | higher |
| Self-service ratio against tickets | whether the platform is a bottleneck | higher |
| Build and test wall-clock time | the most felt daily friction | lower |
| Local environment start time | inner-loop friction | lower |
| Flaky test rate | trust in the signal | lower |
| Interruptions per engineer per week | cognitive overhead | lower |
| Platform net promoter score | whether engineers want to use it | higher |
Two entries in that table are underrated. Build and test wall-clock time is the friction an engineer feels many times a day, and a ten-minute test suite costs more aggregate attention than a weekly deployment delay. Flaky test rate destroys the value of the whole pipeline: once engineers learn to re-run failures rather than investigate them, the suite is no longer a signal and a real failure passes through.
How these metrics get misused
Three misuses are common and each one is worse than not measuring.
Using them per engineer converts a system measurement into a performance review, and the response is gaming rather than improvement. Deployment frequency per person rewards splitting changes pointlessly. Every one of these metrics measures a system.
Optimizing one in isolation produces a predictable failure. Deployment frequency alone rewards shipping without care, which shows up in change fail rate. The four DORA metrics are read together for exactly this reason: two measure speed and two measure stability, and a real improvement moves both.
Using only quantitative metrics misses the largest problems. Cognitive overhead, unclear ownership, poor documentation, and the sense that nobody knows how something works do not appear in a dashboard. A quarterly qualitative survey with a small number of consistent questions catches them, and the survey results and the dashboard usually disagree in an informative way.
Where the time actually goes
Instrument the full path from commit to production, per stage, and the bottleneck is almost never where the team assumed.
commit -> production, median across 400 deployments, one quarter
local build and test 4m ##
CI queue wait 9m ##### <- capacity, not compute
CI build and test 14m ########
security and policy scan 3m #
PR review wait 31m ################## <- the largest
merge queue 6m ###
deploy to staging 5m ##
staging soak 20m ############ <- fixed, rarely justified
deploy to production 7m ###
progressive rollout 25m ###############
----
total 124m
Two of the largest are not engineering problems. Review wait is a
team process problem, and the staging soak is a policy with no
evidence behind it. A platform team that spends the quarter making
CI 30 percent faster wins 4 minutes of 124.
That is the argument for measuring before optimizing, and it applies to platform work more than most, because platform teams have a natural bias toward the parts they own.
Sources and further reading
The DORA research program's annual State of DevOps reports, and the current software delivery performance model. Nicole Forsgren and others, "Accelerate". Nicole Forsgren and others, "The SPACE of Developer Productivity", ACM Queue 2021. Matthew Skelton and Manuel Pais, "Team Topologies", for platform as a service to stream-aligned teams and for cognitive load as the organizing constraint. Evan Bottcher on golden paths and on platform as a product. The Backstage documentation for the catalog and plugin model. The CNCF platforms working group white paper and its maturity model. Recent multivocal literature reviews of internal developer portals for the current component taxonomy.
What this chapter established
- A platform's product is the interface application teams write against, and cognitive load is the number it exists to reduce.
- Around 78 percent of organizations above 500 engineers ran a dedicated platform team in 2026, up from roughly 43 percent in 2023.
- A progressive interface gives a near-empty default, declarative overrides, and a visible escape hatch. Forbidding the escape hatch produces a shadow platform.
- Measure escape hatch usage. A cluster of similar overlays is a feature request with evidence attached.
- The portal is the human interface and the platform is the control plane. A portal with nothing behind it goes stale.
- Generate the service catalog from platform state. A catalog that teams maintain by hand is wrong within a month.
- Ephemeral environments replace a shared staging queue. Data is the part that decides whether they are useful: seeded, anonymized, and versioned with the schema.
- The destroy step will sometimes not run. Time-to-live sweepers, hard quotas, and daily reconciliation are the controls that stop orphan accumulation.
- Continuous reconciliation removes drift and will revert an incident fix. Every reconciler needs a documented suspend mechanism in the runbook.
- A golden path must be genuinely easier than the alternative, or it needs enforcement, and enforcement produces routing around it.
- Scorecard checks must be automatic, owned, and fixable. Roll out in reporting mode, and tie enforcement to the level of change rather than to a global cutoff.
- Run the same policy in the pipeline, at admission, and in continuous audit. Every denial names the rule, the field, and the correct value.
- A platform team with a growing ticket queue is a platform that is not finished. Anything done manually three times becomes self-service.
- DORA measures the delivery system, SPACE covers what it omits, and platform-specific metrics say whether the platform is succeeding as a product.
- Never apply these metrics per engineer, never optimize one in isolation, and pair the dashboard with a qualitative survey.
- Instrument the full commit-to-production path per stage. The largest delays are usually process decisions rather than engineering problems.