Last hour, version 2 — read this, then stop
On this page12
- The three rules
- One line per new answer
- Typing
- Async
- Git
- Brokers
- Infrastructure as code
- PostgreSQL vs MySQL
- Kinds of test
- Regulated vocabulary this ad adds
- Facts with dates
- Your numbers
Last hour, version 2 — read this, then stop
One page for the hour before the second call: this ad’s new ground,
compressed. The shared tables — status codes, Postgres isolation, migration
locks, index rules, retry rules, healthcare vocabulary — are in
version 1’s last-hour sheet and apply
unchanged.
The three rules
- Precise about practice. Name the tool, the setting and the reason.
- Honest about gaps. “Not in production” — then the mechanism, then the
closest thing you did.
- 60 to 90 seconds, reasoned aloud. Slow down; close every answer.
One line per new answer
The sentence each answer in Answers, version 2 — say these out loud is built around.
The carried-over answers have theirs in
version 1.
- Type hints — annotate every boundary;
Protocol for seams; Pydantic at the edge, dataclasses inside; strict mypy in CI, package by package; nothing enforced at runtime.
- Async patterns — TaskGroup when tasks can fail; a semaphore acquired inside the coroutine;
asyncio.timeout() on every wait; re-raise CancelledError; keep task references.
- Project layout — one
pyproject.toml; uv with a committed lockfile; src/ layout; packages by feature; typed settings from the environment; gates in CI.
- FastAPI, Django or Flask — FastAPI for typed async APIs, Django for batteries, Flask for small sync services; the framework stays at the edge.
- Evolving an API — additive by default; breaking means a new version plus
Deprecation and Sunset; the committed spec is diffed in CI.
- Postgres vs MySQL — InnoDB’s clustered index, transactional DDL only in Postgres, Read Committed vs Repeatable Read,
utf8mb4.
- Contract testing — the consumer records what it needs, the provider’s CI verifies it; it catches what a schema check can’t; for third parties, recordings plus a sandbox canary.
- Git workflow — trunk-based; branches of a day or two; flags for unfinished work; protected
main; squash merges; --force-with-lease.
- Brokers — queue (RabbitMQ, SQS) or log (Kafka); Pub/Sub is managed fan-out; at-least-once everywhere, so idempotent consumers and an outbox.
- Containers — multi-stage, slim, non-root, lockfile layer first; liveness touches nothing, readiness checks dependencies; graceful SIGTERM.
- Branch to production — a gate at every step; one image promoted through environments; expand/contract migrations; rollback is the previous image; flags separate deploy from release.
- IaC — declare, preview, apply; Terraform’s state is the risk; Pulumi is the same model in Python; CloudFormation manages state for you, and SAM is CloudFormation.
- Instrumentation — OpenTelemetry auto-instrumentation; RED metrics with bounded labels; the trace id in every log; tail sampling in the collector; no PHI anywhere.
- Performance — measure p99 first; find where the time goes; N+1, blocking calls, sequential I/O, pool size; prove it with a load test.
- Regulated environments — controls that emit their own evidence; audit logging no code path can skip; IEC 62304 adds safety classes, traceability and SOUP.
- AI tools — mechanical work yes, judgement no; tests first, small diffs, CI as the gate; no patient data in tools outside the boundary.
Typing
| Need |
Use |
| an interface for a seam — a repository, a client |
Protocol; an ABC only when you want shared implementation |
| a generic function or class |
def first[T](xs: list[T]) -> T — PEP 695, Python 3.12+ |
| untrusted input at the edge |
a Pydantic model, validated at runtime |
| a plain internal record |
@dataclass(frozen=True, slots=True) |
| the shape of JSON you don’t own |
TypedDict |
| a closed set of values |
Literal[...] or an Enum |
an exhaustive match |
assert_never() in the fallthrough |
| typing a decorator |
ParamSpec |
| “anything” |
object if you only pass it along; Any switches checking off |
Async
| Situation |
Pattern |
| several tasks, any of which may fail |
async with asyncio.TaskGroup() — siblings cancelled, ExceptionGroup raised, caught with except* |
| a few independent reads, all-or-nothing |
asyncio.gather |
| at most N at once |
Semaphore(N), acquired inside the coroutine |
| a deadline around a block |
async with asyncio.timeout(5): |
| a sync library |
await asyncio.to_thread(fn) |
| CPU-bound work |
a process pool or a worker — never the loop |
| fire-and-forget |
keep a reference in a set; discard it when done |
| cleanup on cancel |
catch CancelledError, clean up, re-raise |
Git
| Merge button |
Result |
Use it when |
| merge commit |
keeps the branch, adds a merge commit |
long-lived or shared branches, libraries |
| squash and merge |
one commit per pull request on main |
trunk-based services — one-command revert |
| rebase and merge |
linear history, every commit kept |
small PRs whose commits each mean something |
--force-with-lease, never --force. Never rebase a branch someone else is
building on. GitFlow is for versioned software; services go trunk-based.
Brokers
|
Kafka |
RabbitMQ |
SQS |
Pub/Sub |
| model |
a retained log |
a queue with routing |
a managed queue |
a managed topic with subscriptions |
| after consumption |
stays; each consumer group has an offset |
deleted on ack |
deleted by the consumer |
acked per subscription |
| ordering |
per partition, by key |
per queue, with one consumer |
FIFO queues, per message group |
per ordering key |
| replay |
yes, within retention |
no |
no |
seek to a snapshot or a timestamp |
| fits |
events with many readers, streams |
commands, jobs, routing |
AWS jobs with no ops |
GCP fan-out |
Infrastructure as code
|
Terraform |
Pulumi |
CloudFormation / SAM |
| language |
HCL |
Python, TypeScript, Go and others |
YAML or JSON |
| state |
a file you host and lock |
Pulumi Cloud or your own backend |
managed by AWS |
| clouds |
any |
any |
AWS only |
| preview / apply |
plan / apply |
preview / up |
change set / deploy |
| a failed apply |
partial; fix forward |
partial; fix forward |
automatic rollback |
PostgreSQL vs MySQL
|
PostgreSQL |
MySQL (InnoDB) |
| table storage |
a heap; every index points into it |
clustered on the primary key |
| default isolation |
Read Committed |
Repeatable Read |
| DDL inside a transaction |
yes — a failed migration rolls back |
no — implicit commit |
| online schema change |
CONCURRENTLY, NOT VALID |
online DDL, else gh-ost or pt-online-schema-change |
| encoding trap |
— |
utf8 is three bytes; use utf8mb4 |
Kinds of test
| Kind |
Proves |
Cost |
| unit |
the logic is right, in isolation |
milliseconds |
| integration |
your code works against the real database, broker, cache |
seconds; needs Docker |
| contract, consumer-driven |
the provider still gives each consumer what it needs |
fast; needs shared contract files |
| schema (OpenAPI) |
responses match the declared spec |
fast; only as good as the spec |
| end-to-end |
the whole path works |
slow and flaky — keep a handful |
Regulated vocabulary this ad adds
| Term |
One line |
| ISO 27001 |
certifies an information security management system |
| SOC 2 Type I / II |
an auditor’s report on controls — designed, on one date (I) / operating, over months (II) |
| IEC 62304 |
the lifecycle standard for medical-device software |
| Safety class |
A, B or C by the worst harm a failure could cause; it sets how much rigour applies |
| SOUP |
software of unknown provenance — every third-party library, listed with its version and assessed |
| Traceability |
requirement → design → test, in both directions |
Facts with dates
| Fact |
As of 2026-10 |
| Kafka |
4.x; ZooKeeper was removed in 4.0, so KRaft is the only mode |
| Terraform |
BSL licence since 2023; OpenTofu is the open-source fork |
| Kubernetes |
Gateway API is GA and the recommended path for HTTP routing; Ingress is feature-frozen |
| OpenTelemetry |
traces, metrics and logs are all GA |
| Python tooling |
uv for environments and locks; Ruff for lint and format; mypy the safe answer, pyright stricter, ty the newcomer |
| Python |
3.14 is current; 3.15.0 final is due 9 October 2026 |
Your numbers
Version 1’s list holds — see it there. Add three for this ad:
- A performance fix: [before] → [after], and the cause: [ ]
- How long your CI pipeline took, and what you did to speed it up: [ ]
- The size of a typical pull request on your last team: [ ]