496303471d
---ci--- project: atelier phase: 7 milestone: v0.1 status: complete phase_role: final milestone_complete: true requirements: covered: [ATELIER-01, ATELIER-02, ATELIER-03, ATELIER-04, ATELIER-05, ATELIER-06, ATELIER-07, ATELIER-08, ATELIER-09, ATELIER-10, ATELIER-11, ATELIER-12, ATELIER-13, ATELIER-14, ATELIER-15, ATELIER-16, ATELIER-17, ATELIER-18, ATELIER-19, ATELIER-20, ATELIER-21, ATELIER-22, ATELIER-23, ATELIER-24, ATELIER-25, ATELIER-26, ATELIER-27, ATELIER-28, ATELIER-29, ATELIER-30, ATELIER-31, ATELIER-32, ATELIER-33, ATELIER-34, ATELIER-35] partial: [] ship: milestone: v0.1 type: NFR tag: v0.0.7 merge: milestone/v0.1-atelier -> main release: https://git.cloudinit.dev/cloudinit-bot/atelier/releases/tag/v0.0.7 ---/ci--- Milestone v0.1 — Initial Framework (NFR, complete). 8 core principles (C1-C8), 11 domains, 110 domain principles, 27 derived docs, 4 good + 3 bad examples, 4 language docs, full matrix, 3 review docs. All 35 requirements covered. 7 patches (v0.0.0 pre-execution through v0.0.7 final). v0.0.7 IS the v0.1.0 milestone release.
2.2 KiB
2.2 KiB
Backend Performance — Derived Rules
Derives from
domains/performance/first-principles.mdP1 (Measure First), P3 (Complexity Awareness), P4 (Resource Bounds).
Measure First (P1)
- p50, p95, p99 latencies. The average hides the long tail.
- Throughput (req/s) under load. Saturation point (where latency rises).
- Resource utilization: CPU, memory, I/O, network. Each is a budget.
N+1 Queries (P3 Complexity Awareness)
- A query in a loop is an N+1. It is O(N) queries instead of O(1).
- Detect with a query counter in tests. A test that issues 100 queries is failing.
- Fix with a JOIN, a batch load, or a dataloader. Never "we'll fix it later."
Caching (P5 Caching with Intent)
- Cache what is: expensive to compute, stable, read often.
- Invalidation is designed: TTL, event-based, or version-based. Never "we'll just clear it."
- A cache without an invalidation strategy is a cache that serves stale data forever.
- Multi-level: HTTP cache → CDN → app cache → DB. Each layer has its own rules.
Async and Concurrency (P7 Async When Independent, see domains/concurrency/)
- I/O-bound work is async. Don't block a thread on a network call.
- CPU-bound work is in a worker, not the request path.
- Bounded queues everywhere (P9 Bounded Queues). Unbounded = OOM.
Database (P4 Resource Bounds, see domains/data/indexing.md)
- Connection pool: bounded. The DB has a connection limit; the pool respects it.
- Slow queries: logged, explained, fixed. A 10-second query is a bug.
- Pagination on large tables: cursor, not offset. Offset scans rows.
Resource Bounds (P4)
- Memory: bounded. A request that allocates unbounded memory is a DoS vector.
- Timeouts: every external call has one. A call without a timeout is a call that can hang forever (P8 Timeout Discipline).
- File handles, DB connections, HTTP connections: all bounded, all pooled.
What Violates Backend Performance
| Violation | Principle |
|---|---|
| N+1 query in a loop | P3 |
| No timeout on an HTTP call | P4, P8 (concurrency) |
| Unbounded in-memory sort | P4 |
| Cache with no invalidation | P5 |
SELECT * |
P4 (data P10) |
| Connection pool size = 1000 | P4 (DB limit) |