Developer Experience: What Platform Teams Get Wrong

Philip Rehberger Apr 17, 2026 7 min read

Platform teams exist to make developers faster. Most of them end up making developers slower. Here is where they go wrong and what high-performing platform teams do differently.

Developer Experience: What Platform Teams Get Wrong

A platform team's job is to multiply the output of the engineers who use their platform. Every hour a product engineer spends wrestling with infrastructure, debugging CI failures, or waiting for environment provisioning is an hour not spent on product work. Platform teams exist to make that time zero.

Most platform teams fail at this. Not because they are not working hard — they often work very hard — but because they optimize for the wrong things. This article is about what those wrong things are and what the right things look like.

Mistake 1: Building for Completeness Instead of Adoption

A platform that nobody uses is worse than no platform at all. It consumed resources to build, creates maintenance burden, and may still leave product engineers cobbling together their own solutions.

The sign that a platform team has fallen into this trap: they measure success by features shipped, not by adoption metrics. They present roadmaps full of capabilities and celebrate completing them without tracking whether anyone uses what was built.

High-performing platform teams track:

  • How many teams use the internal deployment tool (versus rolling their own)
  • What percentage of new services use the standard service template
  • How long it takes a new engineer to get their first code to production
  • How often engineers contact the platform team for help (high volume = friction)

Before building a new capability, talk to the teams that would use it. Watch them work. Where are they spending time they should not have to? The best platform features address real, observed pain — not imagined future needs.

Mistake 2: Abstracting Away Understanding

There is a seductive idea in platform engineering: if you abstract infrastructure away completely, product engineers do not need to understand it. Give them a button that says "deploy" and they will be happy.

This works until something breaks. When the abstraction fails and the engineer has no mental model of what is underneath, they cannot debug it. They file a ticket with the platform team. The platform team becomes a bottleneck.

# Bad: a "deploy" command that hides everything
./platform deploy --app myapp
# Output: "Deployed!"

# Good: a command that shows what it's doing, with explanations
./platform deploy --app myapp
# Output:
# Building Docker image...
#   docker build -t myapp:abc123def . (run with --verbose to see full output)
# Pushing to container registry...
#   docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:abc123def
# Applying Kubernetes deployment...
#   kubectl set image deployment/myapp myapp=...abc123def
# Waiting for rollout (timeout: 5m)...
#   1/3 pods updated
#   2/3 pods updated
#   3/3 pods updated
# Health check...
#   GET https://myapp.internal/health → 200 OK
# Deployed successfully in 2m 14s

The second version teaches the engineer what is happening. When the push fails because they are not logged into ECR, they understand what "push failed" means. When the rollout hangs, they know enough to run kubectl describe pod to investigate.

Abstractions should reduce keystrokes, not remove understanding.

Mistake 3: One-Size-Fits-All Platform Standards

Platform teams often set uniform standards: every service must use the approved CI template, must deploy with the standard Helm chart, must use the approved logging library. The intent is good — consistency reduces cognitive overhead.

The problem: a payment processing service with strict compliance requirements has very different needs than a marketing landing page. Forcing both to use the same CI pipeline and the same deployment configuration means the pipeline is either too permissive for payments or too heavyweight for the landing page.

Better approach: layered defaults with escape hatches.

# .platform.yml — per-service configuration that overrides platform defaults
service:
  name: payment-processor
  tier: critical  # Affects deployment strategy, monitoring thresholds, alerting

ci:
  template: standard  # or: minimal, compliance, custom
  additional_checks:
    - pci-dss-scan
    - dependency-audit-strict

deployment:
  strategy: blue-green  # Default is rolling-update
  health_check_timeout: 600  # 10 minutes instead of default 5
  rollback_on_error: true

monitoring:
  slo_latency_p99_ms: 200   # Strict SLO for this service
  slo_error_rate_pct: 0.1   # 0.1% vs default 1%

The platform provides opinionated defaults. Teams can override what they need. Teams that need something the platform does not support can opt out of that specific piece while staying on the platform for everything else.

Mistake 4: Poor Documentation and Discoverability

Platform documentation is often either nonexistent, out of date, or technically correct but practically unusable. Documentation written by the person who built the system rarely accounts for what a newcomer does not already know.

Test your documentation by watching a new engineer follow it. Time how long it takes them to get from zero to working. Watch where they get stuck. The stuck points are documentation failures.

A good internal developer portal follows these principles:

Task-oriented, not reference-oriented: Most documentation is organized around what things are. Developers need documentation organized around what they want to do.

# Bad structure (reference-oriented):
## Infrastructure
### Kubernetes
#### Namespaces
#### Deployments
#### Services

# Good structure (task-oriented):
## I want to...
- Deploy a new service for the first time
- Add environment variables to my service
- Set up a database for my service
- Debug a failing deployment
- Scale my service horizontally

Working examples: Every how-to should have a full, working example. Not pseudocode — actual commands you can copy and run.

Version information: Which version of the CLI does this apply to? Which Kubernetes version? When was this last verified?

Feedback mechanism: A "Was this helpful?" button and a link to fix the documentation. Engineers who find documentation wrong will fix it if the barrier is low enough.

Mistake 5: Treating Engineers as Ticket-Submitters

Platform teams that run a ticket queue are platform teams that are bottlenecks. When a product engineer needs a new environment variable, a new service account, or a new database, they should not have to open a ticket and wait.

Self-service is the goal. Everything that can be done by the requesting team should be done by the requesting team — with guardrails, not gatekeepers.

# Bad: engineer opens ticket "Please create a database for service X"
# Platform team creates database 3 days later

# Good: engineer runs a command
platform database create \
  --service payment-processor \
  --engine mysql \
  --size small \
  --backup-retention-days 30
# Output:
# Database created: payment-processor-prod-db
# Connection string stored in Secrets Manager: prod/payment-processor/db
# Backup enabled: daily at 02:00 UTC, retained for 30 days
# Estimated monthly cost: $45/month
# Ready in approximately 5 minutes

The platform enforces policies (naming conventions, backup requirements, cost limits) automatically. The engineer gets their database without waiting for a human in the loop.

Mistake 6: Neglecting Local Development

A platform that works beautifully in CI but makes local development painful creates a hidden tax. Engineers who cannot reproduce production behavior locally spend enormous amounts of time debugging against CI — slow, expensive, and frustrating.

Prioritize local development parity:

# docker-compose.yml — production-equivalent local environment
version: '3.8'

services:
  app:
    build: .
    environment:
      APP_ENV: local
      DB_HOST: db
      REDIS_HOST: redis
      QUEUE_CONNECTION: redis
    volumes:
      - .:/app  # Live code reloading
    ports:
      - "8000:8000"

  worker:
    build: .
    command: php artisan queue:work --tries=3
    environment:
      DB_HOST: db
      REDIS_HOST: redis

  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: myapp
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - db-data:/var/lib/mysql

  redis:
    image: redis:7-alpine

volumes:
  db-data:

Provide a single command to start the environment:

# platform dev start — starts local environment and checks dependencies
platform dev start
# Checking Docker is running... OK
# Checking .env file exists... OK
# Starting services...
# Waiting for database to be ready...
# Running migrations...
# Seeding development data...
# Environment ready at http://localhost:8000

What Good Looks Like

A high-performing platform team is measured by one thing: how fast product engineers can deliver value. Concrete signs it is working:

  • A new engineer deploys to production on their first day
  • The time from "code merged" to "running in production" is under 10 minutes
  • Engineers rarely contact the platform team for routine operations
  • The platform team spends most of their time on new capabilities, not support tickets
  • Product teams voluntarily adopt platform tools because they make life easier

The platform team exists in service to product engineers. The moment the relationship inverts — product engineers existing to satisfy platform team requirements — the value has been lost.

Building secure, reliable systems? We help teams deliver software they can trust. scopeforged.com

Share this article

Related Articles

Need help with your project?

Let's discuss how we can help you build reliable software.