#backend
15 posts
Atomic file writes: write a temp file, then rename
Overwriting in place leaves half a file behind on power loss, a crash, or a concurrent read. A temp file plus rename uses filesystem atomicity to make half a file impossible.
Estimating work: why "about three days" becomes three weeks
You estimated writing code; what you owe is writing plus integration, review, rework, and waiting on others. Listing the unknowns beats multiplying every day count by two.
Feature flags are debt, not configuration
Every flag doubles the reachable code paths and no flag ever gets deleted by itself. Giving each one a removal date matters far more than building a clever flag system.
Graceful shutdown: the exit sequence decides between 502s and clean responses
Exiting immediately on a termination signal cuts in-flight requests. The order is stop accepting, drain what is running, release resources, then exit.
Idempotency keys: the one write that makes retries safe
A network timeout does not mean the server did nothing. An idempotency key identifies the same request so the server replays the first result instead of executing again.
JSON canonicalization: why the same object hashes two ways
Key order, number formatting and escape style all change the bytes. A stable hash has to pin those rules at serialization, not hope JSON.stringify is deterministic.
Deadlock: break any one of four conditions
Mutual exclusion, hold and wait, no preemption, circular wait. All four must hold at once. The practical one to break is circular wait: give every lock a global order.
The N+1 query: the most typical ORM performance trap
Fetch 100 rows and query the relation for each one and you have made 101 queries. There are only three fixes: eager load, batch fetch, or use a single join.
Rate limiting: what token bucket and leaky bucket really differ on
A token bucket permits bursts; a leaky bucket flattens traffic to a constant rate. Picking wrong shows up as throttled normal users, or a limit that does nothing.
SQLite indexes: the leftmost prefix is a consequence of sorting
A composite index (a, b) can only order by b within equal a, so skipping a and filtering on b has nothing to use. See it as sorting and the mnemonic stops being a rule to memorize.
Time zones and DST: store UTC, or daylight saving will bite
A DST day has 23 or 25 hours, and local times near the switch may not exist or may happen twice. Storing UTC timestamps and converting at display is the only model that holds.
Unicode normalization: why two identical-looking strings differ
An e-acute can be one code point or a base letter plus a combining mark. Normalize to NFC before comparing, storing or indexing, or duplicates quietly slip through.
In Rust, context belongs on the line that actually fails
The question mark operator rethrows an error without saying which step failed. Structured errors in the core, Context in the application layer, with the input attached, is what makes a log line locatable.
When a crate should become a workspace
The trigger for splitting a workspace is build time and dependency boundaries, not tidy directories. Split when three signals hold, or you trade one compile for managing several packages.
Structured logging is not println replaced by tracing::info
Log lines built by concatenation can only be read by humans. Fields make them queryable. Fields, spans, levels and knowing when not to format are the four real decisions.
