Command Palette

Search for a command to run...

Mission 2.4 · Stage 2 — Self-Service Infrastructure, Automation, and Measuring the Platform

Measuring the Platform: DORA, Developer Experience, and Cost

Goal: A platform dashboard showing DORA metrics per team, golden-path adoption, developer satisfaction, and cost per team, used to steer the platform roadmap.

50 min Free 4 steps 1 break-it drills

By the end of this mission

  • Define and collect the four DORA metrics (plus reliability)
  • Measure developer experience with surveys and the SPACE framework
  • Show cost per team with OpenCost and tags
  • Run the platform as a product: SLOs for the platform itself and a roadmap from data

Part 1

Understand it first

DORA metrics

From the DevOps Research and Assessment program, the best-validated delivery metrics: DEPLOYMENT FREQUENCY (how often you ship to production), LEAD TIME FOR CHANGES (commit to production), CHANGE FAILURE RATE (share of deployments causing a failure that needs remediation), and FAILED DEPLOYMENT RECOVERY TIME (how long to restore after a bad deploy). Later reports add RELIABILITY (meeting SLOs). Throughput and stability move together in high performers; speed and safety are not a trade-off when the platform is good.

With GitOps, the data is already in your systems: commits and PR merges (GitHub), deploys (Argo CD sync events or config-repo commits), and failures and restores (incidents, rollbacks, reverts). Measure per team and watch trends, and never use them to rank individuals, or the numbers get gamed.

Developer experience

Metrics from systems miss friction that only people feel: flaky tests, slow local builds, confusing docs, waiting on reviews. The SPACE framework (Satisfaction, Performance, Activity, Communication and collaboration, Efficiency and flow) reminds you to combine perception data (a short quarterly survey: 'how easy is it to deploy a change?', 'what slowed you down this month?') with system data. The DX Core 4 and similar frameworks package the same idea.

Cost visibility

OPENCOST (CNCF) allocates Kubernetes cost to namespaces, labels, and teams using real cloud prices, including idle capacity. Combined with AWS cost allocation tags (set by Terraform, Crossplane compositions, and Karpenter) you can show each team its spend (SHOWBACK) or bill it (CHARGEBACK). Visibility alone typically changes behaviour: right-sizing requests, deleting stale previews (Mission 2.3), and using Spot (Mission 0.3).

The platform's own SLOs

The platform is a product with users, so it gets SLOs (SRE course): 'golden-path template succeeds 99% of the time', 'CI queue time p90 < 2 minutes', 'Argo CD sync of a merged change < 5 minutes', 'portal availability 99.5%'. When the platform breaks, every team is blocked, so platform incidents deserve the same rigour as customer incidents.

Where each metric comes fromdiagram
Rendering diagram…

Part 2

Your project after this mission · 4 files change

shoplite-platform/
  • shoplite-platform/
    • addons/
      • opencost/
        • opencost-app.yamlnew
    • docs/
      • dx-survey.mdnew
    • metrics/
      • dora-queries.sqlnew
      • platform-slos.yamlnew

Part 3

Build it, step by step

  1. 1

    Collect deployments and changes

    Apache DevLake (or Google's Four Keys, or a commercial tool) ingests GitHub, Argo CD, and incident data and computes DORA metrics out of the box. Whatever the tool, the model is three tables: CHANGES (commit SHA, time), DEPLOYMENTS (SHA, environment, time, success), and INCIDENTS (start, end, caused-by deploy). These queries show the calculations, so you understand the numbers the dashboards print.

    shoplite-platform/metrics/dora-queries.sqlwhole filesql
    -- Deployment frequency: prod deploys per team per week
    SELECT team, date_trunc('week', deployed_at) AS week, count(*) AS deploys
    FROM deployments WHERE env = 'prod' GROUP BY 1, 2;
    
    -- Lead time for changes: median commit → prod deploy, last 30 days
    SELECT d.team,
           percentile_cont(0.5) WITHIN GROUP (ORDER BY d.deployed_at - c.committed_at) AS median_lead_time
    FROM deployments d JOIN changes c ON c.sha = ANY (d.shas)
    WHERE d.env = 'prod' AND d.deployed_at > now() - interval '30 days'
    GROUP BY d.team;
    
    -- Change failure rate: share of prod deploys linked to an incident or rollback
    SELECT team,
           round(100.0 * count(*) FILTER (WHERE caused_incident) / count(*), 1) AS change_failure_pct
    FROM deployments WHERE env = 'prod' AND deployed_at > now() - interval '90 days'
    GROUP BY team;
    
    -- Failed deployment recovery time: median incident duration for deploy-caused incidents
    SELECT team, percentile_cont(0.5) WITHIN GROUP (ORDER BY resolved_at - started_at) AS median_recovery
    FROM incidents WHERE caused_by_deploy IS NOT NULL GROUP BY team;
  2. 2

    Install OpenCost

    Chart opencost from https://opencost.github.io/opencost-helm-chart, pointed at the cluster's Prometheus. Then query cost per team label.

    terminal
    $ kubectl -n opencost port-forward svc/opencost 9003:9003 &
    curl -s 'localhost:9003/allocation/compute?window=7d&aggregate=label:shoplite.dev/team' | jq -r '.data[0] | to_entries[] | "\(.key)\t$\(.value.totalCost|floor)"'
    ── expected output ──
    checkout $412
    storefront $298
    catalog $187
    fulfilment $96
    __idle__ $341
  3. 3

    Give the platform SLOs

    Written with Sloth (or Pyrra), which generates Prometheus recording and burn-rate alert rules (Observability course, burn-rate alerts). Check the exact metric names your Backstage and Argo CD versions export (/metrics) before copying queries.

    shoplite-platform/metrics/platform-slos.yamlwhole fileyaml
    version: prometheus/v1
    service: shoplite-platform
    slos:
      - name: golden-path-success
        objective: 99
        description: Backstage scaffolder runs that complete successfully.
        sli:
          events:
            error_query: sum(rate(scaffolder_task_count{result="failed"}[{{.window}}]))
            total_query: sum(rate(scaffolder_task_count[{{.window}}]))
        alerting: { name: GoldenPathFailing, page_alert: { disable: true } }
      - name: gitops-sync-success
        objective: 99.5
        description: Argo CD sync operations that succeed.
        sli:
          events:
            error_query: sum(rate(argocd_app_sync_total{phase!="Succeeded"}[{{.window}}]))
            total_query: sum(rate(argocd_app_sync_total[{{.window}}]))
  4. 4

    Ask developers

    A five-question survey, every quarter, the same questions so trends are comparable. Free-text answers are the most valuable part: they become roadmap items.

    shoplite-platform/docs/dx-survey.mdwhole filemarkdown
    # ShopLite developer experience survey (5 minutes)
    
    1. How easy is it to get a change into production? (1 very hard – 5 very easy)
    2. How often did tooling or the platform block you this quarter? (never / monthly / weekly / daily)
    3. How confident are you when you deploy? (1–5)
    4. How easy was it to find the information you needed (docs, owners, runbooks)? (1–5)
    5. What single thing slowed you down most this quarter? (free text)

Checkpoint — you should now have

  • ✓A dashboard shows DORA metrics per team with a 90-day trend.
  • ✓OpenCost shows spend per team, including idle capacity.
  • ✓The platform has its own SLOs with alerts.
  • ✓The next quarter's platform roadmap cites survey and metric data.

Part 4

Break it on purpose

Make each change, run the command, and read the error before revealing the diagnosis. Recognising these messages on sight is what makes you fast on a real team. Undo the change afterwards.

Break #1

Metrics become targets

Leadership sets a goal: 'every team must deploy 20 times a week', and ranks teams on a leaderboard.

terminal
$ git log --since=1.week --oneline shoplite-gitops | grep -c 'bump'
── what you'll see ──
412 # tag bumps with no code changes, e.g. "chore: bump to same image"

Part 5

Interview questions from this mission

01

What are the DORA metrics and how would you collect them?

02

How do you decide what to build next on the platform?

0/4 · 0%