Skip to content

Archive / page 88

All articles

Every practical article from the Nalar archive, newest first.

Artificial Intelligence 01 Sep 2026 5 min read

Validate LLM Output with Structured Contracts

Large language models are useful when software needs to turn ambiguous text into a structured decision, extraction, or plan. The dangerous shortcut is to treat a model response as if it were already trusted application data. Even when a provider can constrain output to JSON or a schema, the result can still be semantically wrong: a date can be impossible, an identifier can refer to a nonexistent record, or a supposedly positive amount can be negative. Reliable integrations therefore need a contract boundary between model output and the rest of the system.

Rust 01 Sep 2026 3 min read

Use the Typestate Pattern to Make Invalid Rust States Unrepresentable

Many APIs have lifecycle rules: a connection must be opened before sending, a transaction must begin before committing, or a builder must receive required values before producing output. Runtime flags can enforce these rules, but Rust can sometimes encode them in types instead. The typestate pattern represents each valid state with a distinct type and makes transitions consume one state to produce another. Encode states as marker types use std::marker::PhantomData; struct Disconnected; struct Connected; struct Connection<State> { endpoint: String, _state: PhantomData<State>, } impl Connection<Disconnected> { fn new(endpoint: String) -> Self { Self { endpoint, _state: PhantomData } } fn connect(self) -> Connection<Connected> { Connection { endpoint: self.endpoint, _state: PhantomData, } } } impl Connection<Connected> { fn send(&self, payload: &[u8]) { println!("sending {} bytes", payload.len()); } } send does not exist for Connection<Disconnected>. Incorrect call ordering becomes a compile-time error instead of a branch in production.

Software Engineering 01 Sep 2026 3 min read

Use the Strangler Fig Pattern for Incremental System Modernization

Large rewrites concentrate technical and delivery risk. Teams can spend months reproducing existing behavior before users receive any benefit, while the original system continues to change. The strangler fig pattern takes a different approach: replace capabilities incrementally and route traffic to the new implementation as each slice becomes ready. Choose a bounded slice Start with a capability that has a clear input, output, and ownership boundary. Good first candidates are important enough to validate the migration approach but not so central that every subsystem must move at once.

JavaScript 01 Sep 2026 3 min read

Use structuredClone for Safe Deep Copying in JavaScript

Copying JavaScript values is easy until nested objects, dates, maps, sets, binary data, or circular references appear. The common JSON round trip works only for a limited subset of values and silently changes some data. The built-in structuredClone() API provides a defined deep-cloning algorithm for many JavaScript data types. Spread syntax is only a shallow copy Object spread copies the first level: const original = { profile: { name: "Ada" } }; const copy = { ...original }; copy.profile.name = "Grace"; console.log(original.profile.name); // "Grace" Both objects still reference the same nested profile. Spread syntax is useful when shallow copying is intentional, but it is not a general deep-copy mechanism.

Python 01 Sep 2026 3 min read

Use Python Protocols for Structural Typing at API Boundaries

Python often relies on duck typing: if an object supports the operation a function needs, its concrete class does not matter. typing.Protocol gives static type checkers a way to describe that idea explicitly without requiring implementations to inherit from a shared base class. Define the behavior you consume from typing import Protocol class ByteWriter(Protocol): def write(self, data: bytes) -> int: ... def emit_header(writer: ByteWriter) -> None: writer.write(b"NLR1") Any statically compatible object can satisfy ByteWriter, even if its class never mentions the protocol.

JavaScript 01 Sep 2026 3 min read

Use JavaScript Import Maps for Browser Module Aliases

Native ES modules normally require browser-resolvable URLs such as ./math.js or /vendor/lib.js. Import maps add a controlled indirection layer so application code can use stable bare specifiers such as app/config without a bundler rewriting imports. Define a map before modules load <script type="importmap"> { "imports": { "app/": "/js/app/", "vendor-utils": "/vendor/utils-v3.js" } } </script> <script type="module" src="/js/main.js"></script> Then /js/main.js can use:

Web Development 01 Sep 2026 3 min read

Use HTTP 103 Early Hints Without Breaking Page Delivery

A server may need time to produce an HTML response even though it already knows that the page will require a stylesheet or other critical resource. HTTP 103 Early Hints lets the server send selected Link hints before the final response so a supporting client can begin useful work sooner. The optimization is optional: the final response still determines the page result. Understand the response sequence A simplified exchange looks like this:

CSS 01 Sep 2026 3 min read

Use CSS Subgrid to Align Nested Components

CSS Grid normally creates an independent track system for every grid container. That isolation is useful until nested components need to align with columns or rows defined by an ancestor. subgrid lets a nested grid reuse those tracks instead of guessing their sizes. Modern evergreen browsers support subgrid, making it practical for production layouts where cross-component alignment matters. The problem with independent nested grids Consider a product list where every card contains a title, description, price, and action. If each card uses its own rows, the buttons move vertically when descriptions have different lengths.

Linux 01 Sep 2026 6 min read

Troubleshooting systemd Services with systemctl and journalctl

When a Linux service fails under systemd, the fastest path to a fix is usually not restarting it repeatedly. A better approach is to inspect the service state, read the relevant logs, confirm the effective unit configuration, and validate changes before trying again. This guide presents a repeatable troubleshooting workflow for modern Linux distributions that use systemd. The examples use commands available in systemd 257, but the core workflow also applies to many earlier systemd releases.

Linux 01 Sep 2026 2 min read

Troubleshoot Linux Services with systemd and journalctl

On systemd-based Linux distributions, a service that “will not start” can fail for many reasons: an invalid command, missing file, permission problem, dependency failure, timeout, or application crash. A repeatable workflow is faster than repeatedly restarting the unit. Start with unit state systemctl status example.service Look at Loaded, Active, the main process exit status, and the most recent log lines. A unit can be loaded correctly while its process exits immediately.

Database 01 Sep 2026 5 min read

Transaction Isolation and Safe Database Retries

Database transactions make groups of reads and writes atomic, but atomicity alone does not answer what concurrent transactions are allowed to observe. That is the job of isolation. The practical challenge appears when correct transactions conflict. Strong isolation can intentionally abort one transaction rather than allow an invalid interleaving. Applications need to distinguish those retryable concurrency failures from ordinary errors. Isolation protects invariants, not just statements Consider two concurrent requests that reserve the last available item.

Go 01 Sep 2026 7 min read

Token Bucket Rate Limiting in Go

Rate limiting protects a service from traffic spikes, accidental client loops, and workloads that consume more resources than the system can safely handle. A useful limiter should do more than enforce a fixed request count: it should allow small bursts while keeping the long-term request rate bounded. The token bucket algorithm provides exactly that behavior. This guide implements a small, concurrency-safe token bucket using only Go’s standard library and then shows how to use it in an HTTP service.

Data Science 01 Sep 2026 4 min read

Time Series Cross-Validation with Walk-Forward Splits

Random train/test splits assume examples are exchangeable. Time-series data violates that assumption because the future occurs after the past, and production models normally predict observations that were not available during training. Walk-forward validation preserves that chronology. Why random splitting is misleading Suppose you want to predict next week’s demand from historical sales. A random split can place March observations in the test set while April observations appear in training. Even if features do not explicitly contain future values, the evaluation now uses a model fitted on a future regime. Seasonality, pricing, inventory, customer behavior, and economic conditions can all make the score more optimistic than deployment reality.

Go 01 Sep 2026 8 min read

Testing Go HTTP Handlers with httptest

HTTP handlers are one of the easiest parts of a Go service to test well. You usually do not need to bind a real network port, start the entire application, or depend on an external test framework. Go’s standard library provides net/http/httptest, which can construct HTTP requests, capture handler responses, and even start temporary HTTP servers when a real client-server round trip matters. This guide builds a small JSON endpoint and tests it at several useful levels.

Go 01 Sep 2026 7 min read

Structured Logging in Go with slog

Plain text logs are easy to print but difficult to query reliably. Once an application runs across multiple processes or containers, operators usually need to filter events by fields such as HTTP status, request path, customer ID, or latency rather than search arbitrary strings. Go’s standard library includes log/slog for structured logging. It was added in Go 1.21, so the examples in this article require Go 1.21 or newer. What structured logging changes A traditional log message often embeds data inside prose:

Go 01 Sep 2026 5 min read

Streaming Pipelines with io.Reader and io.Writer in Go

Go’s io.Reader and io.Writer interfaces are intentionally tiny, but they enable a large class of streaming programs. Files, HTTP bodies, compression streams, hashes, encoders, sockets, and in-memory buffers can all participate in the same pipeline without loading the entire payload into memory. The key design principle is to pass streams through components instead of converting them to []byte or string at every boundary. Start with the two core interfaces The standard library defines the essential contracts as methods equivalent to:

Web Development 01 Sep 2026 5 min read

Safe Database Migrations with the Expand-and-Contract Pattern

A schema migration can be syntactically correct and still cause an outage. Production deployments often run old and new application versions at the same time, background workers may lag behind, and a large table can turn a simple-looking DDL statement into a long lock. The expand-and-contract pattern reduces those risks by splitting an incompatible change into compatible stages. Why one-step schema changes are risky Suppose an application wants to rename users.full_name to users.display_name.

Go 01 Sep 2026 7 min read

Request Coalescing in Go Without Extra Dependencies

When many requests ask for the same expensive resource at the same time, running identical work for every caller can overload a database, API, or filesystem. A cache can help after a result exists, but it does not necessarily prevent several concurrent cache misses from triggering the same backend operation. Request coalescing solves a different problem: while one operation for a key is already running, later callers wait for that operation and share its result. After the operation finishes, the result is forgotten. The next request starts fresh work.

Go 01 Sep 2026 5 min read

Reliable Application Configuration from Environment Variables in Go

Environment variables are a convenient way to configure deployed Go services, but calling os.Getenv throughout an application makes configuration difficult to validate and test. A stronger pattern is to load configuration once at startup, parse it into typed fields, validate all invariants, and pass the resulting value to the components that need it. The examples below use only the Go standard library and work with modern supported Go releases. Keep configuration in a typed struct Suppose a service needs a listen address, request timeout, and optional log level:

Cybersecurity 01 Sep 2026 4 min read

Reduce Software Supply Chain Risk with Dependency Controls

Modern applications routinely execute code downloaded from package registries, container registries, build actions, and language-specific ecosystems. That convenience creates supply chain risk: an attacker does not need to compromise your source repository if they can compromise something your build trusts. No single control eliminates this risk. The practical approach is to reduce unnecessary trust and make dependency changes visible. Treat dependency resolution as a security boundary A manifest may specify broad version ranges, while a lockfile records the exact dependency graph selected for a build.

Python 01 Sep 2026 5 min read

Python Protocols and Structural Subtyping for Flexible APIs

Python code often depends on behavior rather than a specific class hierarchy. A function may only need an object with a send() method, a read() method, or a pair of repository operations. typing.Protocol lets type checkers describe those behavioral requirements directly. A class satisfies a protocol by having compatible members; it does not need to inherit from the protocol. This is structural subtyping: “if it has the required shape, it can be used here.”

Python 01 Sep 2026 4 min read

Python Context Managers for Reliable Resource Cleanup

Python’s with statement is more than convenient file syntax. It is a general protocol for pairing setup with guaranteed cleanup, including when code exits early or raises an exception. Understanding context managers makes resource lifetimes visible and prevents a broad class of leaked files, locks, connections, and temporary state. Why try/finally is the foundation Without a context manager, safe cleanup often looks like this: file = open("input.txt", encoding="utf-8") try: data = file.read() finally: file.close() The finally block runs whether the read succeeds or raises. A with statement packages that pattern:

Cloud Computing 01 Sep 2026 4 min read

Propagate Timeout Budgets Across Cloud Services

A request that crosses several cloud services does not have one timeout. It has a chain of deadlines: client, edge proxy, application, database, and downstream APIs. When those limits are configured independently, an upstream service can give up while downstream work continues consuming connections and CPU for a response nobody will use. An end-to-end timeout budget gives the request one bounded lifetime and lets each hop consume part of it.

Web Development 01 Sep 2026 5 min read

Progressive Enhancement for Resilient Web Forms

A web form does not need JavaScript to submit data. That native capability is a useful reliability baseline. Progressive enhancement starts with semantic HTML and a server endpoint that can complete the operation, then adds JavaScript for faster feedback or richer interactions. If the enhancement fails, the core task still has a path to succeed. This approach is valuable even in highly interactive applications because JavaScript can fail for ordinary reasons: slow networks, stale cached chunks, browser extensions, runtime exceptions, or a partial deployment.