Part II β The Shield Β· Lesson 4.5
Performance Testing
In one lineTurn performance into a build gate with numbers, so regressions fail CI instead of shipping.
Where you've seen itA pull request that imports one convenience library, adds 180KB to the main bundle, and gets blocked before a human reads it.
Diagram
BUDGETS AS A GATE β the check runs on every PR
metric budget this PR result
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
LCP (p75, mobile) β€ 2.5s 2.4s β pass
INP (p75) β€ 200ms 180ms β pass
CLS β€ 0.1 0.02 β pass
main bundle (gzip) β€ 170KB 214KB β FAIL β blocks merge
requests, 1st load β€ 30 27 β pass
Fail the build, don't file a ticket. Tickets lose to features.LAB vs FIELD β you need both, they answer different questions
LAB (synthetic) FIELD (RUM)
ββββββββββββββββββ ββββββββββββββββββ
Lighthouse CI, WebPageTest real users, real devices
same device + network each run every device + network
β comparable between commits β tells you the truth
β one machine, one profile β can't run before merge
Gate on LAB. Alert on FIELD. Never confuse the two.WHY p75 AND NOT AVERAGE
users sorted by load time
ββββββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββ€
fast median p75 p95 slowest
1.9s 3.4s 7.1s
average 2.4s "looks fine" while 25% of users wait 3.4s+
and they are the ones who leave.How it works
- Set budgets from current p75, slightly tighter β a budget nobody can pass gets disabled within a week.
- Run Lighthouse CI on a fixed device profile and throttled network so numbers are comparable commit to commit.
- Add a bundle-size check (
size-limit,bundlesize) β it's faster, deterministic, and catches most regressions. - Run three passes and take the median; single Lighthouse runs vary by 10β20%.
- Load-test the API separately (k6, Artillery) β a frontend that's fast at 10 users and dead at 10,000 is still broken.
Trade-offs
| Check | Speed | Catches |
|---|---|---|
| Bundle size limit | seconds | dependency bloat, bad imports |
| Lighthouse CI | ~1 min | render-blocking, unused JS, CLS |
| WebPageTest | minutes | real device, filmstrip, waterfall |
| RUM (field) | continuous | what users actually experience |
Interview angle
"How do you stop performance regressing over time?"
- Make it a gate, not a goal: budgets fail CI so no regression merges silently.
- Cheap deterministic checks (bundle size) on every PR, full Lighthouse on main, RUM alerting in production.
- Track p75 on real devices β averages hide exactly the users who churn.
Recap
- Budgets in CI beat performance sprints, because they prevent instead of repair.
- Lab numbers gate merges; field numbers tell you the truth.
- Median of three runs, p75 of real users.