Skip to content

Topic archive

Software Engineering

Software Engineering covers developer tooling, architecture, maintainability, engineering workflows, protocols, and practices that improve how software is designed and built.

460 articles
Software Engineering 16 Sep 2026 8 min read

HTTP 425 Keeps Replay-Sensitive Requests Out of TLS Early Data

TLS 1.3 can carry application data before a resumed handshake completes, which means an HTTP request can reach server processing earlier than the connection has its final handshake state. That latency optimization changes a security property: early data can be replayed, so a request that is safe to execute once can become unsafe when the same bytes are accepted more than once. HTTP status 425 Too Early marks the boundary between transport acceptance and application acceptance. A server can accept TLS early data at the connection layer yet decline to process a particular HTTP request from that data. The client can then retry after the handshake completes, where the early-data replay condition no longer applies.

Software Engineering 16 Sep 2026 7 min read

HTTP 421 Misdirected Request Marks a Connection Authority Boundary

An HTTP/2 client can reuse one secured connection for requests to more than one origin when the server is authoritative for those origins. A request can still reach a server instance whose connection context does not fit the target URI. 421 Misdirected Request exists for that boundary: the server rejects the routing context rather than treating the target resource itself as missing. This distinction separates resource semantics from connection authority. A 421 response says that this server, on this path or connection context, is unable or unwilling to produce an authoritative response for the target URI. It does not say that the resource has been deleted, that its method is forbidden, or that the request representation is invalid.

Software Engineering 16 Sep 2026 6 min read

HTTP 103 Early Hints Separate Speculation From Final Response Semantics

An HTTP server can emit a 103 Early Hints informational response before it has produced the final response. A client may act on suitable fields in that interim message, such as starting a preload named by Link, even though the eventual status code, header fields, and representation are still pending. This creates a deliberate split between speculative work and authoritative response semantics. The interim response can move selected preparation earlier in time, but it cannot stand in for the final response or determine its meaning.

Software Engineering 16 Sep 2026 6 min read

ETag Revalidation Separates Cache Freshness From Representation Transfer

An HTTP cache can hold a response that is no longer fresh yet still avoid downloading the representation again. When the stored response carries a usable validator, the cache can send a conditional request and let the origin confirm whether the selected representation has changed. This separates two operations that are often treated as one: checking whether cached state remains valid and transferring a new representation. A successful revalidation can perform the first without performing the second.

Software Engineering 16 Sep 2026 7 min read

Duplicate File Descriptors Share Offsets but Not Descriptor Flags

Calling dup() does not create an independent stream position. The returned descriptor refers to the same open file description as the source descriptor, so a seek through either descriptor changes the offset observed through both. At the same time, descriptor-local state such as the close-on-exec flag remains attached to each descriptor separately. That split is easy to miss because both kinds of state are manipulated through integer file descriptors. The integer is only a process-local reference. Several descriptors can point at one open file description, and that shared object carries state with consequences for reads, writes, seeks, and status-flag changes.

Software Engineering 16 Sep 2026 6 min read

DNS Negative Caching Can Outlive Record Creation

A recursive DNS resolver can continue returning an earlier absence result after the authoritative zone has gained the requested name. The new record and the cached negative answer are not contradictory: they exist at different points in the resolution path, and the cache remains valid until its negative TTL expires or local policy removes it sooner. This behavior gives DNS absence its own cache lifetime. Publishing a record changes authoritative state, but it does not synchronously invalidate negative entries already stored by recursive resolvers.

Software Engineering 15 Sep 2026 7 min read

Write Skew Escapes Row-Level Conflict Detection

Two concurrent transactions can each read a valid database state, update different rows, and both commit without colliding on a written row. The final state can still violate a constraint that spans those rows. No lost update is required; each transaction can preserve every value written by the other and still produce an invalid result. This anomaly is commonly called write skew. Its defining feature is that the conflict lives in the relationship among values rather than in two writes aimed at the same row. Isolation mechanisms that detect direct write-write conflicts therefore do not automatically protect every application invariant.

Software Engineering 15 Sep 2026 7 min read

Version Columns Turn Lost Updates Into Explicit Conflicts

Two clients can read the same database row, derive different changes, and then write in sequence. If each update replaces values without checking the state that produced its decision, the later write can silently erase part or all of the earlier one. The database has serialized the statements, yet the application-level read-modify-write operation has still lost a concurrent change. A version column changes the admission rule for the write. The update is accepted only if the row still carries the version observed by the client. A competing update advances that version, so a stale writer affects zero rows instead of overwriting newer state.

Software Engineering 15 Sep 2026 6 min read

Tombstones Preserve Deletions Across Replica Gaps

A replicated store cannot always represent deletion as immediate absence. If one replica removes a record while another replica is disconnected, erasing every trace of the record also erases the evidence needed to distinguish a deliberate deletion from a replica that simply has not seen recent state. A tombstone keeps that evidence as versioned metadata. Instead of removing the key from the replication domain at once, the system records a deletion marker that participates in reconciliation. A replica carrying an older live value can then compare its state with the marker and discard the obsolete value.

Software Engineering 15 Sep 2026 7 min read

TCP Half-Close Separates the Two Stream Directions

A TCP peer can reach end-of-stream on incoming data while its outgoing stream remains usable. The event is directional: a FIN closes one side’s sending direction after previously queued bytes, but it does not require the opposite direction to close at the same instant. That property is easy to hide behind APIs that expose a connection as one object with a single close operation. At the protocol boundary, however, TCP carries two byte streams in opposite directions. A half-close makes the distinction visible and gives application protocols a useful signal: one participant can state that its request body is complete while still accepting a response.

Software Engineering 15 Sep 2026 8 min read

Task Scopes Bind Child Lifetimes to Parent Operations

An asynchronous function can return while work it started is still running. Once that happens, the caller no longer has a lexical boundary that states when the spawned work finishes, where its failure is observed, or which operation owns its cancellation. Structured concurrency changes that lifetime relation. Child tasks belong to an enclosing scope, and the scope does not complete until its children reach a terminal state according to the runtime’s task-group semantics. The central property is not parallel execution. It is that task lifetime follows program structure.

Software Engineering 15 Sep 2026 5 min read

Schema Renames Create a Compatibility Interval

Renaming a database column is a single catalog operation in many relational systems, but an application deployment can make that apparently atomic change span several software versions. If an old process still sends statements containing old_name after the database exposes only new_name, the schema is valid and the process is valid in isolation, yet their interface no longer matches. The central issue is not the rename operation itself. It is the interval in which multiple application versions can reach one database. During that interval, schema evolution behaves like an API compatibility problem.

Software Engineering 15 Sep 2026 6 min read

Savepoints Create Partial Rollback Boundaries

A database transaction does not have to choose only between keeping every statement and discarding the entire unit of work. In systems that support transaction savepoints, a transaction can mark an intermediate boundary, perform additional operations, then roll back changes made after that boundary while keeping the transaction itself active. That behavior makes a savepoint more than a convenience for error recovery. It creates a local rollback boundary inside a larger atomic unit, with semantics that remain tied to the surrounding transaction. Nothing before the final commit becomes durable merely because a partial rollback succeeded.

Software Engineering 15 Sep 2026 7 min read

Request Coalescing Turns Concurrent Cache Misses Into Shared Work

A cache entry can expire while hundreds of requests for the same key are already in flight. If every request observes the miss independently, each can start the same backend operation before any result reaches the cache. The cache still limits work across time, but it does not limit duplicate work during that miss interval. Request coalescing adds a second boundary: concurrent operations for the same logical key can share one in-flight computation. One caller becomes the active producer, while matching callers wait for that producer’s result instead of starting equivalent work. The mechanism is also called single-flight suppression in systems that expose it as a concurrency primitive.

Software Engineering 15 Sep 2026 7 min read

Idempotency Keys Bind Retries to One Logical Operation

A client can transmit a state-changing request, lose the response, and retry without knowing whether the first attempt committed. At that boundary, transport failure has created ambiguity rather than proof of application failure. Repeating the mutation blindly can create a second logical effect. An idempotency key gives the server a stable operation identity across those delivery attempts. The first accepted request associates the key with an operation record. A later request carrying the same key can then reuse the recorded outcome instead of executing the mutation again.

Software Engineering 15 Sep 2026 8 min read

HTTP Preconditions Turn Resource Versions Into Write Guards

A client reads a resource at revision 41, edits one field, and sends the whole representation back. During that interval, another client commits revision 42. If the server accepts the first client’s replacement without testing its source revision, revision 42 can disappear from the visible state even though both requests completed normally. This is the lost-update shape at an HTTP boundary. The notable detail is not simultaneous execution. The requests can arrive seconds apart. The conflict exists because a later mutation was derived from an earlier representation and the server has no condition connecting those two facts.

Software Engineering 15 Sep 2026 6 min read

Half-Open TCP Connections Hide Peer Failure Until Traffic Resumes

A TCP socket can remain in the established state on one host after the peer has become unreachable or has lost all connection state. No contradiction exists in that state: TCP endpoints maintain local protocol state, and a silent network failure does not automatically deliver evidence that the peer is gone. This creates a boundary between connection state and peer liveness. An established socket records what the local TCP implementation currently knows about a byte-stream association. It is not a continuously refreshed assertion that the remote process, host, route, and intervening network are all operational.

Software Engineering 15 Sep 2026 7 min read

Generation Counters Reject Stale Async Results

An asynchronous operation can start first and finish last. If every completion writes into the same state slot, completion order becomes state order even when the application intended request order to define authority. This race appears without shared-memory threads. Two network requests, background computations, database queries, or worker messages can overlap through an event loop and return in the opposite order from their initiation. The older result is not necessarily incorrect data. It is stale because a later request has superseded the state transition that originally authorized it.

Software Engineering 15 Sep 2026 7 min read

Fencing Tokens Reject Stale Lock Holders

A process acquires a distributed lease, pauses long enough for that lease to expire, then resumes. Another process has already acquired the same lease. At that moment both processes can execute code that was entered under an apparently valid acquisition, even though only the newer owner should retain authority. The lease itself cannot retract instructions from the paused process. Expiration changes coordination state; it does not erase local state, stop a suspended runtime, or cancel an operation already queued elsewhere. This gap is the central limitation of treating a distributed lock as a remote version of an in-process mutex.

Software Engineering 15 Sep 2026 6 min read

Fencing Tokens Reject Stale Lease Holders

A distributed lease can expire while its holder is paused. The holder may later resume with local state that still says it owns the lease, even though another client has acquired a newer lease. If the protected resource accepts commands solely because a client once acquired ownership, both clients can act during the same logical ownership interval. Fencing tokens move part of the ownership check to the resource receiving the mutation. Each successful lease acquisition receives a token greater than every token issued before it. The protected resource records the greatest token it has accepted and rejects operations carrying an older value.

Software Engineering 15 Sep 2026 8 min read

Expect 100-Continue Defers Request Body Transfer

An HTTP/1.1 client can send request headers containing Expect: 100-continue and hold back the request body while the server evaluates those headers. The server can answer with 100 Continue, allowing body transfer to proceed, or send a final response when it can reject the request without receiving the payload. This splits one request into a metadata decision boundary followed, conditionally, by body transmission. The mechanism matters most when a request body is costly to transmit and the server can make a useful decision from request metadata alone. Authentication failure, an unsupported method, or another header-visible rejection can terminate the exchange before those bytes cross the connection. The same split also creates a timing dependency: a client cannot wait forever for an interim response, and servers and intermediaries must preserve the protocol semantics closely enough for progress.

Software Engineering 15 Sep 2026 7 min read

Connection Pools Turn Session State Into Shared State

A database connection pool reuses physical sessions across many logical borrowers. That reuse changes the lifetime of session-scoped state. A setting applied by one request can outlive the request itself because returning a connection to the pool usually ends only the borrower’s access to that connection, not the database session behind it. This distinction matters whenever application code changes properties that belong to the session rather than to a single statement or transaction. Transaction isolation, read-only mode, schema selection, session variables, advisory locks, temporary objects, prepared statements, and database-specific configuration can all have lifetimes that differ from the lexical scope of application code.

Software Engineering 15 Sep 2026 6 min read

Atomic Rename Separates Visibility From Crash Durability

A successful rename() can replace an existing pathname without exposing an interval in which that destination name is absent. That visibility property makes rename a common publication boundary for configuration files, checkpoints, manifests, and other file-backed state. It does not, by itself, establish that the replacement survives an abrupt loss of power. The distinction is between namespace atomicity and persistence. Atomic replacement constrains what concurrent observers can see while the system is running. Crash durability concerns which writes and metadata changes are guaranteed to remain after volatile state disappears. Treating those properties as equivalent creates a gap precisely at the failure boundary that atomic replacement is often intended to protect.

Software Engineering 14 Sep 2026 7 min read

Transactional Outboxes Move Atomicity Into the Database

A service updates an order row and emits an event about that update. If the database commit succeeds but the broker publish fails, durable state says one thing while downstream consumers receive no corresponding message. Reversing the order only moves the gap: a successful publish followed by a failed database transaction exposes an event for state that never committed. The difficulty is not message syntax or retry configuration. It is atomicity across two systems that do not share a transaction. A transactional outbox changes the boundary. The application writes its domain state and a message record into the same database transaction, then a separate relay publishes committed outbox records to the broker.