Platform Engineering

Self-service is a journey, not a switch you flip

· Taz Bruce

In a previous post I argued that AI made code cheap and exposed the real constraint: the manual gauntlet a change runs before it reaches production. This is the follow-up I promised, about the way out. It is not a single tool you buy or a repo you stand up. It is a journey, and most organisations are further back on it than they think.

I find it helps to name the stages, because “self-service” gets stuck to all of them and the word stops meaning anything. Here is the model I use: tickets, a central infrastructure-as-code repo, that same code pushed out into each app’s repo, and finally a control plane that takes intent instead of infrastructure. Each stage is a genuine step up. Each one also has a ceiling, and the trap is mistaking your current ceiling for the destination.

Phase one: tickets

A human asks another human for infrastructure, and a human does the work. A developer needs a database, they raise a ticket, someone on the platform team picks it up and provisions it.

What it gets you. It is simple and it is legible. Every request is captured, every change has an owner and an audit trail, and a person with context is looking at each one. For a small org, or a genuinely rare and risky operation, that is not a bad place to be.

Where it stops. A ticket-based platform can only move as fast as the humans in it, and those humans are a fixed, expensive resource that does not scale with demand. When demand was linear you could staff for it. It is not linear any more: one engineer with an agent can generate a week of infrastructure requests in a morning. No amount of hiring closes that gap, because you are scaling people against a thing that no longer needs people to produce it. Tickets were always a ceiling. AI just raised the floor until everyone can see it.

Phase two: a central infrastructure-as-code repo

This is where most organisations live, and I want to be careful here, because getting to code is genuinely the most important step most teams will take. A central repo full of Terraform, or Pulumi, or whatever you like, that a developer opens a pull request against.

What it gets you. The infrastructure is codified, reviewable and versioned. It kills the console clicks nobody remembers making. Changes have history, they can be reverted, and the platform becomes something you can reason about instead of a pile of drift. The developer can author the change themselves rather than describing it in a ticket for someone else to interpret.

Where it stops. Look at what happens after the developer opens that pull request. It still needs an approval from the platform team. It still needs someone who understands the blast radius of the module. It still sits in a queue. We have not removed the human gate, we have moved it from a ticket field to a review comment. If the number of changes your platform can absorb is capped by how many pull requests your team can review in a week, that is not self-service. It is a ticket wearing a pull request as a costume.

Phase two and a half: Terraform moves into the app repo

Some teams push phase two further, and it deserves its own stop, because it is a real step up. Instead of a central repo everyone funnels through, the Terraform lives alongside the application, in the product team’s own repository. Whoever owns the service owns the infrastructure code that runs it, right next to it.

What it gets you. It kills the central-repo bottleneck. There is no queue behind another team’s review and no shared repo to contend on. Ownership and infrastructure sit together, each team moves at its own pace, and “you build it, you run it” finally has the code to back it up. If you are here, you are ahead of most.

Where it stops. Notice what has not changed. The developer is still writing Terraform. They still have to understand the module, the provider, the account, the networking primitive underneath. We distributed the authoring and removed the central gate, which is a genuine win, but the level of abstraction is exactly what it was before. There is a new cost, too: patterns duplicate across dozens of repos and drift apart, and there is still no unified interface a developer or an agent can consume. It is more self-service, and it is still infrastructure, not intent.

The fragmentation problem neither stage fixes

There is a deeper issue that a central repo and an app repo both leave untouched. In most mature organisations there is no such thing as “the platform team”. There are many of them: an events team, an API team, an observability team, a cloud team, a CI/CD team. Each owns a genuine capability, and each, left to its own devices, decides for itself how developers consume it.

So one capability is a ticket. Another is a Terraform module in a specific repo. Another is a YAML file that has to live in exactly the right place. Another is a Slack request, or a form, or a bespoke CLI. Every team made a locally reasonable choice, and the developer has to learn five different front doors to stand up one service. The fragmentation is not in the infrastructure. It is in the experience of asking for it.

And most product teams cannot even tell our platform teams apart. The distinctions we care about, events versus APIs versus observability versus cloud, are our org chart, not theirs. To them we are just “platform”, one thing they consume. So it lands as whiplash when the same “platform” bounces them between front doors, saying that is not my product, go raise that one somewhere else. We have exposed our internal team boundaries as the interface.

We solved this shape one layer up. Application teams did not each invent their own way of exposing an API to the business. They agreed on an API gateway: one consistent front door for auth, routing and policy, so consuming any service felt the same. Our platform capabilities need the same agreement.

Who owns self-service, and how do platform teams align?

That agreement is the hard part, and it is an alignment problem inside the platform organisation, not between platform and product. Self-service only feels like one thing to a developer if the many teams behind it agree to make it one thing, and someone has to own that shared vision and drive it.

The ownership question is genuinely open, and I do not think there is a single right answer. Is self-service a dedicated platform or golden-path team’s product, with every capability team plugging into it? Does it belong to whoever owns Kubernetes, if that is the substrate everything runs on? Is it federated, each team publishing to an agreed interface while a small group holds the standard? Different organisations will land in different places, and that is fine. What is not fine is leaving it unowned, because left alone each team optimises for its own slice and the developer inherits the fragmentation as their day-to-day.

Phase three: a control plane that takes intent

Two ceilings have stacked up by now. The developer is still authoring infrastructure, and there is still no single, owned front door to consume, just a set of teams each publishing their own. A control plane closes both at once, by changing what the developer hands you in the first place, from an implementation to an outcome.

Instead of authoring infrastructure, they express intent. “I need a Postgres database for this service, production-grade, in these regions.” They do not write the Terraform. They do not know or care which module, which account, which networking primitive sits underneath. They state what they want, and a control plane turns that intent into real, governed infrastructure.

This is the unified front door from earlier. Instead of every platform team publishing its own way of being consumed, they all sit behind one gateway that speaks intent: the API gateway idea applied to the platform itself. One entry point, whether you want a database, a topic, a dashboard or a pipeline, with each team still owning the capability behind it but no longer owning a bespoke way in. Kubernetes operators, Crossplane, an internal platform API, a Backstage template that provisions rather than scaffolds. The technology varies. The shape is the same: developers and agents describe outcomes through one interface, and the platform owns how those outcomes get built safely.

This is not the frontier, it is where the industry is heading

If this sounds like a moonshot, it helps to know how mainstream it already is. Gartner expects 80% of large software engineering organisations to have platform teams by 2026, up from 45% in 2022. Platform engineering stopped being a fringe idea years ago, and the control plane is simply where a serious platform team ends up.

The tooling is proven, not experimental. Crossplane, one of the most common ways to build an intent-based control plane on Kubernetes, graduated from the CNCF in October 2025, the same maturity bar as Kubernetes and Prometheus, with more than 100 million downloads and production adopters including Deutsche Bahn, Apple, Nike, Autodesk, SAP, Grafana Labs and the NASA Science Cloud. Deutsche Bahn runs the entire developer platform for its engineers on it: a 100% GitOps, self-service front door to cloud infrastructure.

And it is a pattern, not a single product. The Kubernetes resource model, operators, Crossplane, Backstage software templates, a hand-rolled internal platform API: these are all ways of doing the same one thing, exposing intent and owning the implementation behind it. You are not betting on a vendor. You are adopting a shape the whole industry is converging on.

What a control plane actually buys you

The human comes out of the request path. Guardrails live in the platform as policy, so the safe choice is the only choice on offer and the common case needs no approval at all. Provisioning that used to take days or weeks of tickets and handoffs collapses to the minutes it takes to submit a claim. Teams that make the move report numbers that are hard to argue with: one platform team, Convera, reported a 30% improvement in time to market and a change-failure rate under 5% after moving to a self-service platform.

And it is the interface AI actually needs. Agents are extraordinary at expressing intent and hopeless at navigating your bespoke maze of tickets and tribal knowledge. A clean, declarative front door is exactly what lets an agent stand up infrastructure safely, which means the control plane is not only how you serve developers faster. It is how you let AI help run the platform instead of only writing code against it.

The objections worth answering

I have made this case enough times to know the pushback by heart, and most of it deserves a real answer, not a hand-wave.

“This is overkill for us.” You do not build the whole thing on day one. You pave the one or two paths people wait on most, a database, an environment, a topic, and leave everything else as it is. The control plane earns its next path by proving the first. Overkill is building for scale you do not have; this is the opposite, removing toil you already have.

“Is building a platform even our job? This feels like undifferentiated heavy lifting.” Often the honest answer is adopt or buy rather than build. The control-plane pattern is a CNCF-graduated project and a stack of open standards, not a bespoke system you invent from scratch. What you own is the thin layer of golden paths on top, the part that reflects how your organisation actually ships. That layer is the differentiator. The plumbing is a commodity you should take off the shelf.

“Who maintains it, and does the platform team just become the bottleneck again?” Only if you build a snowflake. The whole point is that the human leaves the per-request path: the team maintains one control plane instead of servicing a thousand tickets, and that cost is amortised across every request forever rather than paid again on each one. You are trading linear toil for fixed maintenance.

“What about lock-in?” This is the best reason to favour the open, Kubernetes-native end of the spectrum. Building on the Kubernetes resource model and a graduated project like Crossplane keeps your intent APIs portable and your control plane out of somebody’s proprietary console. You are standardising on an interface, not surrendering to a vendor.

But won’t abstraction mean teams don’t understand their systems?

This is the objection I hear most, and the one worth ending on, because it is usually where these conversations die.

The argument goes: abstract the infrastructure away and teams will not know how it works, so when something breaks they are helpless. I understand the instinct. I just think it argues for the opposite of what people use it to argue for.

If abstracting your platform leaves teams unable to understand or debug it, that is not proof the abstraction is bad. It is proof your documentation, observability, monitoring and guardrails are not good enough yet. The abstraction did not create that gap, it exposed it. A good abstraction comes with the ability to see through it when you need to: clear docs, real telemetry, sensible defaults, and guardrails that stop the dangerous thing before it happens rather than explaining it in a postmortem.

We do not ask every developer to understand the internals of the cloud provider they build on, or the language runtime they ship on. We trust those abstractions precisely because they are well documented, observable and hard to misuse. Holding your internal platform to a lower standard than AWS holds its APIs is not rigour. It is just a reason to keep the keys.

Where this leaves you

The stages are cumulative and honest. Tickets give you control and a ceiling. A central IaC repo gives you code and a review queue. Terraform in the app repo gives you ownership and leaves you still authoring infrastructure. A control plane gives you intent, and asks for the platform investment the earlier stages let you defer. The trap at every stage is the same: declaring the current one “done”.

Knowing the destination is not the same as knowing how to build it. In the next post I want to get concrete and actually stand up a control plane with Crossplane, so this stops being architecture-diagram talk and turns into something you can run. That one is coming soon, once I have done it justice.