ЁЯПл The SchoolтА║ЁЯПЕ Engineering LeadershipтА║ЁЯУИ рдзрдбрд╛ 08 тАФ Delivery metrics: DORA four keys, flow, рдЖрдгрд┐ Goodhart's law
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯУИ рдзрдбрд╛ 08 тАФ Delivery metrics: DORA four keys, flow, рдЖрдгрд┐ Goodhart's law

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-07-technical-debt ┬╖ рдкреБрдврдЪрд╛: lesson-09-team-topologies


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбрд╛ 07, рдЖрдгрд┐ delivery system рдЪреЗ рдореЛрдЬрдорд╛рдк. DORA four keys тАФ deployment frequency, lead time for changes, change failure rate, рдЖрдгрд┐ failed-deployment recovery time тАФ рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд reliability; cycle time рдЖрдгрд┐ flow efficiency рд╕рд╛рд░рдЦреЗ flow metrics; рдЖрдгрд┐ Goodhart's law, рдореНрд╣рдгрдЬреЗ рдпрд╛рдВрдкреИрдХреА рдХреЛрдгрддреЗрд╣реА рдорд╛рдк target рдмрдирд▓реЗ рдХреА рддреНрдпрд╛рдЪреЗ рдХрд╛рдп рд╣реЛрддреЗ. metrics() lead/demo.py рдордзреНрдпреЗ; dora() рдЖрдгрд┐ flow() lead/models.py рдордзреНрдпреЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛ рдЬрд╛рдгреВрди рдШреНрдпрд╛рдпрдЪреЗ рдЖрд╣реЗ рдХреА рдЧрдгрд┐рдд рд╡рд┐рднрд╛рдЧ рдЪрд╛рдВрдЧрд▓реЗ рдХрд╛рдо рдХрд░рддреЛ рдЖрд╣реЗ рдХрд╛. рдореНрд╣рдгреВрди рддреА рдХрд╛рд╣реА рдЧреЛрд╖реНрдЯреА рдореЛрдЬрддреЗ: рдирд╡реЗ рдзрдбреЗ рдХрд┐рддреА рд╡реЗрд│рд╛ рддрдпрд╛рд░ рд╣реЛрддрд╛рдд, рддреНрдпрд╛рдВрдирд╛ рдХрд┐рддреА рд╡реЗрд│ рд▓рд╛рдЧрддреЛ, рдЖрдгрд┐ рдХрд┐рддреА рд╡реЗрд│рд╛ рдПрдЦрд╛рджрд╛ рдзрдбрд╛ рдЪреБрдХрддреЛ. ЁЯУК

рдЙрдкрдпреЛрдЧреА! рдЬреЛрдкрд░реНрдпрдВрдд рддреА рдЕрд╕реЗ рдореНрд╣рдгрдд рдирд╛рд╣реА: "рдЖрдЬрдкрд╛рд╕реВрди 10 рдкреИрдХреА 1 рдкреЗрдХреНрд╖рд╛ рдХрдореА рдзрдбреЗ рдЪреБрдХрд▓реЗ рдкрд╛рд╣рд┐рдЬреЗрдд."

рдордЧ рдХрд╛рд╣реАрддрд░реА рд╡рд┐рдЪрд┐рддреНрд░ рдШрдбрддреЗ. рд╡рд┐рднрд╛рдЧ рд╕реБрдзрд╛рд░рдд рдирд╛рд╣реА. рдкрдг рдЖрдХрдбрд╛ рд╕реБрдзрд╛рд░рддреЛ. рдПрдЦрд╛рджрд╛ рдзрдбрд╛ рдЪреБрдХрд▓рд╛ рдХреА рд▓реЛрдХ рддреНрдпрд╛рд▓рд╛ "рдирд┐рдпреЛрдЬрд┐рдд рдмрджрд▓" рдореНрд╣рдгреВ рд▓рд╛рдЧрддрд╛рдд. ЁЯЩИ рдЖрдХрдбрд╛ 17% рд╡рд░реВрди 6% рд╡рд░ рдпреЗрддреЛ. рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдВрдирд╛ рдкреВрд░реНрд╡реАрдЗрддрдХреЗрдЪ рд╡рд╛рдИрдЯ рдзрдбреЗ рдорд┐рд│рд╛рд▓реЗ.

рдордЧ рддреА рдореНрд╣рдгрддреЗ: "рдЖрдгрдЦреА рдзрдбреЗ рд╣рд╡реЗрдд!" рдЖрдгрд┐ рд╡рд┐рднрд╛рдЧ рдкреНрд░рддреНрдпреЗрдХ рдЫреЛрдЯреНрдпрд╛ worksheet рд▓рд╛ "рдзрдбрд╛" рдореНрд╣рдгреВрди рдореЛрдЬреВ рд▓рд╛рдЧрддреЛ. рдЖрдХрдбрд╛ рджреБрдкреНрдкрдЯ рд╣реЛрддреЛ. рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдХрд╛рд╣реАрдЪ рдирд╡реАрди рд╢рд┐рдХрдд рдирд╛рд╣реАрдд. ЁЯУДЁЯУДЁЯУД

рдХрддрд░рд┐рдирд╛ рд╕рдордЬрд╛рд╡рддреЗ: "рдПрдЦрд╛рджрд╛ рдЖрдХрдбрд╛ target рдмрдирд▓рд╛ рдХреА рд▓реЛрдХ рдореЛрдЬрд▓реНрдпрд╛ рдЬрд╛рдгрд╛рд▒реНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдРрд╡рдЬреА рдЖрдХрдбреНрдпрд╛рд╡рд░рдЪ рдХрд╛рдо рдХрд░реВ рд▓рд╛рдЧрддрд╛рдд." рдореНрд╣рдгреВрди рддреА рдЖрдХрдбреНрдпрд╛рдВрдЪрд╛ рд╡рд╛рдкрд░ рд╡рд┐рднрд╛рдЧ рдХрд╕рд╛ рдХрд╛рдо рдХрд░рддреЛ рдпрд╛рдмрджреНрджрд▓ рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рдгреНрдпрд╛рд╕рд╛рдареА рдХрд░рддреЗ тАФ рд╢рд┐рдХреНрд╖рд┐рдХрд╛рдВрдЪреА рдХреНрд░рдорд╡рд╛рд░реА рд▓рд╛рд╡рдгреНрдпрд╛рд╕рд╛рдареА рдХрдзреАрдЪ рдирд╛рд╣реА.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    l["ЁЯУж 18 deploys in 4 weeks"] --> k["four keys<br/>4.5/week ┬╖ lead 18 h<br/>CFR 16.7% ┬╖ recovery 45 min"]
    l --> a["reliability<br/>availability 99.52%"]
    k -->|"target: CFR under 10%"| g1["2 failures relabelled<br/>CFR 5.6% ┬╖ availability still 99.52%"]
    k -->|"target: deploy more"| g2["18 no-op deploys<br/>9.0/week ┬╖ users see nothing new"]
    f["ЁЯМК flow: cycle times 5тАУ12 days<br/>flow efficiency 40%"]

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/engineering-leadership/lesson-diagrams.html#l08

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдЯреАрдордЪреНрдпрд╛ рдХрд╛рдорд╛рдЪреНрдпрд╛ рдкрджреНрдзрддреАрддрд▓реЗ рдмрджрд▓ рдорджрдд рдХрд░рдд рдЖрд╣реЗрдд рдХрд╛ рд╣реЗ lead рд▓рд╛ рдХрд│рд╛рдпрд▓рд╛ рд╣рд╡реЗ, рдЖрдгрд┐ рднрд╛рд╡рдирд╛ рд╡рд┐рд╢реНрд╡рд╛рд╕рд╛рд░реНрд╣ рдирд╕рддрд╛рдд. Four keys рд╡реНрдпрдХреНрддреАрдВрдЪреЗ рдирд╡реНрд╣реЗ рддрд░ delivery system рдЪреЗ рд╡рд░реНрдгрди рдХрд░рддрд╛рдд тАФ рдмрджрд▓ users рдкрд░реНрдпрдВрдд рдХрд┐рддреА рд╡реЗрдЧрд╛рдиреЗ рдЖрдгрд┐ рдХрд┐рддреА рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдкреЛрд╣реЛрдЪрддрд╛рдд. рдЖрдгрд┐ рдХрд╛рд░рдг рдЙрдкрдпреЛрдЧреА metric рдмрд┐рдШрдбрд╡рдгреНрдпрд╛рдЪрд╛ рд╕рд░реНрд╡рд╛рдд рдЬрд▓рдж рдорд╛рд░реНрдЧ рдореНрд╣рдгрдЬреЗ рддреНрдпрд╛рд▓рд╛ target рдмрдирд╡реВрди рд▓реЛрдХрд╛рдВрд╢реА рдЬреЛрдбрдгреЗ: рдЯреАрдо рдХрд╕рд╛рд╣реА рдХрд░реВрди рдЖрдХрдбрд╛ рд╕реБрдзрд╛рд░реЗрд▓.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

lead/models.py рдордзреАрд▓ dora(log, weeks) deploys (lead time hours, failed?, minutes of user impact) рдпрд╛ рд░реВрдкрд╛рдд рдШреЗрддреЗ рдЖрдгрд┐ рдкрд░рдд рджреЗрддреЗ: рдЖрдард╡рдбреНрдпрд╛рдЪреА frequency, median lead time, change failure rate, failed deploys рдЪрд╛ median recovery time, рдЖрдгрд┐ availability (1 тИТ impact minutes ├╖ 28 рджрд┐рд╡рд╕рд╛рдВрддрд▓реА minutes). Impact minutes deploy рд▓рд╛ рдХреЛрдгрддреЗрд╣реА рд▓реЗрдмрд▓ рд▓рд╛рд╡рд▓реЗ рддрд░реА рдореЛрдЬрд▓реА рдЬрд╛рддрд╛рдд тАФ рдЖрдгрд┐ рдпрд╛рдЪ рдорд╛рд░реНрдЧрд╛рдиреЗ demo relabelling рдЙрдШрдбреЗ рдкрд╛рдбрддреЛ. flow(items) (start day, end day, active days) рдШреЗрддреЗ рдЖрдгрд┐ cycle times рд╡ flow efficiency рдкрд░рдд рджреЗрддреЗ. lead/demo.py рдордзреАрд▓ metrics() рдПрдХ рдкреНрд░рд╛рдорд╛рдгрд┐рдХ log рдЖрдгрд┐ рджреЛрди рдлрд╕рд╡рд▓реЗрд▓реЗ logs рдЪрд╛рд▓рд╡рддреЗ. рд╣реЗ рдЖрдХрдбреЗ рдПрдХрд╛ system рдЪреЗ рд╡рд░реНрдгрди рдХрд░рддрд╛рдд: рд╡рд┐рдЪрд╛рд░ рдХрд░рдгреНрдпрд╛рдЪреЗ рд╕рд╛рдзрди, рд▓реЛрдХрд╛рдВрд╕рд╛рдареАрдЪреЗ рд╕реВрддреНрд░ рдирд╡реНрд╣реЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 lead/demo.py metrics
python3 - <<'EOF'
import sys; sys.path.insert(0, "lead"); from models import dora, flow
leads = [20, 6, 30, 52, 8, 4, 26, 72, 10, 14, 5, 28, 48, 9, 22, 3, 16, 40]
fails = {3: 45, 7: 120, 12: 30}
for hidden in (0, 1, 2, 3):
    relabel = list(fails)[:hidden]
    log = [(l, i in fails and i not in relabel, fails.get(i, 0)) for i, l in enumerate(leads)]
    d = dora(log, 4)
    print(f"relabel {hidden} of 3 failures тЖТ CFR {d['cfr']:>5.1%} ┬╖ availability {d['availability']:.2%}")
cyc, eff = flow([(0, 5, 2), (1, 9, 3), (2, 4, 2), (3, 15, 4), (5, 8, 2), (6, 16, 3)])
cyc2, eff2 = flow([(0, 3, 2), (1, 5, 3), (2, 4, 2), (3, 8, 4), (5, 7, 2), (6, 10, 3)])
print(f"board A: cycle {cyc} days ┬╖ flow efficiency {eff:.0%}")
print(f"board B: cycle {cyc2} days ┬╖ flow efficiency {eff2:.0%}")
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

metrics рд╣реЗ рдЫрд╛рдкрддреЗ:

   deployment frequency 4.5/week ┬╖ lead time for changes (median) 18 h ┬╖ change failure rate 16.7% ┬╖ failed-deploy recovery (median) 45 min ┬╖ availability 99.52%
тФАтФА target 'change failure rate under 10%' тЖТ two failures relabelled 'planned hotfix' тЖТ CFR 5.6% ┬╖ availability still 99.52%
тФАтФА target 'deploy more' тЖТ 18 config-only no-op deploys added тЖТ frequency 9.0/week ┬╖ median lead time 1.8 h ┬╖ users see nothing new
   Goodhart's law, in Marilyn Strathern's words: when a measure becomes a target, it ceases to be a good measure

рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

relabel 0 of 3 failures тЖТ CFR 16.7% ┬╖ availability 99.52%
relabel 1 of 3 failures тЖТ CFR 11.1% ┬╖ availability 99.52%
relabel 2 of 3 failures тЖТ CFR  5.6% ┬╖ availability 99.52%
relabel 3 of 3 failures тЖТ CFR  0.0% ┬╖ availability 99.52%
board A: cycle [5, 8, 2, 12, 3, 10] days ┬╖ flow efficiency 40%
board B: cycle [3, 4, 2, 5, 2, 4] days ┬╖ flow efficiency 80%

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

Failures рдЪреЗ рд▓реЗрдмрд▓ рдмрджрд▓рд▓реНрдпрд╛рдиреЗ change failure rate 16.7% рд╡рд░реВрди 0.0% рдЭрд╛рд▓рд╛, рдкрдг availability 99.52% рд╡рд░рдЪ рд░рд╛рд╣рд┐рд▓реА тАФ users рдирд╛ рдкреНрд░рддреНрдпреЗрдХ рдорд┐рдирд┐рдЯ рдЬрд╛рдгрд╡рд▓реЗ. Log рдордзреНрдпреЗ no-op deploys рднрд░рд▓реНрдпрд╛рдиреЗ deployment frequency рджреБрдкреНрдкрдЯ рдЭрд╛рд▓реА (рдЖрдард╡рдбреНрдпрд╛рд▓рд╛ 4.5 тЖТ 9.0) рдЖрдгрд┐ median lead time 1.8 hours рд╡рд░ рдЖрд▓рд╛, рдкрдг users рд╕рд╛рдареА рдХрд╛рд╣реАрдЪ рдирд╡реАрди рдирд╡реНрд╣рддреЗ. рдореНрд╣рдгреВрдирдЪ рдПрдХрдореЗрдХрд╛рдВрд╡рд┐рд░реБрджреНрдз рдУрдврдгрд╛рд▒реНрдпрд╛ рдорд╛рдкрд╛рдВрдЪреА рдЬреЛрдбреА (рд╡реЗрдЧ рдЖрдгрд┐ рд╕реНрдерд┐рд░рддрд╛), рдЖрдгрд┐ users рдирд╛ рдЬрд╛рдгрд╡рдгрд╛рд░рд╛ рдПрдХ рдкрд░рд┐рдгрд╛рдо, рдпрд╛рдВрдирд╛ рдлрд╕рд╡рдгреЗ рдПрдХрд╛ рдЖрдХрдбреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдХрдареАрдг рдЕрд╕рддреЗ. Flow boards рдЖрдгрдЦреА рдПрдХ рдмрд╛рдЬреВ рджрд╛рдЦрд╡рддрд╛рдд: board A рд╡рд░ рдХрд╛рдорд╛рдВрдиреА рддреНрдпрд╛рдВрдЪрд╛ 60% рд╡реЗрд│ рд╡рд╛рдЯ рдкрд╛рд╣рдгреНрдпрд╛рдд рдШрд╛рд▓рд╡рд▓рд╛.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

Four keys рдкреИрдХреА рдмрд╣реБрддреЗрдХ рддреБрдордЪреНрдпрд╛рдХрдбреЗ рдЖрдзреАрдЪ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ data рдордзреВрди рдХрд╛рдврддрд╛ рдпреЗрддрд╛рдд: pipeline рдордзреВрди deploy events, git рдордзреВрди commit times, incident tracker рдордзреВрди incidents. рдЦрд▒реНрдпрд╛ repository рд╡рд░, PR рдЙрдШрдбрд▓реНрдпрд╛рдкрд╛рд╕реВрди merge рдкрд░реНрдпрдВрддрдЪрд╛ lead time рд╣рд╛ рдкрд╣рд┐рд▓рд╛ рдвреЛрдмрд│ рддреБрдХрдбрд╛ рдЖрд╣реЗ (рдкреВрд░реНрдг lead time production рдкрд░реНрдпрдВрдд рдЪрд╛рд▓рддреЛ):

gh pr list --state merged --limit 100 --json number,createdAt,mergedAt \
  --jq '.[] | "\(.number) \(.createdAt) \(.mergedAt)"'

Deploys рдЖрдгрд┐ failures рдирд╛ рдореВрд│ рдард┐рдХрд╛рдгреАрдЪ tag рдХрд░рд╛, рдореНрд╣рдгрдЬреЗ рдЖрдХрдбреЗ рдХреЛрдгрд╛рдЪреНрдпрд╛ рд▓реЗрдмрд▓рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рд░рд╛рд╣рдгрд╛рд░ рдирд╛рд╣реАрдд:

# a deploy event your pipeline writes on every production release
deploy:
  service: gradebook
  sha: 3f9c2e1
  commit_time: 2026-09-14T09:12:00Z
  deployed_at: 2026-09-14T15:40:00Z
  caused_incident: INC-231        # linked by the incident process, not self-reported

Four keys рдЪрд╛ рдЖрдврд╛рд╡рд╛ рдЯреАрдо рдореНрд╣рдгреВрди, рджрд░ рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛, рдПрдХрд╛рдЪ рдкреНрд░рд╢реНрдирд╛рдиреЗ рдШреНрдпрд╛: "рдЖрдкрд▓реНрдпрд╛ system рдордзрд▓реА рдХреЛрдгрддреА рдЧреЛрд╖реНрдЯ рд╣рд╛ рдЖрдХрдбрд╛ рдЕрд╕рд╛ рдмрдирд╡рддреЗ рдЖрд╣реЗ?" рд▓рд╣рд╛рди, рд╡рд╛рд░рдВрд╡рд╛рд░ deploys рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░рдгрд╛рд▒реНрдпрд╛ pipelines рд╕рд╛рдареА CI/CD school рдкрд╛рд╣рд╛, рдЖрдгрд┐ users рдирд╛ рдХрд╛рдп рдЬрд╛рдгрд╡рддреЗ рд╣реЗ рдореЛрдЬрдгреНрдпрд╛рд╕рд╛рдареА Observability school рдкрд╛рд╣рд╛.

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: delivery system рдореЛрдЬрд╛, рдПрдХрдореЗрдХрд╛рдВрдирд╛ рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдареЗрд╡рдгрд╛рд▒реНрдпрд╛ рдЬреЛрдбреНрдпрд╛рдВрдордзреНрдпреЗ, рдЖрдгрд┐ рдЖрдХрдбреНрдпрд╛рдВрд╡рд░ рдЯреАрдорд╕реЛрдмрдд рдЪрд░реНрдЪрд╛ рдХрд░рд╛. рдЬреНрдпрд╛ рдХреНрд╖рдгреА рдПрдЦрд╛рджрд╛ metric рдХреЛрдгрд╛рдЪреНрдпрд╛ performance review рдордзреНрдпреЗ рдпреЗрддреЛ, рддреНрдпрд╛ рдХреНрд╖рдгреА рддреНрдпрд╛рд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреЗ рдерд╛рдВрдмрд╡рд╛.

тПня╕П рдкреБрдвреЗ

рднрд╛рдЧ 2 рдкреВрд░реНрдг рдЭрд╛рд▓рд╛: forecasting, prioritisation, debt рдЖрдгрд┐ metrics. рднрд╛рдЧ 3 рдЯреАрдореНрд╕рдЪреНрдпрд╛ рд░рдЪрдиреЗрдмрджреНрджрд▓ рдЖрд╣реЗ тАФ рдЖрдгрд┐ рддреБрдордЪреНрдпрд╛ рд╕рдВрд╕реНрдереЗрдЪрд╛ рдЖрдХрд╛рд░ рд╢реЗрд╡рдЯреА рддреБрдордЪреНрдпрд╛ software рдЪреНрдпрд╛ рдЖрдХрд╛рд░рд╛рдд рдХрд╛ рдЙрддрд░рддреЛ.

git checkout lesson-09-team-topologies

ЁЯУИ Lesson 08 тАФ Delivery metrics: the DORA four keys, flow, and Goodhart's law

ЁЯУН You are here: Lesson 08 of 12 ┬╖ Previous: lesson-07-technical-debt ┬╖ Next: lesson-09-team-topologies


ЁЯУж What's in this branch

Lesson 07, plus measuring the delivery system. The DORA four keys тАФ deployment frequency, lead time for changes, change failure rate, and failed-deployment recovery time тАФ plus reliability; flow metrics such as cycle time and flow efficiency; and Goodhart's law, which is what happens to any of them when it becomes a target. metrics() in lead/demo.py; dora() and flow() in lead/models.py.

ЁЯзТ Explain like I'm 5

The head teacher wants to know if the maths department is doing well. So she counts things: how often new lessons are ready, how long they take, and how often a lesson goes wrong. ЁЯУК

Useful! Until she says: "From now on, fewer than 1 in 10 lessons may go wrong."

Something strange happens. The department does not get better. But the number does. When a lesson goes wrong, people start calling it a "planned change" instead. ЁЯЩИ The number drops from 17% to 6%. The pupils had exactly as many bad lessons as before.

Then she says: "More lessons, please!" And the department starts counting every small worksheet as a "lesson". The number doubles. The pupils learn nothing new. ЁЯУДЁЯУДЁЯУД

Katrina explains: "When a number becomes a target, people start working on the number instead of the thing it measured." So she uses the numbers to ask questions about how the department works тАФ never to rank the teachers.

ЁЯЧ║я╕П Diagram

flowchart LR
    l["ЁЯУж 18 deploys in 4 weeks"] --> k["four keys<br/>4.5/week ┬╖ lead 18 h<br/>CFR 16.7% ┬╖ recovery 45 min"]
    l --> a["reliability<br/>availability 99.52%"]
    k -->|"target: CFR under 10%"| g1["2 failures relabelled<br/>CFR 5.6% ┬╖ availability still 99.52%"]
    k -->|"target: deploy more"| g2["18 no-op deploys<br/>9.0/week ┬╖ users see nothing new"]
    f["ЁЯМК flow: cycle times 5тАУ12 days<br/>flow efficiency 40%"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/engineering-leadership/lesson-diagrams.html#l08

тЭУ What

ЁЯдФ Why

Because a lead needs to know whether changes to the way the team works are helping, and feelings are unreliable. The four keys describe the delivery system тАФ how fast and how safely changes reach users тАФ rather than individuals. And because the fastest way to break a useful metric is to set it as a target and tie it to people: the team will improve the number, one way or another.

ЁЯФз How (in this repo)

dora(log, weeks) in lead/models.py takes deploys as (lead time hours, failed?, minutes of user impact) and returns frequency per week, median lead time, change failure rate, median recovery time of failed deploys, and availability (1 тИТ impact minutes ├╖ minutes in 28 days). The impact minutes count however the deploy was labelled тАФ which is how the demo exposes relabelling. flow(items) takes (start day, end day, active days) and returns cycle times and flow efficiency. metrics() in lead/demo.py runs an honest log and two gamed ones. The numbers describe a system: a thinking tool, not a formula for people.

ЁЯзк Try it

python3 lead/demo.py metrics
python3 - <<'EOF'
import sys; sys.path.insert(0, "lead"); from models import dora, flow
leads = [20, 6, 30, 52, 8, 4, 26, 72, 10, 14, 5, 28, 48, 9, 22, 3, 16, 40]
fails = {3: 45, 7: 120, 12: 30}
for hidden in (0, 1, 2, 3):
    relabel = list(fails)[:hidden]
    log = [(l, i in fails and i not in relabel, fails.get(i, 0)) for i, l in enumerate(leads)]
    d = dora(log, 4)
    print(f"relabel {hidden} of 3 failures тЖТ CFR {d['cfr']:>5.1%} ┬╖ availability {d['availability']:.2%}")
cyc, eff = flow([(0, 5, 2), (1, 9, 3), (2, 4, 2), (3, 15, 4), (5, 8, 2), (6, 16, 3)])
cyc2, eff2 = flow([(0, 3, 2), (1, 5, 3), (2, 4, 2), (3, 8, 4), (5, 7, 2), (6, 10, 3)])
print(f"board A: cycle {cyc} days ┬╖ flow efficiency {eff:.0%}")
print(f"board B: cycle {cyc2} days ┬╖ flow efficiency {eff2:.0%}")
EOF

тЬЕ Verify тАФ what you should see

metrics prints:

   deployment frequency 4.5/week ┬╖ lead time for changes (median) 18 h ┬╖ change failure rate 16.7% ┬╖ failed-deploy recovery (median) 45 min ┬╖ availability 99.52%
тФАтФА target 'change failure rate under 10%' тЖТ two failures relabelled 'planned hotfix' тЖТ CFR 5.6% ┬╖ availability still 99.52%
тФАтФА target 'deploy more' тЖТ 18 config-only no-op deploys added тЖТ frequency 9.0/week ┬╖ median lead time 1.8 h ┬╖ users see nothing new
   Goodhart's law, in Marilyn Strathern's words: when a measure becomes a target, it ceases to be a good measure

Your snippet prints:

relabel 0 of 3 failures тЖТ CFR 16.7% ┬╖ availability 99.52%
relabel 1 of 3 failures тЖТ CFR 11.1% ┬╖ availability 99.52%
relabel 2 of 3 failures тЖТ CFR  5.6% ┬╖ availability 99.52%
relabel 3 of 3 failures тЖТ CFR  0.0% ┬╖ availability 99.52%
board A: cycle [5, 8, 2, 12, 3, 10] days ┬╖ flow efficiency 40%
board B: cycle [3, 4, 2, 5, 2, 4] days ┬╖ flow efficiency 80%

ЁЯПБ What you just proved

Relabelling failures took the change failure rate from 16.7% to 0.0% while availability stayed at 99.52% тАФ users felt every minute. Padding the log with no-op deploys doubled deployment frequency (4.5 тЖТ 9.0 a week) and cut the median lead time to 1.8 hours, with nothing new for users. That is why a pair of measures that pull against each other (speed and stability), plus an outcome users feel, is harder to game than one number. The flow boards show another view: on board A, items spent 60% of their time waiting.

тЪая╕П Common mistakes

ЁЯПн In production

Most of the four keys can be computed from data you already have: deploy events from the pipeline, commit times from git, incidents from the incident tracker. On a real repository, lead time from a PR opening to merge is a first rough slice (the full lead time runs to production):

gh pr list --state merged --limit 100 --json number,createdAt,mergedAt \
  --jq '.[] | "\(.number) \(.createdAt) \(.mergedAt)"'

Tag deploys and failures at the source, so the numbers do not depend on anyone's label:

# a deploy event your pipeline writes on every production release
deploy:
  service: gradebook
  sha: 3f9c2e1
  commit_time: 2026-09-14T09:12:00Z
  deployed_at: 2026-09-14T15:40:00Z
  caused_incident: INC-231        # linked by the incident process, not self-reported

Review the four keys as a team, monthly, with one question: "what in our system is making this number what it is?" See the CI/CD school for pipelines that make small, frequent deploys safe, and the Observability school for measuring what users feel.

ЁЯПн Why this matters in production: measure the delivery system, in pairs that keep each other honest, and discuss the numbers with the team. The moment a metric appears in someone's performance review, stop trusting it.

тПня╕П Next

Part 2 is done: forecasting, prioritisation, debt and metrics. Part 3 is about the shape of teams тАФ and why the shape of your organisation ends up in the shape of your software.

git checkout lesson-09-team-topologies
тЖР Previoustechnical debtNext тЖТteam topologies

This page is the lesson's README from the lesson-08-delivery-metrics branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.