Introduction
Platform engineering has matured beyond simple automation to become a product discipline. Modern platform teams build Internal Developer Platforms (IDPs) that accelerate development while maintaining standards. This guide covers building platforms that developers love, measuring platform success, and evolving your platform strategy.
The Platform Engineering Maturity Model
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Platform Maturity Levels โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Level 1: Manual โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข Ticket-based infrastructure requests โ โ
โ โข Manual environment provisioning โ โ
โ โข No standardization โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Level 2: Automated โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข Self-service provisioning โ โ
โ โข Infrastructure as Code โ โ
โ โข Basic templates โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Level 3: Platform โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข Internal Developer Platform โ โ
โ โข Golden paths and guardrails โ โ
โ โข Product thinking โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Level 4: Integrated โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข AI-assisted operations โ โ
โ โข Predictive scaling โ โ
โ โข Self-healing systems โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Building the Internal Developer Platform
Platform Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Internal Developer Platform โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Platform Layer โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โ โ Service โ โ CI/CD โ โSecurity โ โ โ
โ โ โ Catalog โ โ Pipeline โ โ Scanning โ โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โ โ Observ- โ โ Database โ โ Secret โ โ โ
โ โ โ ability โ โ Mgmt โ โ Mgmt โ โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Developer Experience โ โ
โ โ Portal โ CLI โ IDE โ Documentation โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Consuming Teams โ โ
โ โ Team A โ Team B โ Team C โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Core Platform Components
Service Catalog
# Backstage service catalog
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Payment processing service
tags:
- go
- microservices
- payments
annotations:
github.com/project-slug: "company/payment-service"
spec:
type: service
lifecycle: production
owner: payments-team
system: commerce
---
kind: API
metadata:
name: payment-api
spec:
type: openapi
lifecycle: production
owner: payments-team
definition:
openapi: 3.0.0
info:
title: Payment API
version: 1.0.0
Self-Service Provisioning
# Platform API for self-service
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ServiceRequest(BaseModel):
name: str
team: str
repository: str
resources: dict
class DatabaseRequest(BaseModel):
name: str
engine: str # postgres, mysql, redis
size: str # small, medium, large
backup_enabled: bool = True
@app.post("/services")
async def create_service(request: ServiceRequest):
"""Provision new service."""
# Create GitHub repo
repo = github.create_repo(request.repository)
# Generate scaffold
template = get_template(request.repository)
repo.upload_template(template)
# Create CI/CD pipeline
pipeline = create_pipeline(request)
# Create Kubernetes resources
k8s = create_deployment(request)
# Add to service catalog
catalog.add_service(request)
return {"status": "created", "resources": {...}}
@app.post("/databases")
async def create_database(request: DatabaseRequest):
"""Provision database."""
db = cloud_sql.create_instance(
name=request.name,
engine=request.engine,
size=request.size,
backup_enabled=request.backup_enabled
)
# Create connection secrets
secrets.create(
name=f"db-{request.name}",
data=db.credentials
)
return {"status": "created", "connection": db.connection_string}
Golden Paths
# Golden path template - Go microservice
apiVersion: platform.example.com/v1
kind: GoldenPath
metadata:
name: go-microservice
spec:
language: Go
framework: gin
structure:
- cmd/
- main.go
- internal/
- handlers/
- service/
- repository/
- pkg/
- api/
- configs/
- Makefile
- go.mod
cicd:
stages:
- name: build
steps:
- go build ./...
- go test ./...
- go lint
- name: security
steps:
- trivy fs
- gosec
- name: deploy
steps:
- docker build
- deploy to k8s
required_checks:
- unit-tests
- lint
- security-scan
- coverage > 80%
defaults:
resources:
cpu: "500m"
memory: "512Mi"
replicas: 3
autoscaling:
enabled: true
min_replicas: 2
max_replicas: 10
target_cpu: 70
Developer Experience
Platform CLI
# Developer platform CLI
import click
from platform import PlatformAPI
@click.group()
def cli():
"""Platform CLI - self-service for developers."""
pass
@cli.command()
@click.argument("name")
def create(name):
"""Create a new service."""
api = PlatformAPI()
click.echo(f"Creating service: {name}")
# Scaffold
api.create_service(name)
# Setup CI/CD
api.setup_cicd(name)
click.echo(f"Service {name} created!")
@cli.command()
@click.argument("name")
def deploy(name):
"""Deploy to environment."""
api = PlatformAPI()
env = click.prompt("Environment (dev/staging/prod)",
type=click.Choice(["dev", "staging", "prod"]))
click.echo(f"Deploying {name} to {env}...")
result = api.deploy(name, env)
if result.success:
click.echo(f"Deployed! URL: {result.url}")
else:
click.echo(f"Failed: {result.error}")
@cli.command()
def status(name):
"""Check service status."""
api = PlatformAPI()
status = api.get_status(name)
for env, info in status.items():
click.echo(f"{env}: {info.version} - {info.status}")
@cli.command()
@click.argument("name")
def scale(name):
"""Scale a service."""
replicas = click.prompt("Number of replicas", type=int)
api = PlatformAPI()
api.scale(name, replicas)
click.echo(f"Scaled to {replicas} replicas")
Developer Portal
# Portal dashboard configuration
apiVersion: platform.example.com/v1
kind: PortalDashboard
metadata:
name: developer-portal
spec:
sections:
- name: "Quick Actions"
widgets:
- type: button
action: /services/new
label: "Create Service"
- type: button
action: /databases/new
label: "Provision Database"
- type: button
action: /environments/new
label: "Create Environment"
- name: "My Services"
widget: service-list
filters:
owned_by: current_user
- name: "Platform Status"
widget: system-status
components:
- cicd-health
- k8s-health
- security-scan-results
- name: "Cost Overview"
widget: cost-summary
period: 30d
- name: "Documentation"
widget: docs
sections:
- getting-started
- platform-guides
- troubleshooting
Platform as a Product
Product Management
# Platform as Product
class PlatformProduct:
"""Treat platform as a product."""
def __init__(self):
self.discoverability = DiscoveryService()
self.feedback = FeedbackService()
self.analytics = AnalyticsService()
def build_roadmap(self) -> list:
"""Build platform roadmap based on user feedback."""
# Gather feedback
feedback_items = self.feedback.get_unresolved()
# Prioritize
prioritized = self.prioritize(feedback_items)
# Create roadmap
return [
{"item": p.feedback, "priority": p.priority, "quarter": p.planned_quarter}
for p in prioritized[:10]
]
def prioritize(self, feedback: list) -> list:
"""Prioritize based on impact and effort."""
scored = []
for item in feedback:
impact = self.calculate_impact(item)
effort = self.estimate_effort(item)
score = impact / effort
scored.append({
"item": item,
"impact": impact,
"effort": effort,
"score": score
})
return sorted(scored, key=lambda x: x["score"], reverse=True)
def calculate_impact(self, item) -> int:
"""Calculate developer impact score."""
return item.request_count * item.team_size
def get_metrics(self) -> dict:
"""Platform health metrics."""
return {
"developer_satisfaction": self.analytics.nps_score(),
"self_service_adoption": self.analytics.self_service_percentage(),
"time_to_first_deploy": self.analytics.average_deploy_time(),
"incident_count": self.analytics.platform_incidents(),
"api_availability": self.analytics.platform_uptime()
}
Feedback Loop
# Developer feedback collection
class FeedbackCollector:
"""Collect and track developer feedback."""
def __init__(self):
self.sources = [
"slack_channel",
"survey",
"support_tickets",
"feature_requests"
]
def collect_all(self) -> list:
"""Collect feedback from all sources."""
feedback = []
for source in self.sources:
feedback.extend(self.collect_from(source))
return feedback
def collect_from(self, source: str) -> list:
"""Collect from specific source."""
if source == "slack_channel":
return self.collect_slack()
elif source == "survey":
return self.collect_survey()
# ...
def close_feedback(self, feedback_id: str, resolution: str):
"""Mark feedback as addressed."""
# Track resolution
# Notify requester
# Update metrics
Measuring Platform Success
Platform Metrics
# Platform KPIs
platform_kpis = {
"developer_experience": {
"nps_score": {
"target": "> 50",
"current": 45,
"trend": "improving"
},
"self_service_adoption": {
"target": "> 80%",
"current": 65,
"trend": "improving"
},
"time_to_first_deployment": {
"target": "< 1 hour",
"current": "2 hours",
"trend": "improving"
}
},
"platform_reliability": {
"uptime": {
"target": "99.9%",
"current": "99.95%"
},
"mttr": {
"target": "< 30 min",
"current": "15 min"
}
},
"efficiency": {
"deploy_frequency": {
"target": "> 10/day",
"current": "15/day"
},
"change_failure_rate": {
"target": "< 15%",
"current": "8%"
}
}
}
Developer Satisfaction
# Quarterly survey configuration
survey:
name: "Platform Satisfaction Q1 2026"
questions:
- id: "nps"
type: "nps"
text: "How likely are you to recommend the platform?"
- id: "ease_of_use"
type: "rating"
text: "How easy is it to use our platform?"
scale: 1-5
- id: "most_valued"
type: "multiple_choice"
text: "What do you value most?"
options:
- "Self-service capabilities"
- "Documentation"
- "Support"
- "Reliability"
- id: "improvements"
type: "free_text"
text: "What would you improve?"
Best Practices
1. Start with Developer Needs
# Discovery-first approach
platform_discovery = [
"Shadow developers for a week",
"Analyze support tickets",
"Survey all platform users",
"Review deployment frequency",
"Identify bottlenecks"
]
2. Build Golden Paths, Not Gateways
# Golden path vs golden gate
comparison = {
"golden_path": [
"Easy to do the right thing",
"Pre-configured templates",
"Built-in best practices",
"Fast to get started"
],
"golden_gate": [
"Block at the end",
"Manual approval",
"Slow feedback",
"Developer frustration"
]
}
3. Measure Everything
# Platform metrics to track
platform_metrics = {
"adoption": [
"Services using platform",
"Self-service percentage",
"Template usage"
],
"velocity": [
"Deploy frequency",
"Lead time",
"Time to first deployment"
],
"reliability": [
"Platform uptime",
"Incident frequency",
"Change failure rate"
],
"satisfaction": [
"NPS score",
"Support ticket volume",
"Feature request completion"
]
}
4. Iterate Based on Feedback
# Continuous improvement
iteration_cycle = {
"week_1": "Collect feedback",
"week_2": "Analyze and prioritize",
"week_3": "Implement improvements",
"week_4": "Measure impact",
"repeat": True
}
Conclusion
Platform engineering transforms how teams deliver software. Key takeaways:
- Product thinking: Treat developers as customers
- Self-service: Enable speed while maintaining standards
- Golden paths: Make the right thing easy
- Measure success: Track adoption, satisfaction, reliability
- Iterate continuously: Build feedback loops
The best platforms disappearโthe developers using them don’t notice the complexity you’ve abstracted away.
Comments