Skip to content

Archive / page 54

All articles

Every practical article from the Nalar archive, newest first.

Python 09 Sep 2026 9 min read

Shut Down asyncio Worker Queues Cleanly

Asynchronous worker pools often start with a simple pattern: producers put jobs into an asyncio.Queue, consumers loop over get(), and the application waits for join() before exiting. The awkward part is shutdown. Older designs commonly put one sentinel value into the queue for each worker, cancel consumers after join(), or maintain a separate stop event. Each approach can work, but each adds a second protocol beside the queue itself. Python 3.13 added asyncio.Queue.shutdown() and the asyncio.QueueShutDown exception. They let the queue represent its own lifecycle: open for producers, shutting down while existing work drains, and finally closed to consumers.

Artificial Intelligence 09 Sep 2026 10 min read

Select Active Learning Examples with BALD

When labels are expensive, training on every available example may be impractical. An active learning system tries to spend its labeling budget selectively: train a model on the labels already available, score unlabeled examples, request labels for useful examples, then retrain. A common first idea is to label the examples with the highest predictive entropy. That can help, but entropy mixes together two different reasons for uncertainty. The model may be uncertain because it does not yet know enough, or because the input itself is genuinely ambiguous. More labels are most valuable for the first case.

Python 09 Sep 2026 10 min read

Run CPU-Bound Python with InterpreterPoolExecutor

For CPU-heavy Python work, I usually reach for ProcessPoolExecutor. Threads are convenient, but ordinary CPython threads do not give CPU-bound Python code the kind of multi-core parallelism people often expect. Python 3.14 adds another option: concurrent.futures.InterpreterPoolExecutor. It looks deliberately familiar. You still submit callables and receive futures, but every worker thread owns a separate Python interpreter. Each interpreter has its own GIL, so Python code in different workers can execute on different CPU cores at the same time.

Software Engineering 09 Sep 2026 9 min read

Replacing Boolean Parameters with Explicit Choices

A call such as sendReport(report, true) may be perfectly valid code, yet it makes the reader stop. What does true mean? Send immediately? Include attachments? Compress the report? The answer exists somewhere in the called function’s contract, but it is not visible at the call site. Boolean parameters become a design problem when they represent an important choice between behaviors. They compress that choice into true or false, so callers must remember what each value means and the implementation often grows branches around the flag.

Python 09 Sep 2026 10 min read

Reload Process Environment Variables with Python 3.14

Python applications often treat environment variables as if every read goes straight to the operating system. In CPython, that mental model is incomplete. os.environ is a mapping captured when the os module is first imported, normally during interpreter startup. If the process environment later changes through something outside that mapping, Python’s cached view can become stale. Python 3.14 adds os.reload_environ() for the unusual cases where an application really needs to refresh that view.

Software Engineering 09 Sep 2026 8 min read

Reducing Positional Coupling in Function Calls

A function can be perfectly implemented and still be easy to call incorrectly. One common cause is a parameter list in which several values have the same representation and their meaning depends mainly on position. Consider a reporting function that accepts three dates. At the call site, the values may all look valid even when two of them are accidentally reversed. A compiler or type checker often cannot help because each argument still has the expected type.

Software Engineering 09 Sep 2026 8 min read

Reducing Coupling with the Law of Demeter

A small change to one class should not routinely force edits in code that is several objects away. Yet this happens when callers navigate through collaborators to reach deeper objects: order.customer().address().country().code() The line is compact, but the caller now knows that an order exposes a customer, a customer exposes an address, an address exposes a country, and a country exposes a code. If that structure changes, the caller may need to change even when the business question it asks stays the same.

Python 09 Sep 2026 13 min read

Reduce Filesystem Stat Calls with Python Path.info

Filesystem code often looks cheap until it runs over a directory with hundreds of thousands of entries. A loop that asks whether every path is a file, directory, or symbolic link can translate into a large number of metadata queries. On a local SSD that cost may be tolerable. On network filesystems, container-mounted volumes, or very large trees, repeated metadata lookups can become a noticeable part of runtime. Python 3.14 adds Path.info, a cached file-type information interface on pathlib.Path. It is especially useful when paths come from Path.iterdir(), because Python may initialize the cache with information already obtained while scanning the directory.

Database 09 Sep 2026 10 min read

Recover Durable Object SQLite Data with Point-in-Time Recovery

A database mistake is rarely dramatic at first. It is usually one bad UPDATE, an application bug that overwrites valid state, or a deployment that writes data in a shape we did not expect. With a normal SQLite database, I would think about backups before making a risky change. SQLite-backed Cloudflare Durable Objects add another useful option: point-in-time recovery, or PITR. Cloudflare keeps enough history to restore an object’s embedded SQLite database to a point within the previous 30 days.

Cybersecurity 09 Sep 2026 10 min read

Rate Limit by the Resource an Attacker Can Exhaust

A rate limit can look effective in testing and still fail against the abuse it was meant to control. The usual reason is not the counter or the algorithm. It is the key used to group requests. Suppose a password-recovery endpoint allows five requests per hour from each source address. That may slow one client, but it does not directly protect a user’s mailbox from receiving hundreds of recovery messages sent through many source addresses. The resource under pressure is the destination account or delivery channel, while the limit is counting something else.

Software Engineering 09 Sep 2026 11 min read

Propagating Deadlines Through Call Chains

A request can have a timeout at every network call and still take far longer than the caller intended. The problem appears when each layer starts a fresh timeout. A frontend gives service A 800 milliseconds. Service A spends 300 milliseconds doing local work, then gives service B another 800 milliseconds. Service B spends 250 milliseconds and gives service C yet another 800 milliseconds. Every individual timeout looks reasonable, but the chain no longer has an 800-millisecond limit.

Software Engineering 09 Sep 2026 8 min read

Null Object Pattern for Optional Behavior

Optional behavior often begins with one harmless-looking condition. A component may send notifications only when a notifier is configured, record metrics only when metrics are enabled, or write audit events only in some deployments. As the code grows, the same absence check can spread across many call sites: if notifier != null: notifier.send(message) The condition is simple, but repetition creates a maintenance problem. Every caller must remember that the collaborator may be absent and must know what absence means.

Cybersecurity 09 Sep 2026 10 min read

Normalize Once Before Security Validation

A security check can inspect the right field and still make the wrong decision if another component interprets that field differently later. Consider an application that accepts a path-like identifier. One layer rejects values containing a forbidden segment. A later layer decodes or normalizes the value before using it. If those two layers do not agree on what the input means, the application may approve one representation and act on another.

Software Engineering 09 Sep 2026 9 min read

Moving Behavior Toward the Data It Uses

A method can live in one class while doing most of its work with another class’s data. At first this may seem harmless: the code runs, the names are clear, and the calculation is short. Over time, however, the method often becomes a second place that knows how the other object works. That design smell is commonly called feature envy. A piece of behavior appears to “envy” another object’s features because it reads that object’s state or calls its methods much more than it uses its own.

Python 09 Sep 2026 12 min read

Model UUID Sentinels with uuid.NIL and uuid.MAX

UUIDs are often treated as ordinary identifiers: generate one, store it, compare it, and pass it between services. But some systems also need boundary or sentinel UUID values. A protocol may reserve an all-zero identifier for “no object.” A range query may need the lowest or highest possible UUID. Test fixtures may need deterministic endpoints without inventing magic strings. Python 3.14 makes those cases explicit with two constants from RFC 9562:

Python 09 Sep 2026 13 min read

Migrate Time-Based Identifiers from UUIDv1 to UUIDv6 in Python 3.14

UUID version 1 has been around for a long time. It combines a timestamp, a clock sequence, and a node identifier into a 128-bit value, which makes it useful when applications need identifiers that can be generated without coordinating through a central database sequence. Its layout has an awkward property, though: the timestamp bits are not arranged from most significant to least significant in the same order that ordinary UUID comparison uses.

Python 09 Sep 2026 11 min read

Manage Subinterpreters Directly with Python 3.14

Python 3.14 gives application code a new way to work directly with multiple interpreters in one process. The concurrent.interpreters module exposes a high-level API for creating interpreters, running code inside them, and communicating through cross-interpreter queues. It sits below InterpreterPoolExecutor: instead of submitting independent jobs to a ready-made pool, you own the interpreter lifecycle and decide how work reaches each isolated execution context. That extra control is useful, but it also removes several conveniences an executor normally provides. A subinterpreter is not a lightweight thread with shared globals, and creating one does not automatically create concurrency.

Software Engineering 09 Sep 2026 8 min read

Making Complex Rules Visible with Decision Tables

Conditional code often starts clearly. One condition becomes two, then a special case appears, and eventually nobody can answer a simple question with confidence: have we covered every meaningful combination? The problem is not necessarily that if statements are bad. The problem is that branching code makes a set of rules visible one execution path at a time. When several independent conditions affect one decision, developers must mentally reconstruct the whole rule set from those paths.

Python 09 Sep 2026 13 min read

Make Warning Tests Concurrency-Safe with Context-Aware Warnings

Python’s warnings.catch_warnings() is convenient in tests, compatibility shims, and small diagnostic scopes. It lets code temporarily change warning filters and then restore the previous state. That model becomes harder to reason about when several threads or asynchronous tasks use it at the same time. Historically, catch_warnings() manipulated process-global state in the warnings module. Two overlapping contexts could therefore interfere with each other. Python 3.14 adds an opt-in context-aware mode that changes this behavior. When sys.flags.context_aware_warnings is true, catch_warnings() stores its filtering state in a context variable instead of mutating the same global warning state for every concurrent execution path.

Cybersecurity 09 Sep 2026 10 min read

Make Tenant Context Part of Every Authorization Decision

A multi-tenant application can have correct login logic and still expose one customer’s data to another. The failure often begins with an authorization check that asks only whether a user may access a resource, while forgetting to verify the tenant in whose context that access is being requested. A tenant is an isolated customer, organization, workspace, or similar security domain that shares an application with other tenants. Tenant isolation means actions intended for one tenant should not silently cross into another.

Cybersecurity 09 Sep 2026 10 min read

Make Sensitive Requests Replay-Resistant

A server can correctly prove that a request came from a trusted client and still process it more times than intended. If an authenticated request says “approve this payout” or “change this recovery address,” accepting the same valid request twice can create a security problem even though neither copy was forged. This is a replay problem. A replay happens when a previously valid message is presented again and the receiver cannot tell that its authority has already been used, or that the message is too old to trust.

Cybersecurity 09 Sep 2026 8 min read

Make Authorization Policy Conflicts Explicit

Authorization becomes difficult when more than one rule applies to the same request. One policy may grant a developer access to a project while another restricts access to confidential records. If the system has no explicit rule for combining those policies, a small implementation detail can decide whether access is granted. That is a security problem because developers, administrators, and reviewers may believe different policies take precedence. A later refactor can then change effective access without anyone intending to change the security model.

Artificial Intelligence 09 Sep 2026 9 min read

LLM Sampling: Temperature, Top-K, and Top-P

A language model does not normally produce a single inevitable next token. Given a prefix, it assigns scores to many possible tokens. A decoding algorithm then decides how to turn those scores into the next output. That last step matters. If you sample too freely, a model can drift into unlikely continuations. If you restrict sampling too aggressively, outputs can become repetitive or lose useful variation. Parameters such as temperature, top-k, and top-p control different parts of this trade-off, so treating them as interchangeable “creativity settings” leads to confusing results.

Cybersecurity 09 Sep 2026 11 min read

Limit Decompression Before Processing Untrusted Archives

An upload limit can look like a complete resource limit until the application accepts compressed input. A small archive may expand into far more data than its uploaded size suggests, contain an excessive number of entries, or require enough decompression work to tie up workers. If the service trusts the compressed size, an attacker may be able to exhaust disk, memory, CPU time, or processing capacity without sending a large request.