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 19 Sep 2026 6 min read

Write Skew Breaks Cross-Row Invariants Under Snapshot Isolation

Snapshot isolation can let two transactions commit even when their combined result violates a rule that each transaction checked before writing. The anomaly appears when both transactions read the same logical condition, then write different rows. Because their write sets do not overlap, ordinary write-write conflict detection has nothing to reject. This is write skew. It matters at the boundary between application invariants and database isolation: a transaction may see a consistent snapshot and still participate in a final state that would have failed its own predicate.

Software Engineering 19 Sep 2026 5 min read

Version Columns Turn Database Updates into Conditional State Transitions

A database client can read a row, spend time computing a change, then issue an UPDATE after another transaction has already changed the same row. If the final statement identifies the row only by its primary key, the later write can replace state derived from the intervening transaction without any visible conflict. A version column changes that boundary. The client reads both the application state and a revision value, then includes that revision in the update predicate. The database accepts the write only while the stored revision still matches the state the client observed.

Software Engineering 19 Sep 2026 8 min read

Transactional Outbox Couples State Change to Message Intent

A service that updates its database and publishes an event to a message broker crosses two independent commit boundaries. If the database commit succeeds and the broker publish fails, durable state exists without its corresponding message. Reversing the order only reverses the failure: a consumer can observe a message for a state change that never commits. A transactional outbox narrows this gap by placing the application write and a durable message record in the same local database transaction. Publication moves to a separate relay. The pattern does not make the database and broker one atomic system; it changes the boundary so message intent becomes part of the database commit.

Software Engineering 19 Sep 2026 7 min read

Sequence Counters Detect Concurrent Writes Without Reader Locks

A sequence counter can let readers copy shared state without taking the writer’s lock. The reader samples a counter, copies the protected fields, then samples the counter again. A stable even value at both observations indicates that no writer overlapped the copy under the synchronization contract. A changed or odd value forces the reader to discard the snapshot and retry. This pattern moves work away from reader-side lock ownership, but it does not remove synchronization. Writers still need serialization, counter transitions need defined memory-ordering semantics, and the protected data must remain safe to access during an overlapping write. Those constraints make sequence counters suitable for some read-mostly snapshots and unsafe for data whose lifetime can disappear beneath a reader.

Software Engineering 19 Sep 2026 6 min read

seccomp User Notification Moves Selected Syscall Decisions to a Broker

A seccomp filter can do more than allow or reject a system call immediately. With user notification, a matching call can be suspended while another process receives a structured request on a listener file descriptor and decides what result the blocked thread receives. The mechanism turns selected syscall decisions into a brokered interface without moving the entire syscall implementation into user space. The boundary is precise but narrower than a general interposition layer. The kernel still owns syscall dispatch, task state, descriptor tables, and validation performed by kernel code. The broker receives metadata and can return a value, an error, or in supported cases request continued execution of the original syscall. Correct designs account for mutable target memory, notification lifetime, and the fact that a policy decision is not automatically a transaction over process state.

Software Engineering 19 Sep 2026 6 min read

Request Coalescing Collapses Concurrent Cache Misses into One Fill

A cache can reduce steady-state backend traffic yet amplify work at the instant a popular entry expires. If one hundred requests observe the same missing key before any replacement value is stored, a conventional lookup path can send one hundred equivalent reads to the origin. The cache is functioning according to its lookup rules; the amplification comes from concurrency around the empty interval. Request coalescing changes that interval. The first caller for a key starts the fill, while later callers for the same key attach to that in-flight operation instead of starting equivalent work. When the operation completes, its result is distributed to the waiting callers and, when appropriate, stored in the cache.

Software Engineering 19 Sep 2026 5 min read

process_vm_readv and process_vm_writev Transfer Memory Across Process Boundaries

process_vm_readv() and process_vm_writev() let one Linux process copy bytes directly between its address space and another process’s address space. The calls operate on vectors of local and remote memory ranges, but a successful process lookup does not make remote memory stable. Mapping changes, page accessibility, permissions, and concurrent mutation remain separate parts of the contract. These interfaces are Linux-specific system calls. They do not define C object lifetime, synchronization, or a portable interprocess-memory model.

Software Engineering 19 Sep 2026 8 min read

Open File Description Locks Bind Byte Ranges to File Instances

A byte-range lock can protect the same inode yet have radically different lifetime semantics depending on what owns the lock. Traditional fcntl() record locks are process-associated. Open file description locks instead attach to the kernel open file description referenced by a descriptor. That shift changes which close operation releases a lock, what survives fork(), and whether two threads in one process can contend on the same file region. Linux exposes this model through F_OFD_SETLK, F_OFD_SETLKW, and F_OFD_GETLK. The range model remains familiar: struct flock specifies a read lock, write lock, or unlock together with an offset and length. The significant difference is ownership.

Software Engineering 19 Sep 2026 8 min read

MQTT and QUIC Solve Different Parts of a Chat Transport

MQTT and QUIC Solve Different Parts of a Chat Transport MQTT and QUIC are often placed in the same comparison table when discussing real-time chat. That comparison is convenient, but it collapses two different protocol layers into one choice. MQTT is an application-layer messaging protocol. It defines concepts such as clients, brokers, topics, subscriptions, retained messages, session state, and delivery quality of service. QUIC is a secure transport protocol over UDP. It provides connections, streams, flow control, loss recovery, encryption, and connection migration mechanisms.

Software Engineering 19 Sep 2026 5 min read

LLVM Poison Values Defer Undefined Behavior Through the IR

LLVM IR does not turn every invalid arithmetic or pointer condition into immediate undefined behavior. Many instructions produce a poison value instead. That value can flow through later instructions, preserving the optimizer’s ability to rely on promises such as “this addition does not overflow” without forcing undefined behavior at the exact instruction where the promise is violated. This is part of LLVM’s semantics, not an optimizer implementation detail. A frontend that emits nsw, nuw, inbounds, noundef, or related constraints is stating facts that later passes may trust.

Software Engineering 19 Sep 2026 6 min read

Linux pidfds Bind Process Operations to Stable Kernel References

A numeric process ID names a process only while that PID remains assigned to it. After process exit and reaping, Linux may reuse the number for another process. Code that observes a PID, performs unrelated work, then acts on that number can therefore cross a lifetime boundary that the integer itself does not encode. Linux pidfds provide a file-descriptor reference to a process so later operations can target the referenced process object rather than repeat a numeric PID lookup.

Software Engineering 19 Sep 2026 6 min read

Linux membarrier Moves Memory Ordering Cost to a Coordinating Thread

A concurrent runtime can have thousands of fast-path operations for every rare state transition that requires global coordination. Placing a full memory barrier on every fast path makes each operation pay for that rare transition. Linux membarrier() supports the opposite arrangement: a coordinating thread enters the kernel and forces a defined ordering point across a target set of threads, moving more cost to the infrequent side of the protocol. This is not a generic replacement for atomics, mutexes, or language memory models. It is a Linux kernel interface whose guarantees apply to memory accesses and targeted threads under specific commands. Correct use requires a protocol that already defines which accesses occur before and after the coordination point.

Software Engineering 19 Sep 2026 6 min read

io_uring Linked Requests Encode Dependency in Submission Order

An io_uring submission queue can contain many operations at once, but not every operation has to be independent. Setting IOSQE_IO_LINK on a submission queue entry binds it to the next entry, forming a chain in which execution order and failure propagation become part of the kernel-visible request structure. That changes the contract compared with submitting two unrelated SQEs and coordinating them after completion. A linked chain expresses dependency before the kernel starts processing the operations. The distinction matters when a later request is valid only after an earlier request has completed, or when failure of one stage should prevent the remaining stages from running.

Software Engineering 19 Sep 2026 6 min read

Idempotency Keys Bound Retry Safety to a Request Identity

A client can send the same logical operation more than once even when it intended one effect. A timeout after POST /payments leaves an ambiguous boundary: the server may have committed the payment while the client received no response. Retrying restores delivery, but an ordinary retry can create a second payment. An idempotency key changes the interface by giving repeated attempts a stable request identity. The key is not a substitute for transactionality, and it does not make every operation intrinsically idempotent. It creates a protocol between client and server: attempts carrying the same key are treated as candidates for the same logical operation. The server still needs rules for request equivalence, concurrent arrival, persistence lifetime, failure recovery, and response replay.

Software Engineering 19 Sep 2026 7 min read

Idempotency Keys Bind Retries to One Logical Mutation

A client can lose an HTTP response after the server has committed the requested mutation. From the client’s perspective, the operation is unresolved: the connection failed, but that failure does not reveal whether durable state changed. Retrying the same POST can then create a second order, payment attempt, reservation, or other mutation. An idempotency key gives the retry a stable identity that is separate from any single transport attempt. The server can associate repeated requests carrying that identity with one logical operation. That mechanism narrows an ambiguity at the API boundary, but the key alone is not a guarantee. Its scope, persistence, request comparison, concurrency control, and replay policy determine what repeated delivery actually means.

Software Engineering 19 Sep 2026 7 min read

How Language Runtimes Use CPU Cores: Threads, Goroutines, Workers, and Processes

A CPU with many cores does not make application code parallel by itself. The operating system can schedule multiple threads at the same time, but the language and runtime decide how application work reaches those threads. That distinction explains why Go, Rust, C++, Java, JavaScript, and PHP can all use a multicore machine even though their programming models look very different. The useful question is not simply whether a language is “multithreaded.” It is how a unit of application work becomes something the operating system can schedule.

Software Engineering 19 Sep 2026 5 min read

How GitHub Codespaces Uses Core-Hours, Port Forwarding, and CI

A GitHub Codespace is a development machine running in the cloud, not a CI runner with an editor attached. It stays interactive while a developer edits files, runs commands, starts servers, debugs processes, and commits changes. That distinction explains three behaviors that are easy to confuse: how compute quota is measured, how localhost becomes reachable from a browser, and where CI begins after code is pushed. Core-hours measure machine capacity multiplied by active time Codespaces compute usage is measured in core-hours. The accounting model is straightforward:

Software Engineering 19 Sep 2026 6 min read

Generation Counters Keep Reused Handles Bound to the Right Resource

A compact handle often looks like an integer because an integer is cheap to store, copy, compare, and pass across an API boundary. In a table-backed resource manager, that integer may simply be an index into a slot array. The representation works until a slot is released and later reused. An old handle can then point at a new resource that happens to occupy the same index. The failure is not an out-of-bounds access. The index can be perfectly valid. The problem is identity: the handle names a storage location, while the caller treats it as the identity of the resource that once occupied that location.

Software Engineering 19 Sep 2026 6 min read

Fencing Tokens Reject Stale Writers After Lease Expiry

A distributed lease can transfer ownership without stopping the process that previously held it. A worker may pause long enough for its lease to expire, then resume after another worker has acquired the same lease. At that point both processes can execute code that was written under the assumption of exclusive ownership. Lease expiry settles ownership in the coordination service. It does not revoke CPU time, cancel an in-flight network request, or erase buffered I/O on the former holder. Fencing tokens address that gap by carrying an ordering value from the ownership decision to the resource being protected.

Software Engineering 19 Sep 2026 6 min read

Fencing Tokens Close the Stale Lease Writer Gap

A distributed lease can expire while its holder is unable to run. The holder may later resume with local state that still says it owns the lease, even though another client has already acquired a newer lease. If the protected storage or service accepts operations solely because the client once acquired the lease, two clients can mutate the same resource across different points in time. A fencing token moves the decisive check from lease ownership into the protected resource. Each successful acquisition receives a token ordered after every earlier token. The resource records the greatest accepted token and rejects operations carrying an older value. The lease still coordinates acquisition, but the token constrains what a delayed former holder can do after it resumes.

Software Engineering 19 Sep 2026 8 min read

FCM Is a Wake-Up Path, Not a Real-Time Transport

FCM Is a Wake-Up Path, Not a Real-Time Transport A mobile application can maintain a WebSocket while it is active and still need Firebase Cloud Messaging when the operating system suspends it. Those mechanisms solve different failure conditions. WebSocket, MQTT, and SignalR assume that a client can participate in a live communication session. FCM is useful precisely when that assumption no longer holds: the application may be backgrounded, its process may not be running, or its persistent connection may have disappeared.

Software Engineering 19 Sep 2026 6 min read

ETag Preconditions Prevent Lost Writes in HTTP Update APIs

Two clients can read the same resource, edit different fields, and send updates seconds apart. If the server accepts both writes without checking which representation each client edited, the later request can silently replace state written by the earlier one. The transport succeeded, yet the application lost a concurrent change. HTTP provides a conditional request mechanism for this boundary. A server can attach an entity tag to a representation, and a client can return that tag in If-Match when submitting a state-changing request. The update proceeds only while the selected representation still satisfies the supplied precondition.

Software Engineering 19 Sep 2026 5 min read

EPOLLET Makes Readiness a State-Transition Contract

A descriptor registered with EPOLLET can remain readable after an event has been delivered without appearing again in the next epoll_wait(). The kernel reports a readiness transition; it does not promise to repeat the same notification merely because unread data remains. That distinction turns edge-triggered epoll into a state-transition contract between the kernel and the event loop. The consequence is structural. A handler cannot treat one event as permission for one read() and then return to the wait loop. With edge-triggered monitoring, the handler must account for all immediately available I/O state before relying on another transition.

Software Engineering 19 Sep 2026 5 min read

Edge-Triggered epoll Requires Draining Readiness to EAGAIN

With EPOLLET, an event loop can consume one notification, read only part of the available data, and then wait indefinitely even though unread bytes remain in the socket buffer. The descriptor is still ready, but no new readiness transition has occurred to generate another edge. That behavior makes edge-triggered epoll a contract between notification semantics and nonblocking I/O. The event says that readiness changed; it is not a promise that the kernel will keep repeating the same notification until the application finishes the work.