#backend
24 posts
HTTP finally has a safe method with a body: QUERY
GET cannot carry a body and POST cannot be retried safely, so query endpoints have been stuck between two wrong options for twenty years. The IETF QUERY draft adds a third: safe, idempotent, and able to carry content.
Post-quantum TLS is already in your handshake, but it only solves half the problem
Browsers and CDNs now negotiate hybrid key exchange like X25519MLKEM768 by default, which closes the harvest-now-decrypt-later gap. The signature half is still open.
MCP 2026-07-28: delete the session, make the protocol stateless again
The new MCP revision removes the initialize handshake and the Mcp-Session-Id header, and turns cross-call state into explicit server-minted handles. What changed, why, and what it means for an existing server implementation.
Node.js 26 is LTS: do not let a platform schedule your upgrade
Node.js 26 was confirmed as LTS on 6 October, with 26.11.0 and 26.11.1 following on 7 October — while Node.js 20 keeps disappearing from hosting platforms.
Harness buys Augment Code: AI coding tools start to consolidate
Harness acquired Augment Code assets including Cosmos, a platform that coordinates multiple agents, plus the Auggie CLI and the Code Context Engine, folding AI coding into the delivery pipeline.
PostgreSQL 19: REPACK, WAIT, and a planner you can finally argue with
PostgreSQL 19 merges VACUUM FULL and CLUSTER into REPACK, adds a WAIT command for catching a standby up, and ships two extensions that pin planner decisions. The features I actually care about, plus three incompatibilities that bite.
SQLite 3.53: a WAL corruption fix, and a proper table for the CLI
SQLite 3.53 fixes a WAL-reset corruption bug, adds the Query Result Formatter library, lets ALTER TABLE add and drop constraints, and introduces REINDEX EXPRESSIONS. That last one is the tool for repairing stale expression indexes.
Wikipedia names rogue agents: after millions of requests
The Wikimedia Foundation publicly accused unauthorised OpenAI agents of millions of requests, questionable edits and tool tampering, possibly worsening a rare service disruption.
Compressed and still mutable: a dynamic compressed self-index
Highly repetitive string data (genomes, web archives, versioned documents) compresses beautifully, but any edit forces a full rebuild. A RIKEN AIP paper at ESA 2026 proposes dynamic RR-index, the first to combine compression, search, and updates in delta-optimal space.
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.
