Skip to content

Archive

Software Engineering

462 articles
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.

Software Engineering 19 Sep 2026 7 min read

Deadline Propagation Bounds Request Lifetime Across Service Calls

A request can stop being useful before every process handling it stops working. An HTTP client may give up after two seconds while an upstream service continues a database query, an RPC, and a retry sequence for several more seconds. Those operations still consume connections, CPU time, queue capacity, and downstream concurrency even though their result no longer has a recipient. A deadline makes that usefulness boundary explicit. Propagating it through nested calls gives participating components a common upper bound derived from the original request. This differs from assigning an independent timeout at every hop: local timeouts limit individual operations, while a propagated deadline limits the lifetime of the operation graph.

Software Engineering 19 Sep 2026 8 min read

Compose Multiplatform vs Flutter: Rendering, Performance, and Bundle Size

Compose Multiplatform vs Flutter: Rendering, Performance, and Bundle Size Compose Multiplatform and Flutter can produce similarly smooth mobile interfaces, but they do not reach the screen through the same stack. That difference matters more than the usual “Kotlin versus Dart” comparison. Compose Multiplatform extends the Compose programming model across platforms. Flutter ships a more self-contained UI stack with its own engine and Dart runtime. Both approaches add machinery around application code, but the cost appears in different places: rendering work, startup, memory, binary size, and platform integration.

Software Engineering 19 Sep 2026 7 min read

Circuit Breakers Bound Failure Traffic Across Service Calls

A circuit breaker changes the admission decision for an outbound call before the dependency receives it. In the closed state, calls proceed and their outcomes feed a failure policy. Once that policy trips, the breaker enters the open state and rejects subsequent calls locally. After a configured recovery interval, a limited set of probe calls can test whether the dependency is usable again. That mechanism is distinct from retries. A retry issues another attempt after a failed attempt. A breaker can prevent an attempt from being issued at all. Combining the two without a precise ordering can amplify traffic during an outage or keep a breaker open based on signals that do not represent dependency health.

Software Engineering 19 Sep 2026 6 min read

Circuit Breakers Bound Failure Amplification Across Service Calls

A service call can fail quickly and still create a larger system problem. When every upstream request continues to invoke a downstream dependency that is already failing, each attempt consumes connection capacity, worker time, retry budget, and queue space. The dependency receives traffic it cannot currently serve, while callers spend resources waiting for outcomes that are already strongly correlated with recent failures. A circuit breaker puts a stateful decision boundary in front of that call. Instead of treating every request as an independent opportunity to try the dependency, it records recent failure state and can reject calls locally for a bounded interval. Recovery is then tested through controlled probes rather than a full return of traffic.

Software Engineering 19 Sep 2026 6 min read

Bounded Queues Turn Overload into an Explicit Admission Decision

A queue between a producer and a slower consumer can absorb a temporary rate mismatch. It cannot remove that mismatch. If arrivals continue faster than completions, every accepted item adds to outstanding work. An unbounded queue lets that state accumulate until some other resource becomes the effective limit, often memory or an external timeout. A bounded queue moves the limit into the interface itself. Once capacity is exhausted, admission has to produce an observable result: wait for space, reject new work, discard selected work, or redirect it elsewhere. The queue therefore becomes more than a storage structure. Its capacity and full-queue behavior define part of the system’s overload contract.

Software Engineering 19 Sep 2026 5 min read

Array Syntax in Go, PHP, JavaScript, Kotlin, Rust, and Python

Square brackets make array code look deceptively portable. In Rust, [10, 20, 30] can be a fixed-size array whose length is part of its type. In Python, the same visual shape creates a mutable list. PHP uses bracket syntax for an ordered map, while JavaScript creates a resizable Array object. The syntax is easy to memorize. The more important distinction is what the value means after it has been created.

Software Engineering 19 Sep 2026 6 min read

Android Priority Notifications Are Not VIP Channels

Android Priority Notifications Are Not VIP Channels A pager-style Android application can expose a button labeled VIP channel, but Android does not turn that label into a private radio frequency, reserved cellular bearer, or guaranteed delivery path. What the application can build is a priority policy. A server can classify an event as urgent, request high-priority delivery from Firebase Cloud Messaging (FCM), and post the resulting notification to an Android notification channel with high importance. Those controls operate at different layers, and none of them alone provides pager-like delivery guarantees.

Software Engineering 19 Sep 2026 8 min read

Ad-Supported Utility SaaS: Keep Processing Stateless and Data Ephemeral

Ad-Supported Utility SaaS: Keep Processing Stateless and Data Ephemeral A utility SaaS does not need a large content operation to create repeat traffic. A user may arrive to resize an image, clean a CSV file, convert structured data, generate a QR code, validate a document, or run another narrow transformation. The technical challenge is different from a conventional content site: each visit performs work. That work can become expensive quickly if every request uploads a file, allocates server memory, writes temporary objects, invokes a database, and retains artifacts after the user leaves. An ad-supported free tier makes this pressure more visible because revenue per visit is usually small compared with the cost of heavy compute or storage.

Software Engineering 18 Sep 2026 5 min read

timerfd Turns Timer Expirations into Descriptor Readiness

A timerfd becomes readable after its timer expires. The notification is not a signal handler invocation and not a byte-stream message. Linux records pending expirations on a timer object and exposes that state through a file descriptor, so a timer can occupy the same readiness boundary as sockets, pipes, and other descriptors. That interface does more than replace one notification mechanism with another. Clock selection determines the time domain, arming flags determine whether a deadline is relative or absolute, and each successful read reports the number of expirations accumulated since the preceding successful read or timer reconfiguration.

Software Engineering 18 Sep 2026 4 min read

timerfd Turns Timer Expiration Counts into Pollable Descriptor State

A Linux timerfd becomes readable when its configured timer has expired. The bytes returned by read(2) are not a timestamp or event record: they encode one unsigned 64-bit integer containing the number of expirations since the previous successful read. Timer state therefore participates in the same readiness machinery as sockets and pipes while retaining timer-specific semantics behind the descriptor boundary. Readiness represents a pending expiration count timerfd_create(2) creates a descriptor associated with a clock, while timerfd_settime(2) arms or disarms its timer. Once at least one expiration is pending, poll(2), select(2), and epoll(7) can report the descriptor as readable.

Software Engineering 18 Sep 2026 5 min read

SO_REUSEPORT Moves Listener Distribution into Socket Selection

SO_REUSEPORT permits multiple Linux AF_INET or AF_INET6 sockets to bind the same local address and port when every member satisfies the reuse-port rules. For TCP listeners, this moves incoming connection distribution ahead of accept(): the kernel selects a listener from the reuse-port group, and that listener receives the connection on its accept queue. For UDP, selection determines which socket receives an incoming datagram. This is a different concurrency boundary from several threads sharing one listening file description. Each reuse-port member is a distinct socket, with its own descriptor, queues, polling state, and lifecycle.

Software Engineering 18 Sep 2026 3 min read

signalfd Routes Pending Signals Through Descriptor I/O

A Linux signalfd becomes readable when a signal selected by its mask is pending for the reading context. A successful read(2) consumes pending signal state and returns one or more fixed-size signalfd_siginfo records. Signal handling can therefore enter a descriptor-driven event loop without turning asynchronous handlers into the primary dispatch mechanism. The descriptor mask does not block signals The mask passed to signalfd(2) selects signals that the descriptor can accept. It does not modify the calling thread’s signal mask. Normal use separately blocks those signals with sigprocmask(2) or pthread_sigmask(3) so their ordinary dispositions do not run before descriptor consumption.

Software Engineering 18 Sep 2026 6 min read

SCM_RIGHTS Transfers Open File Descriptions Across Process Boundaries

SCM_RIGHTS lets one process send a reference to an open file through a Unix domain socket. The receiver obtains a file descriptor in its own descriptor table, but the transfer does not reopen the pathname or copy the kernel object. On Linux, the resulting reference has semantics equivalent to duplicating the sender’s descriptor into the receiving process. That distinction matters whenever a process boundary is also an authority boundary. A supervisor can open a socket, file, pipe, device, or other descriptor-backed object and pass the established reference to a worker. The worker receives access to the already-open object, including open-file state that can remain shared with the sender.

Software Engineering 18 Sep 2026 4 min read

pidfds Bind Process Operations to Stable Kernel References

A numeric PID names a process only while that PID remains assigned to it. After termination and reaping, Linux can reuse the number for another process. A PID file descriptor, or pidfd, instead holds a kernel reference to a specific task, so later operations can target that task without resolving its numeric PID again. This distinction removes a class of time-of-check/time-of-use races from process management. It does not make a process immortal, grant extra permissions, or turn every process operation into a portable descriptor API.

Linux 18 Sep 2026 6 min read

pidfd_getfd Duplicates Another Process File Descriptor into the Caller

A file descriptor number has meaning only inside its process descriptor table, but the kernel object behind that number can be shared across processes. Linux pidfd_getfd() bridges those two scopes: it takes a PID file descriptor plus a descriptor number from the referenced process and installs a duplicate descriptor in the caller. The new descriptor refers to the same open file description as the target descriptor. That last property is the central boundary. pidfd_getfd() does not reopen a pathname, copy bytes, or create an independent file position. It duplicates an existing kernel reference and therefore inherits sharing semantics that can affect both processes.

Cybersecurity 18 Sep 2026 5 min read

openat2 Resolution Flags Constrain Path Traversal at the Kernel Boundary

A service can validate a pathname and still open a different object if the namespace changes between validation and use. Symbolic links, mount topology, rename operations, and special procfs links make pathname resolution a kernel operation with state that can change concurrently. Linux openat2() addresses part of this boundary by attaching resolution constraints to the lookup that produces the file descriptor. The security property is narrower than generic path sanitization. openat2() does not declare a pathname safe. It lets a caller ask the kernel to reject specific resolution behavior while the kernel performs the walk.

Software Engineering 18 Sep 2026 5 min read

openat2 Constrains Path Resolution Inside a Directory Boundary

A pathname is not a stable object reference. Between its starting directory and final component, Linux path resolution may follow symbolic links, cross mount points, process .., or encounter special links exposed by pseudo-filesystems. openat2() lets a caller attach constraints to that resolution operation so the kernel can reject a lookup that leaves the intended boundary. The distinction is stronger than checking a normalized string before open(). String validation examines syntax. openat2() can constrain the kernel’s actual traversal while filesystem objects and mount topology participate in the lookup.

Software Engineering 18 Sep 2026 4 min read

memfd Seals Turn Shared File State into Monotonic Restrictions

A memfd_create() file can begin as writable shared state and later become progressively more constrained. File seals make that transition monotonic: successful seals are properties of the inode, affect every descriptor referring to it, and cannot be removed. That property is useful when one process prepares bytes and then transfers a descriptor to another process. The receiver can inspect kernel-enforced restrictions instead of relying only on a protocol promise that the producer has stopped changing the object.

Software Engineering 18 Sep 2026 8 min read

MAP_SHARED mmap Couples Memory Writes to File-Backed Page State

A writable MAP_SHARED mapping lets a process modify file-backed state with ordinary memory stores. The bytes are addressed through virtual memory rather than passed to write(), but the mapping still participates in filesystem state: modifications can become visible through other shared mappings and file I/O, and dirty pages can later be written back to storage. That interface compresses several mechanisms into one address range. CPU stores, page faults, page-cache residency, filesystem writeback, and storage persistence can all participate in the lifetime of the same bytes. Treating a successful store as equivalent to durable file output collapses boundaries that the operating system keeps distinct.

Software Engineering 18 Sep 2026 6 min read

Linux userfaultfd Moves Selected Page Fault Handling into User Space

A page fault normally crosses from a process into the kernel and returns only after the kernel has resolved the virtual-memory condition or delivered an error. Linux userfaultfd can insert a user-space component into that path for explicitly registered address ranges. The kernel reports selected faults through a file descriptor, blocks the faulting execution context when the mode requires it, and accepts an ioctl that resolves the fault. This is a Linux virtual-memory interface, not a C or POSIX memory guarantee. Its behavior depends on negotiated kernel features, the registered range, its mapping type, and the registration mode.