<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Vaibhav Somani</title><link>https://vabs.github.io/</link><description>Recent content on Vaibhav Somani</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sun, 14 Jun 2026 09:30:00 -0400</lastBuildDate><atom:link href="https://vabs.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Idempotent Consumers in Event Streams</title><link>https://vabs.github.io/2026/06/14/idempotent-consumers-in-event-streams/</link><pubDate>Sun, 14 Jun 2026 09:30:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/14/idempotent-consumers-in-event-streams/</guid><description>&lt;p&gt;In any event-driven system, the consumer will eventually receive the same event twice. This is not a bug you can engineer away — it is a structural consequence of how reliable messaging works. Brokers guarantee at-least-once delivery, which means redelivery on uncertain acknowledgments. Producers retry on lost responses. Rebalances replay uncommitted offsets. Network partitions resurrect in-flight messages. The only robust response is to make the &lt;em&gt;consumer&lt;/em&gt; tolerate duplicates: to build an &lt;strong&gt;idempotent consumer&lt;/strong&gt;, one whose effect on the world is the same whether it processes an event once or ten times.&lt;/p&gt;</description></item><item><title>Data Pipeline Backpressure Handling</title><link>https://vabs.github.io/2026/06/11/data-pipeline-backpressure-handling/</link><pubDate>Thu, 11 Jun 2026 15:48:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/11/data-pipeline-backpressure-handling/</guid><description>&lt;p&gt;Every data pipeline is a chain of producers and consumers operating at different, time-varying speeds. When an upstream stage produces faster than a downstream stage can consume, work accumulates somewhere. Backpressure is the mechanism by which a slow consumer tells a fast producer to slow down, so that &amp;ldquo;somewhere&amp;rdquo; is a bounded, intentional place rather than an unbounded queue that eventually exhausts memory and crashes the process.&lt;/p&gt;
&lt;p&gt;Handling backpressure well is the difference between a pipeline that degrades gracefully under load and one that falls over the moment traffic exceeds steady-state capacity. This post covers the failure mode, the strategies for absorbing and propagating pressure, and the trade-offs of each.&lt;/p&gt;</description></item><item><title>Exactly-Once Processing Guarantees</title><link>https://vabs.github.io/2026/06/08/exactly-once-processing-guarantees/</link><pubDate>Mon, 08 Jun 2026 13:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/08/exactly-once-processing-guarantees/</guid><description>&lt;p&gt;&amp;ldquo;Exactly-once&amp;rdquo; is the most misunderstood phrase in distributed systems. Taken literally — every message is delivered and processed precisely one time, no more, no less, under all failures — it is provably impossible in an asynchronous network with crashes. Yet &amp;ldquo;exactly-once&amp;rdquo; appears prominently in the marketing of Kafka, Flink, and every modern stream processor. The resolution to this apparent contradiction is the key to understanding the whole topic: what these systems actually provide is &lt;strong&gt;exactly-once &lt;em&gt;processing semantics&lt;/em&gt;&lt;/strong&gt; (often called effectively-once), achieved by combining at-least-once delivery with deduplication and atomic state commits — not exactly-once &lt;em&gt;delivery&lt;/em&gt;.&lt;/p&gt;</description></item><item><title>Feature Flags with Rollout Strategies</title><link>https://vabs.github.io/2026/06/05/feature-flags-with-rollout-strategies/</link><pubDate>Fri, 05 Jun 2026 10:22:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/05/feature-flags-with-rollout-strategies/</guid><description>&lt;p&gt;Feature flags decouple deployment from release. Once that decoupling exists, the interesting engineering question stops being &amp;ldquo;is the code in production?&amp;rdquo; and becomes &amp;ldquo;for whom is this code active, and how do we move that population safely from 0% to 100%?&amp;rdquo; A rollout strategy is the answer to that second question, encoded as data rather than as a redeploy.&lt;/p&gt;
&lt;p&gt;This post covers the backend mechanics of feature flagging: flag evaluation models, the common rollout strategies, consistency guarantees, and the operational machinery (kill switches, observability, cleanup) that separates a toy flag library from a production-grade release platform.&lt;/p&gt;</description></item><item><title>Tearing in concurrent UI</title><link>https://vabs.github.io/2026/06/05/tearing-in-concurrent-ui/</link><pubDate>Fri, 05 Jun 2026 09:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/05/tearing-in-concurrent-ui/</guid><description>&lt;h2 id="mental-model-one-screen-two-snapshots"&gt;Mental model: one screen, two snapshots&lt;/h2&gt;
&lt;p&gt;Tearing happens when different parts of the UI render from different versions of shared state at the same time. In a concurrent renderer, rendering can be paused, resumed, and interleaved. If an external store changes during that process and components read it unsafely, the committed screen can show an impossible combination.&lt;/p&gt;
&lt;p&gt;Imagine a header shows cart count &lt;code&gt;3&lt;/code&gt; while the checkout panel, rendered from a newer store snapshot, shows four items. Neither component is individually wrong, but the screen is inconsistent.&lt;/p&gt;</description></item><item><title>Service Discovery: Consul vs DNS</title><link>https://vabs.github.io/2026/06/02/service-discovery-consul-vs-dns/</link><pubDate>Tue, 02 Jun 2026 13:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/06/02/service-discovery-consul-vs-dns/</guid><description>&lt;h2 id="the-problem-service-discovery-solves"&gt;The problem service discovery solves&lt;/h2&gt;
&lt;p&gt;In a static world, service &lt;code&gt;A&lt;/code&gt; calls service &lt;code&gt;B&lt;/code&gt; at a hardcoded IP and port. In a dynamic world — autoscaling groups, container orchestrators, rolling deploys, spot-instance churn — &lt;code&gt;B&lt;/code&gt;&amp;rsquo;s instances appear and disappear constantly, and their addresses change. Service discovery is the mechanism by which &lt;code&gt;A&lt;/code&gt; finds a current, healthy instance of &lt;code&gt;B&lt;/code&gt; without anyone editing config.&lt;/p&gt;
&lt;p&gt;Every solution must answer three questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Registration&lt;/strong&gt; — how does a new instance announce itself?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lookup&lt;/strong&gt; — how does a caller find available instances?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Health&lt;/strong&gt; — how do dead instances get removed before callers hit them?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DNS-based discovery and Consul represent two ends of a spectrum. DNS leans on a protocol every machine already speaks; Consul is a purpose-built registry with rich health and metadata. Understanding their trade-offs is mostly about understanding what each one &lt;em&gt;cannot&lt;/em&gt; do well.&lt;/p&gt;</description></item><item><title>Blue-Green vs Canary Deployments</title><link>https://vabs.github.io/2026/05/31/blue-green-vs-canary-deployments/</link><pubDate>Sun, 31 May 2026 15:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/31/blue-green-vs-canary-deployments/</guid><description>&lt;h2 id="two-answers-to-one-question"&gt;Two answers to one question&lt;/h2&gt;
&lt;p&gt;Every deployment strategy is an answer to the same question: how do you replace running version N with version N+1 without breaking the users hitting your service right now? The naive answer — stop the old, start the new — causes downtime and an all-or-nothing blast radius. Blue-green and canary are the two dominant disciplined alternatives, and they make opposite bets about how to manage risk.&lt;/p&gt;</description></item><item><title>Virtual Memory and Page Faults Impact</title><link>https://vabs.github.io/2026/05/28/virtual-memory-and-page-faults-impact/</link><pubDate>Thu, 28 May 2026 16:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/28/virtual-memory-and-page-faults-impact/</guid><description>&lt;h2 id="the-abstraction-every-process-lives-inside"&gt;The abstraction every process lives inside&lt;/h2&gt;
&lt;p&gt;Every process on a modern OS runs inside a private virtual address space. The pointers your program dereferences are virtual addresses; they do not correspond directly to physical RAM. A hardware unit called the MMU, driven by per-process page tables, translates virtual addresses to physical ones at the granularity of a &lt;strong&gt;page&lt;/strong&gt; — typically 4 KiB on x86-64.&lt;/p&gt;
&lt;p&gt;This indirection buys a lot: isolation between processes, the ability to over-commit memory, demand paging, copy-on-write, memory-mapped files, and shared libraries that exist once in physical RAM but appear in many address spaces. The cost is that every memory access is potentially a translation, and sometimes that translation reveals the page is not actually resident. That event is a &lt;strong&gt;page fault&lt;/strong&gt;, and understanding its flavors is the key to reasoning about backend performance.&lt;/p&gt;</description></item><item><title>Container Runtime Security: seccomp and AppArmor</title><link>https://vabs.github.io/2026/05/25/container-runtime-security-seccomp-apparmor/</link><pubDate>Mon, 25 May 2026 11:20:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/25/container-runtime-security-seccomp-apparmor/</guid><description>&lt;h2 id="containers-are-not-a-security-boundary-by-default"&gt;Containers are not a security boundary by default&lt;/h2&gt;
&lt;p&gt;A container is not a virtual machine. It is a normal Linux process whose view of the system has been narrowed by namespaces (what it can &lt;em&gt;see&lt;/em&gt;) and cgroups (what it can &lt;em&gt;use&lt;/em&gt;). Crucially, every process in every container talks to the &lt;strong&gt;same host kernel&lt;/strong&gt;. A single exploitable kernel bug reachable through a syscall is a path out of the container.&lt;/p&gt;
&lt;p&gt;That shared kernel is why runtime security matters. Namespaces isolate resources; they do not reduce the kernel&amp;rsquo;s attack surface. The two mechanisms that actually shrink what a container can ask the kernel to do are &lt;strong&gt;seccomp&lt;/strong&gt; (filters which syscalls are allowed) and &lt;strong&gt;Linux Security Modules&lt;/strong&gt; like &lt;strong&gt;AppArmor&lt;/strong&gt; and SELinux (mediate what resources those syscalls may touch). They operate at different layers and are most effective together.&lt;/p&gt;</description></item><item><title>Consistent Hashing for Load Balancing</title><link>https://vabs.github.io/2026/05/22/consistent-hashing-for-load-balancing/</link><pubDate>Fri, 22 May 2026 10:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/22/consistent-hashing-for-load-balancing/</guid><description>&lt;h2 id="why-naive-hashing-breaks-under-scaling"&gt;Why naive hashing breaks under scaling&lt;/h2&gt;
&lt;p&gt;The simplest way to distribute keys across a set of &lt;code&gt;N&lt;/code&gt; backend nodes is modulo hashing: pick a node with &lt;code&gt;hash(key) % N&lt;/code&gt;. It is fast, stateless, and uniform when the hash function is good. The problem appears the moment &lt;code&gt;N&lt;/code&gt; changes.&lt;/p&gt;
&lt;p&gt;When you add or remove a single node, the divisor in &lt;code&gt;hash(key) % N&lt;/code&gt; changes for every key. The mapping is recomputed globally, and the fraction of keys that move is roughly &lt;code&gt;(N-1)/N&lt;/code&gt; — almost all of them. For a cache layer this means a near-total cache miss storm; for a sharded database it means a massive rebalancing operation; for sticky sessions it means most users get bounced to a different server.&lt;/p&gt;</description></item><item><title>Sidecar Pattern Limitations</title><link>https://vabs.github.io/2026/05/21/sidecar-pattern-limitations/</link><pubDate>Thu, 21 May 2026 09:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/21/sidecar-pattern-limitations/</guid><description>&lt;h2 id="what-the-sidecar-promises"&gt;What the sidecar promises&lt;/h2&gt;
&lt;p&gt;The sidecar pattern attaches a helper container to a primary application container, sharing the same lifecycle, network namespace, and often storage. The helper handles cross-cutting concerns — TLS termination, retries, metrics, log shipping, secrets injection — so the application can stay ignorant of them. A service mesh like Istio or Linkerd is the most prominent example: every pod gets a proxy sidecar that intercepts all traffic.&lt;/p&gt;</description></item><item><title>Lock-Free Data Structures</title><link>https://vabs.github.io/2026/05/18/lock-free-data-structures/</link><pubDate>Mon, 18 May 2026 13:27:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/18/lock-free-data-structures/</guid><description>&lt;h2 id="what-lock-free-actually-means"&gt;What lock-free actually means&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Lock-free&amp;rdquo; is one of the most abused terms in concurrent programming. It does not mean &amp;ldquo;no locks in the code,&amp;rdquo; and it does not mean &amp;ldquo;fast.&amp;rdquo; It is a precise progress guarantee: a data structure is lock-free if, at any point, &lt;em&gt;at least one&lt;/em&gt; thread is guaranteed to make progress in a finite number of steps, regardless of what other threads do, even if some of them are suspended mid-operation.&lt;/p&gt;</description></item><item><title>Browser compositing layers</title><link>https://vabs.github.io/2026/05/15/browser-compositing-layers/</link><pubDate>Fri, 15 May 2026 12:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/15/browser-compositing-layers/</guid><description>&lt;h2 id="layers-are-an-implementation-strategy"&gt;Layers are an implementation strategy&lt;/h2&gt;
&lt;p&gt;A browser compositing layer is a rendered surface that can be moved, clipped, transformed, blended, and assembled with other surfaces. Layers let the compositor update parts of the screen without repainting the entire page. They are essential for video, canvas, transforms, opacity animations, fixed elements, and complex scrolling.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 DOM["DOM tree"] --&gt; Render["render tree"]
 Render --&gt; Paint["paint chunks/display lists"]
 Paint --&gt; Layerize["layerization heuristics"]
 Layerize --&gt; L1["layer texture: header"]
 Layerize --&gt; L2["layer texture: content tiles"]
 Layerize --&gt; L3["layer texture: modal"]
 L1 --&gt; Composite["compositor frame"]
 L2 --&gt; Composite
 L3 --&gt; Composite

&lt;/pre&gt;

&lt;p&gt;A layer is not the same as a DOM element and not the same as a stacking context, though they are related. The engine groups paint chunks into composited surfaces based on correctness and performance heuristics.&lt;/p&gt;</description></item><item><title>Syscall Overhead and Context Switching</title><link>https://vabs.github.io/2026/05/15/syscall-overhead-and-context-switching/</link><pubDate>Fri, 15 May 2026 11:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/15/syscall-overhead-and-context-switching/</guid><description>&lt;h2 id="the-hidden-tax-on-every-system-call"&gt;The hidden tax on every system call&lt;/h2&gt;
&lt;p&gt;A system call looks like an ordinary function call in your code, but it is anything but. Crossing the boundary from user space into the kernel is one of the more expensive operations a CPU performs in the course of normal work, and a context switch between threads is more expensive still. When you&amp;rsquo;re chasing tail latency or trying to squeeze throughput out of a hot path, these costs stop being abstract and start showing up in flame graphs.&lt;/p&gt;</description></item><item><title>Bloom Filters and HyperLogLog in Practice</title><link>https://vabs.github.io/2026/05/13/bloom-filters-and-hyperloglog-in-practice/</link><pubDate>Wed, 13 May 2026 10:51:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/13/bloom-filters-and-hyperloglog-in-practice/</guid><description>&lt;h2 id="trading-exactness-for-scale"&gt;Trading exactness for scale&lt;/h2&gt;
&lt;p&gt;Some questions are cheap to answer approximately and ruinously expensive to answer exactly. &amp;ldquo;Have I seen this item before?&amp;rdquo; and &amp;ldquo;How many distinct items have I seen?&amp;rdquo; are two of them. Answer them exactly and you store every item, which costs memory proportional to the data. Answer them approximately and you can use a fixed, tiny amount of memory regardless of scale, accepting a controlled, quantifiable error.&lt;/p&gt;</description></item><item><title>Scheduler priorities</title><link>https://vabs.github.io/2026/05/12/scheduler-priorities/</link><pubDate>Tue, 12 May 2026 16:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/12/scheduler-priorities/</guid><description>&lt;h2 id="mental-model-not-all-ui-work-deserves-the-same-lane"&gt;Mental model: not all UI work deserves the same lane&lt;/h2&gt;
&lt;p&gt;Scheduler priorities let a renderer decide which work should run now, which work can wait, and which work should be interrupted. The browser has one main thread for JavaScript, style, layout, paint coordination, and input handling. If a large render monopolizes that thread, a keystroke waits behind work the user may no longer care about.&lt;/p&gt;
&lt;p&gt;Concurrent UI systems treat rendering as interruptible work. Typing, clicking, and focus updates should outrank background list filtering, tab preloads, or offscreen rendering. The goal is not to make total work disappear; it is to keep the user-facing work responsive.&lt;/p&gt;</description></item><item><title>epoll and kqueue Internals</title><link>https://vabs.github.io/2026/05/12/epoll-kqueue-internals/</link><pubDate>Tue, 12 May 2026 14:18:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/12/epoll-kqueue-internals/</guid><description>&lt;h2 id="the-problem-they-solve"&gt;The problem they solve&lt;/h2&gt;
&lt;p&gt;A server that handles thousands of concurrent connections faces a deceptively simple question: which sockets are ready for I/O right now? The naive answers don&amp;rsquo;t scale. Spawning a thread per connection drowns the scheduler. Polling each socket in a loop wastes the CPU. The classic readiness syscalls, &lt;code&gt;select&lt;/code&gt; and &lt;code&gt;poll&lt;/code&gt;, scale linearly with the number of watched descriptors, which collapses under load.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;epoll&lt;/code&gt; on Linux and &lt;code&gt;kqueue&lt;/code&gt; on the BSDs (including macOS) are the scalable answers. Both deliver O(1) readiness notification with respect to the number of &lt;em&gt;idle&lt;/em&gt; connections, which is exactly the property you need for the C10K problem and beyond. Understanding how they work internally explains why they&amp;rsquo;re fast, why edge-triggered mode is tricky, and how to avoid the subtle bugs that bite event-loop authors.&lt;/p&gt;</description></item><item><title>Memory Barriers and CPU Cache Coherence</title><link>https://vabs.github.io/2026/05/09/memory-barriers-and-cpu-cache-coherence/</link><pubDate>Sat, 09 May 2026 16:33:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/09/memory-barriers-and-cpu-cache-coherence/</guid><description>&lt;h2 id="when-the-hardware-lies-to-you"&gt;When the hardware lies to you&lt;/h2&gt;
&lt;p&gt;You write code that stores to one variable and then another. You assume the rest of the system sees those stores happen in that order. On a single thread, the CPU guarantees this illusion. Across threads on different cores, the guarantee evaporates. The store you issued first might become visible to another core &lt;em&gt;after&lt;/em&gt; the store you issued second. Your program is correct as written and broken as executed.&lt;/p&gt;</description></item><item><title>Zero-Copy Networking with sendfile</title><link>https://vabs.github.io/2026/05/08/zero-copy-networking-sendfile/</link><pubDate>Fri, 08 May 2026 09:42:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/08/zero-copy-networking-sendfile/</guid><description>&lt;h2 id="why-copies-are-the-enemy"&gt;Why copies are the enemy&lt;/h2&gt;
&lt;p&gt;When a server streams a file to a socket, the naive approach involves a surprising amount of data movement. The bytes don&amp;rsquo;t travel from disk to network card in a straight line. They bounce through kernel buffers and user-space buffers, get copied multiple times, and force several transitions between user mode and kernel mode. Each copy burns CPU cycles, pollutes the cache, and consumes memory bandwidth that could be doing useful work.&lt;/p&gt;</description></item><item><title>Tree shaking internals</title><link>https://vabs.github.io/2026/05/06/tree-shaking-internals/</link><pubDate>Wed, 06 May 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/06/tree-shaking-internals/</guid><description>&lt;p&gt;Tree shaking is dead-code elimination for module graphs. The bundler starts from entry points, follows imports, marks used exports, and drops code it can prove is unused. The phrase sounds simple, but the result depends on module syntax, side effects, package metadata, and how confidently the bundler can reason about execution.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 Entry[entry module] --&gt; ImportA[import used fn]
 Entry --&gt; ImportB[import component]
 Lib[library module] --&gt; Used[used export]
 Lib --&gt; Unused[unused export]
 ImportA --&gt; Used
 Unused -. dropped if safe .-&gt; Output[final bundle]
 Used --&gt; Output
 ImportB --&gt; Output

&lt;/pre&gt;

&lt;h2 id="why-esm-matters"&gt;Why ESM matters&lt;/h2&gt;
&lt;p&gt;ES modules have static structure. &lt;code&gt;import { format } from &amp;quot;./date.js&amp;quot;&lt;/code&gt; can be analyzed without running the program. CommonJS is dynamic: &lt;code&gt;require()&lt;/code&gt; can be conditional, computed, or mixed with runtime mutation. Bundlers can optimize some CommonJS, but ESM gives them much stronger guarantees.&lt;/p&gt;</description></item><item><title>Protobuf vs JSON: Performance Trade-offs</title><link>https://vabs.github.io/2026/05/05/protobuf-vs-json-performance-trade-offs/</link><pubDate>Tue, 05 May 2026 13:36:19 -0400</pubDate><guid>https://vabs.github.io/2026/05/05/protobuf-vs-json-performance-trade-offs/</guid><description>&lt;h2 id="picking-a-serialization-format-is-an-architectural-decision"&gt;Picking a Serialization Format Is an Architectural Decision&lt;/h2&gt;
&lt;p&gt;Every distributed system has to turn in-memory objects into bytes and back — for network calls, queues, caches, and persistence. The format you choose quietly determines your wire size, CPU cost, schema discipline, and debuggability for the life of the system. The two most common choices sit at opposite ends of a spectrum: &lt;strong&gt;JSON&lt;/strong&gt;, a text format optimized for human readability and ubiquity, and &lt;strong&gt;Protocol Buffers (Protobuf)&lt;/strong&gt;, a binary format optimized for size and speed.&lt;/p&gt;</description></item><item><title>Offline conflict resolution</title><link>https://vabs.github.io/2026/05/02/offline-conflict-resolution/</link><pubDate>Sat, 02 May 2026 12:45:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/02/offline-conflict-resolution/</guid><description>&lt;p&gt;Offline conflict resolution is the set of rules that decides what happens when users make changes without a live connection and those changes meet other changes later. The hard part is not detecting that two writes happened. The hard part is choosing domain-correct semantics: should edits merge, should one win, should the user decide, or should the system create a new version?&lt;/p&gt;
&lt;p&gt;The mental model is that offline-first applications have at least two logs: local intent and remote truth. While offline, the app records local operations. On reconnect, it exchanges state with the server, rebases or merges local operations, resolves conflicts, and updates the UI without pretending that every conflict is an error.&lt;/p&gt;</description></item><item><title>API Contract Testing with Pact and Spring Cloud Contract</title><link>https://vabs.github.io/2026/05/02/api-contract-testing-pact-spring-cloud-contract/</link><pubDate>Sat, 02 May 2026 11:27:48 -0400</pubDate><guid>https://vabs.github.io/2026/05/02/api-contract-testing-pact-spring-cloud-contract/</guid><description>&lt;h2 id="the-integration-testing-gap"&gt;The Integration Testing Gap&lt;/h2&gt;
&lt;p&gt;You have two services: a &lt;code&gt;consumer&lt;/code&gt; (say, a web BFF) and a &lt;code&gt;provider&lt;/code&gt; (an &lt;code&gt;orders&lt;/code&gt; API). How do you guarantee they actually work together? The traditional answer is &lt;strong&gt;end-to-end integration tests&lt;/strong&gt;: spin up both services, plus their databases, plus their dependencies, and exercise real requests. This works until it doesn&amp;rsquo;t. E2E suites are slow, flaky, expensive to maintain, and they scale combinatorially badly. With &lt;code&gt;N&lt;/code&gt; services, the number of integration paths explodes, and a single deployment can require coordinating the whole graph.&lt;/p&gt;</description></item><item><title>Virtual DOM diffing complexity</title><link>https://vabs.github.io/2026/05/02/virtual-dom-diffing-complexity/</link><pubDate>Sat, 02 May 2026 09:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/02/virtual-dom-diffing-complexity/</guid><description>&lt;p&gt;Virtual DOM diffing compares a previous tree of UI descriptions with a next tree and computes the host operations needed to update the real UI. The important performance detail is that frameworks do not solve the general tree-edit-distance problem. A fully general diff is too expensive for interactive rendering. Instead, frameworks use heuristics based on element type, position, and keys.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Previous virtual tree] --&gt; C[Diff]
 B[Next virtual tree] --&gt; C
 C --&gt; D{Same type and key?}
 D --&gt;|yes| E[Update props and children]
 D --&gt;|no| F[Replace subtree]
 E --&gt; G[Commit host operations]
 F --&gt; G

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;A virtual node is a description: type, props, key, and children. During diffing, the renderer asks whether an old node can be reused for a new node. If type and key match, it can update props and continue into children. If they do not match, the old subtree is removed and the new subtree is mounted.&lt;/p&gt;</description></item><item><title>Paint vs composite vs layout</title><link>https://vabs.github.io/2026/05/01/paint-vs-composite-vs-layout/</link><pubDate>Fri, 01 May 2026 09:45:00 -0400</pubDate><guid>https://vabs.github.io/2026/05/01/paint-vs-composite-vs-layout/</guid><description>&lt;h2 id="rendering-work-has-different-prices"&gt;Rendering work has different prices&lt;/h2&gt;
&lt;p&gt;When a page changes, the browser does not perform one generic &amp;ldquo;render&amp;rdquo; step. It may recalculate style, run layout, paint pixels, raster tiles, and composite layers. Performance work becomes much clearer when you can identify which stage your change invalidates.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 JS["JS or CSS change"] --&gt; Style["style recalculation"]
 Style --&gt; Layout["layout: compute geometry"]
 Layout --&gt; Paint["paint: record drawing commands"]
 Paint --&gt; Raster["raster: pixels/tiles"]
 Raster --&gt; Composite["composite: assemble layers"]
 Composite --&gt; Screen["display"]
 JS --&gt; CompositeOnly["transform/opacity change"] --&gt; Composite

&lt;/pre&gt;

&lt;p&gt;Layout determines boxes. Paint determines what those boxes look like. Compositing assembles already-rasterized layers onto the screen.&lt;/p&gt;</description></item><item><title>Binary Protocol Parsing</title><link>https://vabs.github.io/2026/04/30/binary-protocol-parsing/</link><pubDate>Thu, 30 Apr 2026 10:51:27 -0400</pubDate><guid>https://vabs.github.io/2026/04/30/binary-protocol-parsing/</guid><description>&lt;h2 id="when-text-is-not-enough"&gt;When Text Is Not Enough&lt;/h2&gt;
&lt;p&gt;Most application developers spend their careers parsing text: JSON bodies, HTTP headers, CSV files. But underneath all of that runs a layer of &lt;strong&gt;binary protocols&lt;/strong&gt; — formats where meaning is encoded in the exact arrangement of bytes rather than human-readable characters. TCP/IP headers, TLS records, MySQL&amp;rsquo;s wire protocol, Kafka&amp;rsquo;s protocol, Redis&amp;rsquo;s RESP, MessagePack, and Protobuf are all binary. If you build network servers, parsers, or high-throughput data pipelines, you eventually have to read bytes directly.&lt;/p&gt;</description></item><item><title>Microservices Observability: Distributed Tracing</title><link>https://vabs.github.io/2026/04/28/microservices-observability-distributed-tracing/</link><pubDate>Tue, 28 Apr 2026 15:42:11 -0400</pubDate><guid>https://vabs.github.io/2026/04/28/microservices-observability-distributed-tracing/</guid><description>&lt;h2 id="the-problem-with-logs-in-a-microservice-world"&gt;The Problem With Logs in a Microservice World&lt;/h2&gt;
&lt;p&gt;In a monolith, a single request executes inside one process. When something goes wrong you grep one log file, follow the stack trace, and you are done. Decompose that monolith into thirty services and a single user click might fan out across a dozen processes, three message queues, and two databases. The log lines for that one request are now scattered across a dozen machines, interleaved with thousands of other requests, with no thread of continuity between them.&lt;/p&gt;</description></item><item><title>Render waterfalls</title><link>https://vabs.github.io/2026/04/28/render-waterfalls/</link><pubDate>Tue, 28 Apr 2026 09:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/28/render-waterfalls/</guid><description>&lt;h2 id="mental-model-sequential-work-hiding-in-a-tree"&gt;Mental model: sequential work hiding in a tree&lt;/h2&gt;
&lt;p&gt;A render waterfall happens when work that could have run in parallel is discovered sequentially during rendering. Component A renders, starts a fetch, waits, then renders child B, which starts another fetch, waits, then renders child C. The UI may look componentized, but the latency graph is a linked list.&lt;/p&gt;
&lt;p&gt;Waterfalls are not limited to network requests. Code splitting, image discovery, font loading, server component fetches, client effects, and even permissions checks can all create sequential dependency chains. The important signal is not &amp;ldquo;many things loaded&amp;rdquo;; it is &amp;ldquo;the next thing could not even be discovered until the previous thing finished.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Code splitting strategies</title><link>https://vabs.github.io/2026/04/25/code-splitting-strategies/</link><pubDate>Sat, 25 Apr 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/25/code-splitting-strategies/</guid><description>&lt;p&gt;Code splitting is a budgeting tool. The question is not &amp;ldquo;can this code be split?&amp;rdquo; but &amp;ldquo;which users need this code, at what moment, and what latency can they tolerate?&amp;rdquo; A good strategy reduces initial work without turning every interaction into a loading spinner. It is a distribution problem, not a bundler checkbox.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart LR
 App[Application code] --&gt; Critical[critical path]
 App --&gt; Route[route chunks]
 App --&gt; Feature[feature chunks]
 App --&gt; Vendor[vendor chunks]
 App --&gt; Background[background/prefetch]
 Critical --&gt; FCP[fast first interaction]

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;JavaScript cost has multiple parts: download, decompression, parse, compile, and execution. On modern sites, parse and execution can dominate for mid-range devices. Splitting helps when it removes work from the critical path. It does not help if the split code is immediately requested during startup.&lt;/p&gt;</description></item><item><title>Database Failover and Split-Brain Prevention</title><link>https://vabs.github.io/2026/04/24/database-failover-and-split-brain-prevention/</link><pubDate>Fri, 24 Apr 2026 09:14:32 -0400</pubDate><guid>https://vabs.github.io/2026/04/24/database-failover-and-split-brain-prevention/</guid><description>&lt;h2 id="why-failover-is-harder-than-it-looks"&gt;Why Failover Is Harder Than It Looks&lt;/h2&gt;
&lt;p&gt;A database failover sounds simple: the primary dies, a replica takes over, traffic resumes. In practice, the operation sits squarely in the middle of one of distributed computing&amp;rsquo;s nastiest problems. You cannot reliably distinguish a &lt;em&gt;crashed&lt;/em&gt; node from a &lt;em&gt;slow&lt;/em&gt; or &lt;em&gt;partitioned&lt;/em&gt; node. A primary that stopped responding might be dead, or it might be alive on the other side of a network partition still accepting writes. Promote a replica in that second case and you now have two primaries. That condition is called &lt;strong&gt;split-brain&lt;/strong&gt;, and it is the single most dangerous outcome in any high-availability database topology.&lt;/p&gt;</description></item><item><title>Backward-Compatible Schema Evolution</title><link>https://vabs.github.io/2026/04/23/backward-compatible-schema-evolution/</link><pubDate>Thu, 23 Apr 2026 17:08:55 -0400</pubDate><guid>https://vabs.github.io/2026/04/23/backward-compatible-schema-evolution/</guid><description>&lt;h2 id="why-schema-change-is-the-hard-part-of-backend-work"&gt;Why Schema Change Is the Hard Part of Backend Work&lt;/h2&gt;
&lt;p&gt;Writing the first version of a schema is easy. Changing it after millions of rows exist, multiple service versions are deployed, and downtime is unacceptable — that is where backend engineering earns its keep. A careless &lt;code&gt;ALTER TABLE&lt;/code&gt; can lock a table for minutes, an incompatible column rename can crash every running instance of the old code, and a dropped field can silently corrupt a consumer three services away.&lt;/p&gt;</description></item><item><title>Chaos Engineering Principles</title><link>https://vabs.github.io/2026/04/22/chaos-engineering-principles/</link><pubDate>Wed, 22 Apr 2026 09:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/22/chaos-engineering-principles/</guid><description>&lt;p&gt;A distributed system that has never been deliberately broken is a system whose failure behavior is purely theoretical. You wrote retries, timeouts, and fallbacks; you wrote them assuming a model of how dependencies fail; and that model is almost certainly wrong in ways you will only discover at 3 a.m. during a real outage. Chaos engineering inverts this: instead of waiting for production to reveal its weaknesses, you inject controlled failures and find them on your own schedule, with the lights on. This post lays out the discipline — its principles, its experimental method, and how to run it without becoming the outage you were trying to prevent.&lt;/p&gt;</description></item><item><title>Paxos / Raft Consensus Internals</title><link>https://vabs.github.io/2026/04/20/paxos-raft-consensus-internals/</link><pubDate>Mon, 20 Apr 2026 11:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/20/paxos-raft-consensus-internals/</guid><description>&lt;p&gt;Consensus is the problem of getting a group of unreliable machines to agree on a single value — and to keep agreeing even as some of them crash, restart, and rejoin. It is the foundation under replicated databases, configuration stores like etcd and ZooKeeper, and leader election everywhere. Two algorithms dominate the conversation: Paxos, the theoretical bedrock, and Raft, the version designed to actually be understandable. This post walks through what they guarantee, how each one works mechanically, and why Raft replaced Paxos in most engineers&amp;rsquo; heads.&lt;/p&gt;</description></item><item><title>First Input Delay (FID)</title><link>https://vabs.github.io/2026/04/19/first-input-delay-fid/</link><pubDate>Sun, 19 Apr 2026 09:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/19/first-input-delay-fid/</guid><description>&lt;p&gt;First Input Delay measures the delay between a user&amp;rsquo;s first interaction and the browser&amp;rsquo;s ability to start running the corresponding event handler. It focuses on input delay, not handler execution or paint. Even though Interaction to Next Paint is now the broader responsiveness metric, FID remains a useful concept because the first interaction is often where users discover that a page only looked ready.&lt;/p&gt;
&lt;p&gt;The mental model: FID is main-thread availability at the moment of first input. If JavaScript parsing, execution, hydration, style work, or a third-party script owns the main thread, the browser queues the input until that task finishes.&lt;/p&gt;</description></item><item><title>Structural sharing</title><link>https://vabs.github.io/2026/04/18/structural-sharing/</link><pubDate>Sat, 18 Apr 2026 10:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/18/structural-sharing/</guid><description>&lt;p&gt;Structural sharing is the technique of creating a new version of a data structure by copying only the parts that changed and reusing the rest. It is the performance backbone of practical immutability. Without structural sharing, immutable updates would require copying entire trees, arrays, or maps for every small change.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Old root] --&gt; B[Old left branch]
 A --&gt; C[Old right branch]
 C --&gt; F[Old leaf]
 D[New root] --&gt; B
 D --&gt; E[New right branch]
 E --&gt; G[New changed leaf]

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Imagine state as a graph of references. An update creates a new path from the root to the changed leaf. Nodes outside that path are reused. Consumers comparing references can quickly know whether their branch changed. Old versions remain usable because reused nodes are not mutated.&lt;/p&gt;</description></item><item><title>CRDT basics for collaboration</title><link>https://vabs.github.io/2026/04/18/crdt-basics-for-collaboration/</link><pubDate>Sat, 18 Apr 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/18/crdt-basics-for-collaboration/</guid><description>&lt;p&gt;CRDTs are data structures designed so replicas can accept local changes independently, exchange updates later, and converge without a central conflict resolver. In frontend collaboration, that means a user can type, move a card, toggle a checkbox, or edit metadata while disconnected, then sync with other clients without losing concurrent work. The tradeoff is that the conflict policy moves into the data type itself.&lt;/p&gt;
&lt;p&gt;The mental model is convergence by construction. A CRDT does not avoid conflicts by preventing concurrent edits. It defines merge behavior so concurrent edits have deterministic meaning.&lt;/p&gt;</description></item><item><title>Byzantine Fault Tolerance Basics</title><link>https://vabs.github.io/2026/04/17/byzantine-fault-tolerance-basics/</link><pubDate>Fri, 17 Apr 2026 13:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/17/byzantine-fault-tolerance-basics/</guid><description>&lt;p&gt;Most distributed systems assume failures are honest: a node either works correctly or it crashes and stops. Byzantine fault tolerance throws out that comfortable assumption. A Byzantine node can do anything — send different messages to different peers, lie about its state, forge data, collude with other bad nodes, or simply behave arbitrarily because of a bug, a memory corruption, or an attacker. Tolerating that is dramatically harder than tolerating a crash, and the math reflects it. This post explains where the famous &lt;code&gt;3f + 1&lt;/code&gt; bound comes from, how PBFT achieves agreement, and when this expensive machinery is actually worth it.&lt;/p&gt;</description></item><item><title>GPU acceleration in CSS</title><link>https://vabs.github.io/2026/04/16/gpu-acceleration-in-css/</link><pubDate>Thu, 16 Apr 2026 15:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/16/gpu-acceleration-in-css/</guid><description>&lt;h2 id="the-gpu-is-not-a-magic-fast-path"&gt;The GPU is not a magic fast path&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Use GPU acceleration&amp;rdquo; usually means &amp;ldquo;make the browser animate by compositing existing layers instead of repainting pixels on the CPU.&amp;rdquo; The GPU is good at moving textured rectangles, blending opacity, and applying transforms. It is not a general cure for expensive layout, slow JavaScript, huge paints, or memory pressure.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart LR
 DOM["DOM/CSS changes"] --&gt; Layout["layout"]
 Layout --&gt; Paint["paint display lists"]
 Paint --&gt; Raster["raster tiles"]
 Raster --&gt; Layers["GPU textures/layers"]
 Layers --&gt; Composite["transform/opacity compositing"]
 Composite --&gt; Screen["screen"]

&lt;/pre&gt;

&lt;p&gt;The key distinction: animating &lt;code&gt;transform&lt;/code&gt; or &lt;code&gt;opacity&lt;/code&gt; can often skip layout and paint after the layer has been rasterized. Animating &lt;code&gt;width&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;box-shadow&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, or &lt;code&gt;background-position&lt;/code&gt; may require layout or paint every frame.&lt;/p&gt;</description></item><item><title>Hydration</title><link>https://vabs.github.io/2026/04/16/hydration/</link><pubDate>Thu, 16 Apr 2026 10:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/16/hydration/</guid><description>&lt;h2 id="mental-model-make-server-html-interactive-without-replacing-it"&gt;Mental model: make server HTML interactive without replacing it&lt;/h2&gt;
&lt;p&gt;Hydration is the client-side process that takes server-rendered HTML and attaches the JavaScript component model to it. The browser already has DOM nodes on screen. The framework recreates enough of the component tree to connect state, event handlers, refs, and effects to those existing nodes.&lt;/p&gt;
&lt;p&gt;The key constraint is that the client render must agree with the server output. If the first client render produces different markup, the framework may warn, patch, discard nodes, or remount a subtree. Hydration is fastest and safest when the server and client produce the same initial tree.&lt;/p&gt;</description></item><item><title>Idempotency Keys in API Design</title><link>https://vabs.github.io/2026/04/15/idempotency-keys-in-api-design/</link><pubDate>Wed, 15 Apr 2026 10:45:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/15/idempotency-keys-in-api-design/</guid><description>&lt;p&gt;Networks fail in the most inconvenient way possible: not by losing the request, but by losing the &lt;em&gt;response&lt;/em&gt;. The client sends &amp;ldquo;charge this card $50,&amp;rdquo; the server charges it, and then the acknowledgment vanishes into a dropped connection. The client, seeing no answer, retries. Without protection, the customer is charged twice. Idempotency keys are the standard, battle-tested mechanism for making &amp;ldquo;retry safely&amp;rdquo; a first-class property of your API. This post covers what they guarantee, how to implement them correctly, and the subtle failure modes that trip up most first attempts.&lt;/p&gt;</description></item><item><title>Suspense boundaries</title><link>https://vabs.github.io/2026/04/14/suspense-boundaries/</link><pubDate>Tue, 14 Apr 2026 14:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/14/suspense-boundaries/</guid><description>&lt;h2 id="mental-model-a-boundary-is-a-latency-contract"&gt;Mental model: a boundary is a latency contract&lt;/h2&gt;
&lt;p&gt;A Suspense boundary defines what part of the UI may wait and what the user sees while it waits. It is not just a spinner wrapper. It is a latency contract between rendering, data fetching, code loading, and user perception.&lt;/p&gt;
&lt;p&gt;Good boundaries preserve the page&amp;rsquo;s structure while slow regions resolve. Bad boundaries blank out too much UI, flicker on fast requests, or hide the source of slowness behind generic loading states.&lt;/p&gt;</description></item><item><title>Dynamic import chunking</title><link>https://vabs.github.io/2026/04/14/dynamic-import-chunking/</link><pubDate>Tue, 14 Apr 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/14/dynamic-import-chunking/</guid><description>&lt;p&gt;Dynamic &lt;code&gt;import()&lt;/code&gt; is both a language feature and a bundler signal. In application code it means &amp;ldquo;load this module asynchronously.&amp;rdquo; In a bundled frontend it usually means &amp;ldquo;create a separate chunk boundary here.&amp;rdquo; Used well, it keeps initial JavaScript small and delays rarely used code. Used casually, it creates a waterfall of tiny chunks that slow down real navigation.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 Entry[entry chunk] --&gt; Router[router]
 Router --&gt;|import()| Admin[admin chunk]
 Router --&gt;|import()| Editor[editor chunk]
 Editor --&gt;|import()| Markdown[markdown parser chunk]
 Editor --&gt;|import()| Syntax[syntax highlighter chunk]

&lt;/pre&gt;

&lt;h2 id="internals-that-matter"&gt;Internals that matter&lt;/h2&gt;
&lt;p&gt;Bundlers build a module graph. Static imports become part of the synchronous graph for an entry point. Dynamic imports become async edges. The bundler emits a runtime loader that fetches the referenced chunk when execution reaches that import.&lt;/p&gt;</description></item><item><title>Cache invalidation strategies</title><link>https://vabs.github.io/2026/04/13/cache-invalidation-strategies/</link><pubDate>Mon, 13 Apr 2026 14:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/13/cache-invalidation-strategies/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Cache invalidation is the discipline of making cached data stop being used when it no longer matches the source of truth. The hard part is not deleting entries; it is knowing which entries are affected, how quickly they must disappear, and what happens while different layers disagree.&lt;/p&gt;
&lt;p&gt;Frontend systems usually have several caches at once: browser HTTP cache, service worker cache, CDN cache, in-memory data library cache, normalized entity cache, and sometimes local storage or IndexedDB. A mutation may need to update more than one.&lt;/p&gt;</description></item><item><title>Eventual Consistency in Cache</title><link>https://vabs.github.io/2026/04/11/eventual-consistency-in-cache/</link><pubDate>Sat, 11 Apr 2026 14:20:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/11/eventual-consistency-in-cache/</guid><description>&lt;p&gt;A cache exists to answer a read faster than the source of truth can. The moment you place a copy of data somewhere other than its authoritative home, you create the possibility that the copy and the source disagree. Eventual consistency is the honest name for the contract most caches actually offer: reads may return stale data for some window, but if writes stop, all replicas converge to the same value within a bounded time. This post digs into why that window exists, how to reason about it, and how to keep it small enough that your users never notice.&lt;/p&gt;</description></item><item><title>Optimistic Locking with Version Vectors</title><link>https://vabs.github.io/2026/04/09/optimistic-locking-with-version-vectors/</link><pubDate>Thu, 09 Apr 2026 16:30:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/09/optimistic-locking-with-version-vectors/</guid><description>&lt;p&gt;Two users open the same record, both edit it, both save. Whose change wins? In a single-database world, optimistic locking with a simple version counter answers this cleanly: the second save is rejected because the row changed underneath it. But once data lives on multiple replicas that accept writes independently, a scalar version number is no longer enough to tell &amp;ldquo;this is a stale overwrite&amp;rdquo; apart from &amp;ldquo;these two edits happened concurrently on different nodes.&amp;rdquo; Version vectors are the data structure that restores that distinction. This post builds up from the single-node case to version vectors and shows exactly when and why you need them.&lt;/p&gt;</description></item><item><title>Interaction to Next Paint (INP)</title><link>https://vabs.github.io/2026/04/09/interaction-to-next-paint-inp/</link><pubDate>Thu, 09 Apr 2026 16:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/09/interaction-to-next-paint-inp/</guid><description>&lt;p&gt;Interaction to Next Paint measures page responsiveness across real user interactions. It observes clicks, taps, and keyboard interactions, then reports a high-percentile interaction latency for the page. Unlike older first-input metrics, INP cares about the whole session. A page can load quickly and still fail INP if later interactions are blocked by JavaScript, rendering, or main-thread contention.&lt;/p&gt;
&lt;p&gt;The useful mental model splits one interaction into input delay, processing duration, and presentation delay.&lt;/p&gt;</description></item><item><title>Distributed Cache Invalidation: Cache-Aside vs Write-Through</title><link>https://vabs.github.io/2026/04/07/distributed-cache-invalidation-cache-aside-vs-write-through/</link><pubDate>Tue, 07 Apr 2026 16:44:18 -0400</pubDate><guid>https://vabs.github.io/2026/04/07/distributed-cache-invalidation-cache-aside-vs-write-through/</guid><description>&lt;p&gt;There are only two hard things in computer science, the joke goes, and cache invalidation is one of them. The reason it&amp;rsquo;s hard is that a cache is a deliberate copy of data that lives somewhere else, and the moment the source of truth changes, your copy is a lie until you do something about it. The strategy you choose — cache-aside, write-through, write-behind — determines &lt;em&gt;who&lt;/em&gt; keeps the copy honest, &lt;em&gt;when&lt;/em&gt;, and &lt;em&gt;what happens&lt;/em&gt; in the window where they disagree. This post dissects the major patterns, their consistency guarantees, and the race conditions that make distributed caching genuinely treacherous.&lt;/p&gt;</description></item><item><title>Immutable data patterns</title><link>https://vabs.github.io/2026/04/07/immutable-data-patterns/</link><pubDate>Tue, 07 Apr 2026 09:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/07/immutable-data-patterns/</guid><description>&lt;p&gt;Immutable data patterns update state by creating new values instead of modifying existing values in place. The goal is not aesthetic purity. The goal is reliable change detection, predictable debugging, safe undo/redo, and fewer hidden side effects between components that share references.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Previous state] --&gt; B[Update action]
 B --&gt; C[Copy changed path]
 C --&gt; D[Reuse unchanged branches]
 D --&gt; E[Next state]
 A --&gt; F[History/debug snapshot remains valid]

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;State is a value, not a bag of objects to mutate from anywhere. An update receives the previous value and returns the next value. Consumers can compare references to know which branches changed. Old snapshots remain meaningful because later updates do not rewrite them.&lt;/p&gt;</description></item><item><title>Stale-while-revalidate</title><link>https://vabs.github.io/2026/04/06/stale-while-revalidate/</link><pubDate>Mon, 06 Apr 2026 10:10:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/06/stale-while-revalidate/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;stale-while-revalidate&lt;/code&gt; serves a cached response immediately while a refresh happens in the background. The user gets low latency, and the cache eventually catches up. It is a deliberate trade: accept bounded staleness to improve responsiveness.&lt;/p&gt;
&lt;p&gt;The pattern exists in HTTP cache directives, service workers, CDNs, and client data libraries. The same question applies everywhere: &amp;ldquo;How stale is acceptable for this resource?&amp;rdquo;&lt;/p&gt;
&lt;pre class="mermaid"&gt;

sequenceDiagram
 participant U as User
 participant C as Cache
 participant S as Server
 U-&gt;&gt;C: Request resource
 C--&gt;&gt;U: Return stale cached response immediately
 C-&gt;&gt;S: Revalidate in background
 alt changed
 S--&gt;&gt;C: 200 new body
 C-&gt;&gt;C: Update cache
 else unchanged
 S--&gt;&gt;C: 304
 C-&gt;&gt;C: Extend cached metadata
 end

&lt;/pre&gt;

&lt;h2 id="internals-that-matter"&gt;Internals that matter&lt;/h2&gt;
&lt;p&gt;HTTP expresses the pattern like this:&lt;/p&gt;</description></item><item><title>API Gateway Throttling &amp; Caching Layers</title><link>https://vabs.github.io/2026/04/05/api-gateway-throttling-and-caching-layers/</link><pubDate>Sun, 05 Apr 2026 13:21:36 -0400</pubDate><guid>https://vabs.github.io/2026/04/05/api-gateway-throttling-and-caching-layers/</guid><description>&lt;p&gt;An API gateway is the front door to your backend, and the two responsibilities that most determine whether that door holds up under load are throttling and caching. Throttling protects your services from being overwhelmed; caching prevents them from doing the same work twice. Done well, the gateway absorbs traffic that would otherwise flatten your origin. Done badly, it either lets a stampede through or serves stale, incorrect data to every client. This post examines the algorithms behind gateway throttling, where caching belongs in the request path, and how the two interact.&lt;/p&gt;</description></item><item><title>WebRTC</title><link>https://vabs.github.io/2026/04/04/webrtc/</link><pubDate>Sat, 04 Apr 2026 14:30:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/04/webrtc/</guid><description>&lt;p&gt;WebRTC is the browser stack for peer-to-peer audio, video, and data channels. The API looks like media elements and event handlers, but the system underneath includes signaling, ICE candidate gathering, NAT traversal, DTLS, SRTP, congestion control, codecs, jitter buffers, and device permissions. Practical WebRTC work is mostly about managing that state machine reliably.&lt;/p&gt;
&lt;p&gt;The first mental model: WebRTC does not define signaling. Your app must exchange offers, answers, and ICE candidates over a separate channel such as WebSocket, HTTP polling, or your realtime backend. WebRTC uses that information to establish media and data paths.&lt;/p&gt;</description></item><item><title>Module federation</title><link>https://vabs.github.io/2026/04/03/module-federation/</link><pubDate>Fri, 03 Apr 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/03/module-federation/</guid><description>&lt;p&gt;Module Federation lets one JavaScript build load modules from another build at runtime. It is often used for micro-frontends, but the underlying idea is simpler: split deployment ownership without publishing every shared piece as an npm package. A host application discovers a remote container, asks for an exposed module, and executes it with a shared dependency scope.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart LR
 Host[Host app] --&gt;|loads remoteEntry.js| Remote[Remote container]
 Host --&gt; Share[Shared scope]
 Remote --&gt; Share
 Remote --&gt; Exposed[./Widget module]
 Host --&gt;|render| Exposed

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;At build time, the remote declares which modules it exposes. The host declares remotes it may consume. At runtime, the host loads the remote entry script, initializes dependency sharing, then imports exposed modules. This means integration failures can happen after deploy even when both projects compiled successfully.&lt;/p&gt;</description></item><item><title>Service Mesh Traffic Shifting</title><link>https://vabs.github.io/2026/04/02/service-mesh-traffic-shifting/</link><pubDate>Thu, 02 Apr 2026 15:38:47 -0400</pubDate><guid>https://vabs.github.io/2026/04/02/service-mesh-traffic-shifting/</guid><description>&lt;p&gt;Traffic shifting is the capability that turns a service mesh from a fancy observability layer into a genuine deployment safety net. It lets you route a controlled fraction of requests to a new version, watch the metrics, and either ramp up or roll back — all without redeploying, without DNS changes, and without touching your application code. This post covers how traffic shifting works at the sidecar level, the difference between weight-based and request-based routing, how canary analysis automates the decision, and the failure modes that silently corrupt a rollout.&lt;/p&gt;</description></item><item><title>Partial hydration</title><link>https://vabs.github.io/2026/04/02/partial-hydration/</link><pubDate>Thu, 02 Apr 2026 14:10:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/02/partial-hydration/</guid><description>&lt;h2 id="mental-model-hydrate-less-of-what-you-already-rendered"&gt;Mental model: hydrate less of what you already rendered&lt;/h2&gt;
&lt;p&gt;Partial hydration is the practice of server-rendering a page while hydrating only the parts that need client-side behavior. The HTML can contain a full page, but the browser does not have to download, parse, execute, and attach listeners for every component that produced it.&lt;/p&gt;
&lt;p&gt;This differs from classic full-app hydration, where the client framework rebuilds a matching component tree for the whole page. Partial hydration asks a sharper question: which rendered regions actually need to become live?&lt;/p&gt;</description></item><item><title>CSS containment</title><link>https://vabs.github.io/2026/04/02/css-containment/</link><pubDate>Thu, 02 Apr 2026 10:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/02/css-containment/</guid><description>&lt;h2 id="containment-gives-the-browser-boundaries"&gt;Containment gives the browser boundaries&lt;/h2&gt;
&lt;p&gt;CSS containment lets an element promise that some of its internals do not affect the outside world. That promise helps the browser limit style recalculation, layout, paint invalidation, and size dependency. In large interfaces, containment is one of the few CSS tools that directly changes how much of the rendering tree must be reconsidered.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 Change["change inside component"] --&gt; Style["style containment limits selector effects"]
 Change --&gt; Layout["layout containment limits geometry effects"]
 Change --&gt; Paint["paint containment clips invalidation"]
 Change --&gt; Size["size containment removes intrinsic contribution"]
 Style --&gt; Faster["smaller rendering work"]
 Layout --&gt; Faster
 Paint --&gt; Faster
 Size --&gt; Faster

&lt;/pre&gt;

&lt;p&gt;The property is &lt;code&gt;contain&lt;/code&gt;, with values like &lt;code&gt;layout&lt;/code&gt;, &lt;code&gt;paint&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;content&lt;/code&gt;, and &lt;code&gt;strict&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Background Job Queues (Celery / BullMQ) Retry Semantics</title><link>https://vabs.github.io/2026/04/01/background-job-queues-celery-bullmq-retry-semantics/</link><pubDate>Wed, 01 Apr 2026 10:07:55 -0400</pubDate><guid>https://vabs.github.io/2026/04/01/background-job-queues-celery-bullmq-retry-semantics/</guid><description>&lt;p&gt;Background job queues are where the optimistic assumptions of synchronous code go to die. A job runs in a worker that can crash, against a network that can partition, talking to services that can time out. The entire value proposition of a queue is that it will &lt;em&gt;try again&lt;/em&gt; when things fail — but &amp;ldquo;try again&amp;rdquo; hides a thicket of decisions: how many times, with what delay, whether the retry might run the job twice, and what happens to jobs that never succeed. This post compares how Celery and BullMQ handle retries, the semantics you must understand to avoid corrupting data, and the patterns that keep a queue healthy under failure.&lt;/p&gt;</description></item><item><title>Selective hydration</title><link>https://vabs.github.io/2026/04/01/selective-hydration/</link><pubDate>Wed, 01 Apr 2026 10:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/04/01/selective-hydration/</guid><description>&lt;h2 id="mental-model-hydration-is-scheduling-not-just-attaching-events"&gt;Mental model: hydration is scheduling, not just attaching events&lt;/h2&gt;
&lt;p&gt;Hydration turns server-rendered HTML into an interactive client tree. Selective hydration means the browser does not hydrate the entire page with one equal-priority pass. It can prioritize the parts the user needs first, often driven by Suspense boundaries, user input, visibility, and resource readiness.&lt;/p&gt;
&lt;p&gt;This matters because SSR can improve first paint while still leaving the page unusable during a large hydration task. Selective hydration attacks that gap. The goal is not merely a pretty static page; it is a page where the first meaningful interaction is not blocked by unrelated widgets.&lt;/p&gt;</description></item><item><title>Serverless Cold-Start Mitigation</title><link>https://vabs.github.io/2026/03/29/serverless-cold-start-mitigation/</link><pubDate>Sun, 29 Mar 2026 11:52:09 -0400</pubDate><guid>https://vabs.github.io/2026/03/29/serverless-cold-start-mitigation/</guid><description>&lt;p&gt;Cold starts are the tax you pay for not running servers. The first invocation of a function that has no warm container behind it must wait for the platform to allocate compute, download your code, bootstrap the runtime, and initialize your application before a single line of handler logic executes. For a latency-sensitive API this can turn a 20ms p50 into a 2-second p99, and the worst part is that it happens unpredictably. This post breaks down exactly what a cold start consists of, which phases you can influence, and the concrete techniques that actually move the needle.&lt;/p&gt;</description></item><item><title>Cumulative Layout Shift (CLS)</title><link>https://vabs.github.io/2026/03/28/cumulative-layout-shift-cls/</link><pubDate>Sat, 28 Mar 2026 12:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/28/cumulative-layout-shift-cls/</guid><description>&lt;p&gt;Cumulative Layout Shift measures unexpected visual movement. It is not a general animation metric. It penalizes layout shifts that occur without recent user input and that move visible content. CLS is frustrating because it breaks spatial memory: the user reaches for a button, content jumps, and the click lands somewhere else.&lt;/p&gt;
&lt;p&gt;The mental model is reservation. Any content that will appear later needs space before it arrives, or it needs to appear in a layer that does not push existing content. Images, ads, embeds, banners, fonts, client-rendered widgets, and personalized modules are the usual sources.&lt;/p&gt;</description></item><item><title>Kubernetes Pod Disruption Budgets</title><link>https://vabs.github.io/2026/03/27/kubernetes-pod-disruption-budgets/</link><pubDate>Fri, 27 Mar 2026 09:14:22 -0400</pubDate><guid>https://vabs.github.io/2026/03/27/kubernetes-pod-disruption-budgets/</guid><description>&lt;p&gt;Pod Disruption Budgets (PDBs) are one of the most misunderstood reliability primitives in Kubernetes. They sit quietly in your manifests until the day a node drain takes down half your fleet, and only then do most teams discover what they were supposed to be protecting against. This post digs into how PDBs actually work, the difference between voluntary and involuntary disruptions, the arithmetic behind &lt;code&gt;minAvailable&lt;/code&gt; and &lt;code&gt;maxUnavailable&lt;/code&gt;, and the failure modes that bite production clusters.&lt;/p&gt;</description></item><item><title>Referential equality</title><link>https://vabs.github.io/2026/03/25/referential-equality/</link><pubDate>Wed, 25 Mar 2026 08:55:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/25/referential-equality/</guid><description>&lt;p&gt;Referential equality means two values are considered equal because they point to the same object, array, or function instance. In JavaScript, objects compare by reference with &lt;code&gt;===&lt;/code&gt;. Two objects with identical fields are not equal unless they are the same allocation. Frontend frameworks lean on this rule because it makes change detection cheap: if a reference did not change, many systems assume the value did not change.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Previous prop object] --&gt; C{Same reference?}
 B[Next prop object] --&gt; C
 C --&gt;|yes| D[Can skip shallow update]
 C --&gt;|no| E[Inspect or rerender]

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Referential equality is a signal. A new reference usually means &amp;ldquo;something may have changed.&amp;rdquo; The same reference usually means &amp;ldquo;nothing changed.&amp;rdquo; The signal works when data is immutable and updates create new objects along changed paths. It fails when code mutates objects in place or recreates objects unnecessarily.&lt;/p&gt;</description></item><item><title>Index Bloat and Vacuum Strategies</title><link>https://vabs.github.io/2026/03/23/index-bloat-and-vacuum-strategies/</link><pubDate>Mon, 23 Mar 2026 15:52:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/23/index-bloat-and-vacuum-strategies/</guid><description>&lt;h2 id="why-bloat-exists-at-all"&gt;Why bloat exists at all&lt;/h2&gt;
&lt;p&gt;To understand index bloat you first have to understand a design decision at the heart of PostgreSQL: &lt;strong&gt;MVCC&lt;/strong&gt;, multi-version concurrency control. PostgreSQL never updates a row in place. An &lt;code&gt;UPDATE&lt;/code&gt; writes a &lt;em&gt;new&lt;/em&gt; version of the row and marks the old version as obsolete but does not remove it. A &lt;code&gt;DELETE&lt;/code&gt; just marks the row dead. The old versions — &lt;strong&gt;dead tuples&lt;/strong&gt; — stick around so that transactions which started before the change can still see the version they&amp;rsquo;re entitled to. This is what lets readers never block writers.&lt;/p&gt;</description></item><item><title>ETag vs Cache-Control</title><link>https://vabs.github.io/2026/03/23/etag-vs-cache-control/</link><pubDate>Mon, 23 Mar 2026 11:45:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/23/etag-vs-cache-control/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Cache-Control&lt;/code&gt; tells caches how long and under what rules a response can be reused. &lt;code&gt;ETag&lt;/code&gt; gives caches a validator they can send back to ask, &amp;ldquo;Is my stored response still current?&amp;rdquo; They are complementary, not alternatives.&lt;/p&gt;
&lt;p&gt;Freshness avoids a network round trip. Validation makes a round trip but can avoid downloading the full response. The fastest request is the one never made; the next best is a &lt;code&gt;304 Not Modified&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Backpressure in streams API</title><link>https://vabs.github.io/2026/03/23/backpressure-in-streams-api/</link><pubDate>Mon, 23 Mar 2026 10:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/23/backpressure-in-streams-api/</guid><description>&lt;p&gt;Backpressure is the mechanism that prevents a fast producer from overwhelming a slow consumer. In the browser Streams API, it is the difference between a pipeline that stays bounded and a pipeline that quietly buffers unbounded data until memory, latency, or responsiveness collapses. If you stream fetch responses, generate client-side exports, transform large files, or bridge WebSockets into streams, you need to understand where pressure is applied.&lt;/p&gt;
&lt;p&gt;The mental model is a queue with a desired size. A &lt;code&gt;ReadableStream&lt;/code&gt; has an internal queue. A consumer reads from it. A producer enqueues into it. When the queue reaches its high water mark, &lt;code&gt;controller.desiredSize&lt;/code&gt; becomes zero or negative, and a well-behaved producer slows down.&lt;/p&gt;</description></item><item><title>Shadow DOM</title><link>https://vabs.github.io/2026/03/23/shadow-dom/</link><pubDate>Mon, 23 Mar 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/23/shadow-dom/</guid><description>&lt;p&gt;Shadow DOM is an encapsulation boundary for DOM and CSS. It lets a component own internal markup without leaking every class name into the page, and without page styles accidentally rewriting its internals. The tradeoff is that styling, events, accessibility, and testing must be designed around the boundary instead of pretending it is normal nested HTML.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 Host[custom-element host]
 Host --&gt; Light[Light DOM children]
 Host --&gt; ShadowRoot[Shadow root]
 ShadowRoot --&gt; Internal[Internal DOM]
 ShadowRoot --&gt; Slot[slot]
 Light --&gt;|assigned nodes| Slot
 PageCSS[Page CSS] -. limited .-&gt; Host
 ComponentCSS[Shadow CSS] --&gt; Internal

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;A shadow root is attached to a host element with &lt;code&gt;attachShadow({ mode: &amp;quot;open&amp;quot; })&lt;/code&gt; or &lt;code&gt;closed&lt;/code&gt;. The component renders internal DOM inside that root. Selectors in the page do not cross into the shadow tree, and selectors inside the shadow tree do not target the rest of the page. This gives component authors a local styling environment.&lt;/p&gt;</description></item><item><title>Prepared Statement Caching</title><link>https://vabs.github.io/2026/03/20/prepared-statement-caching/</link><pubDate>Fri, 20 Mar 2026 10:14:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/20/prepared-statement-caching/</guid><description>&lt;h2 id="what-a-prepared-statement-actually-buys-you"&gt;What a prepared statement actually buys you&lt;/h2&gt;
&lt;p&gt;Every SQL query the database receives goes through a pipeline before a single row is touched: it is parsed into a syntax tree, analyzed and rewritten (resolving table and column names, expanding views), and then planned — the optimizer enumerates join orders, index choices, and scan strategies and picks the cheapest. Only then does execution begin.&lt;/p&gt;
&lt;p&gt;For a trivial point lookup, this planning overhead can rival or exceed the execution itself. If you run the same query shape thousands of times per second, re-parsing and re-planning each time is pure waste.&lt;/p&gt;</description></item><item><title>Islands architecture</title><link>https://vabs.github.io/2026/03/19/islands-architecture/</link><pubDate>Thu, 19 Mar 2026 09:45:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/19/islands-architecture/</guid><description>&lt;h2 id="mental-model-static-html-with-targeted-interactivity"&gt;Mental model: static HTML with targeted interactivity&lt;/h2&gt;
&lt;p&gt;Islands architecture starts from the assumption that most of a page can be delivered as inert HTML. Only specific interactive regions, or islands, receive client JavaScript. Instead of hydrating one large application root, the page contains multiple independent interactive mounts embedded in server-rendered or statically generated markup.&lt;/p&gt;
&lt;p&gt;This model fits content-heavy sites, ecommerce pages, documentation, marketing pages, and dashboards with isolated widgets. The performance win comes from avoiding JavaScript for regions that do not need browser-side state.&lt;/p&gt;</description></item><item><title>Largest Contentful Paint (LCP)</title><link>https://vabs.github.io/2026/03/18/largest-contentful-paint-lcp/</link><pubDate>Wed, 18 Mar 2026 14:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/18/largest-contentful-paint-lcp/</guid><description>&lt;p&gt;Largest Contentful Paint measures when the largest visible content element in the viewport is painted. It is a user-centric proxy for &amp;ldquo;the main thing loaded.&amp;rdquo; The LCP candidate is often a hero image, poster image, heading, large paragraph, or background image discovered through CSS. Optimizing it requires working backward from the actual winning element, not applying generic performance tricks.&lt;/p&gt;
&lt;p&gt;Think of LCP as four segments: time to first byte, resource load delay, resource load duration, and element render delay. The slowest segment determines the practical fix.&lt;/p&gt;</description></item><item><title>Subpixel rendering</title><link>https://vabs.github.io/2026/03/18/subpixel-rendering/</link><pubDate>Wed, 18 Mar 2026 13:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/18/subpixel-rendering/</guid><description>&lt;h2 id="css-pixels-are-not-device-pixels"&gt;CSS pixels are not device pixels&lt;/h2&gt;
&lt;p&gt;Modern layout is full of fractions. CSS pixels are an abstract unit; device pixels are physical display samples. Device pixel ratio, zoom, transforms, percentage layouts, font metrics, and flex/grid distribution all create subpixel values. The browser does not simply round every box to an integer at layout time. It carries fractional geometry forward and resolves it during painting and compositing.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart LR
 CSS["CSS values: %, rem, vw"] --&gt; Layout["fractional layout boxes"]
 Layout --&gt; Paint["paint commands with floats"]
 Paint --&gt; Raster["rasterize to device pixels"]
 Raster --&gt; Composite["composite transformed layers"]
 Composite --&gt; Display["physical pixels"]

&lt;/pre&gt;

&lt;p&gt;Subpixel rendering is why a three-column layout can divide 1000px into thirds without leaving a giant gap. It is also why borders blur, hairlines disappear, and screenshots differ across zoom levels.&lt;/p&gt;</description></item><item><title>Database Connection Pool Exhaustion</title><link>https://vabs.github.io/2026/03/18/database-connection-pool-exhaustion/</link><pubDate>Wed, 18 Mar 2026 13:37:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/18/database-connection-pool-exhaustion/</guid><description>&lt;h2 id="a-failure-that-looks-like-everything-else"&gt;A failure that looks like everything else&lt;/h2&gt;
&lt;p&gt;Connection pool exhaustion is one of the most common production incidents, and one of the most misdiagnosed. The symptom is generic: requests pile up, latency climbs, the application starts returning timeouts or 500s. The database itself looks healthy — low CPU, plenty of memory, queries running fast. Engineers chase slow queries and missing indexes for hours while the real problem is that the application has run out of connections to &lt;em&gt;send&lt;/em&gt; those fast queries through.&lt;/p&gt;</description></item><item><title>Server components</title><link>https://vabs.github.io/2026/03/16/server-components/</link><pubDate>Mon, 16 Mar 2026 12:10:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/16/server-components/</guid><description>&lt;h2 id="mental-model-components-can-be-a-transport-boundary"&gt;Mental model: components can be a transport boundary&lt;/h2&gt;
&lt;p&gt;Server Components move part of the component tree to the server. The important shift is that a component is no longer only a client-side rendering unit; it can also be a server-side data access and serialization unit. Server Components fetch data, render to a serializable payload, and hand client components only the props needed for interactivity.&lt;/p&gt;
&lt;p&gt;This is different from traditional SSR. SSR produces HTML for the first load and then the client app hydrates. Server Components can continue to render on the server across navigations, reducing client JavaScript for non-interactive parts of the tree.&lt;/p&gt;</description></item><item><title>Read Replicas Lag Monitoring</title><link>https://vabs.github.io/2026/03/16/read-replicas-lag-monitoring/</link><pubDate>Mon, 16 Mar 2026 11:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/16/read-replicas-lag-monitoring/</guid><description>&lt;h2 id="the-promise-and-the-catch"&gt;The promise and the catch&lt;/h2&gt;
&lt;p&gt;Read replicas are the standard first move for scaling reads. You point writes at a primary, stream its changes to one or more replicas, and fan out read traffic across them. Storage stays in sync automatically, and you get more read capacity by adding nodes.&lt;/p&gt;
&lt;p&gt;The catch is that replication is asynchronous by default. A replica is always some amount of time &lt;em&gt;behind&lt;/em&gt; the primary. That gap is &lt;strong&gt;replication lag&lt;/strong&gt;, and it is the single most important thing to monitor about a replicated system. Lag is invisible when small and catastrophic when large: a user updates their profile, the read hits a lagging replica, and they see their old data. Worse, an order is written and a downstream job reads from a replica that hasn&amp;rsquo;t caught up, so the order &amp;ldquo;doesn&amp;rsquo;t exist&amp;rdquo; yet.&lt;/p&gt;</description></item><item><title>HTTP/3 and QUIC</title><link>https://vabs.github.io/2026/03/16/http-3-and-quic/</link><pubDate>Mon, 16 Mar 2026 10:30:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/16/http-3-and-quic/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;HTTP/3 is HTTP semantics running over QUIC instead of TCP. QUIC is a UDP-based transport that includes encryption, streams, congestion control, loss recovery, and connection migration. For frontend engineers, the practical promise is lower latency under packet loss and faster connection setup, especially on mobile networks.&lt;/p&gt;
&lt;p&gt;HTTP/2 multiplexes many requests over one TCP connection, but TCP still delivers bytes in order. If one packet is lost, all streams sharing that connection can stall until the missing TCP segment is retransmitted. QUIC moves ordering to independent streams, so packet loss blocks only affected streams.&lt;/p&gt;</description></item><item><title>Sharding Strategies and Hot Partition Avoidance</title><link>https://vabs.github.io/2026/03/14/sharding-strategies-and-hot-partition-avoidance/</link><pubDate>Sat, 14 Mar 2026 16:48:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/14/sharding-strategies-and-hot-partition-avoidance/</guid><description>&lt;h2 id="why-shard-at-all"&gt;Why shard at all&lt;/h2&gt;
&lt;p&gt;A single database node has a ceiling. Eventually the working set no longer fits in memory, write throughput saturates a single disk, or the table grows so large that index maintenance and vacuum become unmanageable. Vertical scaling — bigger boxes — buys time but ends at the largest instance your provider sells, and at a price that grows faster than the capacity.&lt;/p&gt;
&lt;p&gt;Sharding is horizontal partitioning of data across multiple independent nodes, each owning a disjoint subset of rows. Done well, it gives near-linear scaling of both storage and throughput. Done badly, it concentrates load on one unlucky node — a &lt;strong&gt;hot partition&lt;/strong&gt; — and you get all the operational complexity of a distributed system with none of the scaling benefit.&lt;/p&gt;</description></item><item><title>Memoization pitfalls</title><link>https://vabs.github.io/2026/03/13/memoization-pitfalls/</link><pubDate>Fri, 13 Mar 2026 09:50:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/13/memoization-pitfalls/</guid><description>&lt;p&gt;Memoization caches the result of a computation for a set of inputs. In frontend code it can reduce expensive derived data, stabilize references passed to children, and avoid repeated work during render. It can also hide stale data, increase memory use, make profiling harder, and create the illusion that a render problem has been solved when the real issue is still there.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Inputs] --&gt; B{Same as cache key?}
 B --&gt;|yes| C[Return cached value]
 B --&gt;|no| D[Run computation]
 D --&gt; E[Store result]
 E --&gt; C

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Memoization is a trade: pay comparison and cache complexity to avoid recomputation. It only helps when the saved computation is more expensive than the cache overhead and when input identity changes less often than renders. If the inputs are always new objects, the cache misses every time. If the computation is cheap, the memo wrapper may cost more than recalculating.&lt;/p&gt;</description></item><item><title>AbortController</title><link>https://vabs.github.io/2026/03/12/abortcontroller/</link><pubDate>Thu, 12 Mar 2026 15:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/12/abortcontroller/</guid><description>&lt;p&gt;&lt;code&gt;AbortController&lt;/code&gt; is the web platform&amp;rsquo;s shared cancellation primitive. It started as the cancellation mechanism for &lt;code&gt;fetch&lt;/code&gt;, but it now appears across event listeners, streams, timers in some runtimes, and many library APIs. Its value is not just stopping network requests. It gives frontend code a consistent way to model ownership: when a component, route, interaction, or operation ends, everything attached to its signal should stop.&lt;/p&gt;
&lt;p&gt;The mental model has two pieces. An &lt;code&gt;AbortController&lt;/code&gt; owns an &lt;code&gt;AbortSignal&lt;/code&gt;. Consumers receive the signal. When the owner calls &lt;code&gt;abort()&lt;/code&gt;, the signal flips to aborted, stores a reason, and notifies listeners exactly once.&lt;/p&gt;</description></item><item><title>Outbox Pattern for Reliable Events</title><link>https://vabs.github.io/2026/03/12/outbox-pattern-for-reliable-events/</link><pubDate>Thu, 12 Mar 2026 09:22:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/12/outbox-pattern-for-reliable-events/</guid><description>&lt;h2 id="the-dual-write-problem"&gt;The dual-write problem&lt;/h2&gt;
&lt;p&gt;Almost every service that owns data also needs to tell the rest of the system when that data changes. An order service writes a row to its &lt;code&gt;orders&lt;/code&gt; table and then publishes an &lt;code&gt;OrderPlaced&lt;/code&gt; event to Kafka. On paper this is two lines of code. In production it is one of the most common sources of silent data loss in distributed systems.&lt;/p&gt;
&lt;p&gt;The trouble is that a database transaction and a message broker publish are two independent systems with two independent commit protocols. There is no shared transaction across them. So you are forced into a sequence:&lt;/p&gt;</description></item><item><title>Custom Elements lifecycle</title><link>https://vabs.github.io/2026/03/12/custom-elements-lifecycle/</link><pubDate>Thu, 12 Mar 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/12/custom-elements-lifecycle/</guid><description>&lt;p&gt;Custom elements are classes that the browser upgrades into real DOM behavior. Their lifecycle is not a framework lifecycle with a virtual tree in front of it. It is the platform telling your element when it is constructed, connected, disconnected, adopted into another document, or affected by observed attribute changes. That makes the lifecycle precise, but also unforgiving: your element can be created by the parser, by &lt;code&gt;document.createElement&lt;/code&gt;, by cloning, or by a framework that moves DOM around during reconciliation.&lt;/p&gt;</description></item><item><title>CQRS and Event Sourcing Projections</title><link>https://vabs.github.io/2026/03/10/cqrs-event-sourcing-projections/</link><pubDate>Tue, 10 Mar 2026 16:53:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/10/cqrs-event-sourcing-projections/</guid><description>&lt;p&gt;Most applications use a single data model for both writing and reading: the same tables, the same objects, the same schema serve commands that change data and queries that fetch it. This works until the demands of writes and reads diverge so much that one model can&amp;rsquo;t serve both well. &lt;strong&gt;CQRS&lt;/strong&gt; (Command Query Responsibility Segregation) splits them apart. Paired with &lt;strong&gt;event sourcing&lt;/strong&gt;, it produces a powerful architecture where the write side records facts and the read side builds whatever views it needs through &lt;strong&gt;projections&lt;/strong&gt;. This post focuses on that last, often-underexplained piece: how projections turn an event stream into queryable read models, and the hard problems that come with them.&lt;/p&gt;</description></item><item><title>Priority hints</title><link>https://vabs.github.io/2026/03/09/priority-hints/</link><pubDate>Mon, 09 Mar 2026 15:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/09/priority-hints/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Priority Hints let developers nudge the browser&amp;rsquo;s internal fetch priority using &lt;code&gt;fetchpriority&lt;/code&gt;. They are useful when the browser&amp;rsquo;s default guess is wrong: a hero image should load sooner, or a below-the-fold image should stop competing with critical CSS and JavaScript.&lt;/p&gt;
&lt;p&gt;This is a hint, not a command. The browser still considers resource type, render blocking, viewport, connection state, and its own scheduler.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 A["HTML parser discovers resources"] --&gt; B["Browser assigns default priority"]
 B --&gt; C{"fetchpriority present?"}
 C --&gt;|high| D["Boost relative priority"]
 C --&gt;|low| E["Deprioritize relative priority"]
 C --&gt;|auto| F["Keep browser default"]
 D --&gt; G["Network scheduler"]
 E --&gt; G
 F --&gt; G

&lt;/pre&gt;

&lt;h2 id="internals-that-matter"&gt;Internals that matter&lt;/h2&gt;
&lt;p&gt;Browsers already prioritize resources. CSS and blocking scripts are high. Images often start lower until layout reveals whether they matter. That can delay the Largest Contentful Paint image, especially when it appears in the initial viewport but is discovered among many other images.&lt;/p&gt;</description></item><item><title>Thread Pools vs Virtual Threads (Project Loom)</title><link>https://vabs.github.io/2026/03/08/thread-pools-vs-virtual-threads-project-loom/</link><pubDate>Sun, 08 Mar 2026 11:27:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/08/thread-pools-vs-virtual-threads-project-loom/</guid><description>&lt;p&gt;For two decades, the standard advice for writing scalable Java servers has been: never block a thread, because threads are expensive, so wrap everything in thread pools and reactive callbacks. Project Loom&amp;rsquo;s virtual threads, now a stable feature of the JVM, upend that advice. They make blocking cheap again, letting you write straightforward synchronous code that scales to millions of concurrent operations. This post explains what changed, how virtual threads work under the hood, and when you should still reach for a classic thread pool.&lt;/p&gt;</description></item><item><title>Speculative prerendering</title><link>https://vabs.github.io/2026/03/08/speculative-prerendering/</link><pubDate>Sun, 08 Mar 2026 10:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/08/speculative-prerendering/</guid><description>&lt;p&gt;Speculative prerendering loads and renders a likely future page before the user navigates to it. When the prediction is right, navigation can feel instant because HTML parsing, subresource loading, script execution, layout, and sometimes rendering have already happened in a hidden context. When the prediction is wrong, you have spent bandwidth, CPU, memory, cache capacity, and possibly backend quota for no user-visible result.&lt;/p&gt;
&lt;p&gt;The mental model is a pipeline: predict intent, declare safe candidates, let the browser prerender under constraints, then activate or discard. Your application must be safe to run before visible navigation.&lt;/p&gt;</description></item><item><title>Log Aggregation with Sampling</title><link>https://vabs.github.io/2026/03/06/log-aggregation-with-sampling/</link><pubDate>Fri, 06 Mar 2026 16:18:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/06/log-aggregation-with-sampling/</guid><description>&lt;h2 id="why-aggregate-and-why-sample"&gt;Why aggregate, and why sample&lt;/h2&gt;
&lt;p&gt;A single modern service can emit tens of thousands of log lines per second. Multiply that across a fleet of hundreds of instances and you are producing terabytes per day. Log aggregation is the practice of shipping all of that from individual machines into a central store — Loki, Elasticsearch, a cloud log service — where it can be searched, correlated, and retained. The aggregation part is well understood. The harder question is economic: do you actually need to store every line?&lt;/p&gt;</description></item><item><title>Streaming SSR</title><link>https://vabs.github.io/2026/03/05/streaming-ssr/</link><pubDate>Thu, 05 Mar 2026 12:05:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/05/streaming-ssr/</guid><description>&lt;h2 id="mental-model-send-the-shell-before-every-dependency-is-done"&gt;Mental model: send the shell before every dependency is done&lt;/h2&gt;
&lt;p&gt;Traditional server-side rendering waits until the whole page&amp;rsquo;s data and HTML are ready, then sends one response. Streaming SSR sends useful HTML as soon as possible, then streams later chunks when slower work completes. The user can receive the document shell, critical layout, and fallbacks before every panel is ready.&lt;/p&gt;
&lt;p&gt;Streaming is not just &amp;ldquo;flush earlier.&amp;rdquo; It changes how you model latency. Parts of the page become independently deliverable regions, often aligned with Suspense boundaries. The server can reveal fast content immediately and let slow content arrive later without blocking the entire first byte.&lt;/p&gt;</description></item><item><title>IntersectionObserver internals</title><link>https://vabs.github.io/2026/03/04/intersectionobserver-internals/</link><pubDate>Wed, 04 Mar 2026 16:10:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/04/intersectionobserver-internals/</guid><description>&lt;h2 id="intersectionobserver-answers-a-geometry-question-asynchronously"&gt;IntersectionObserver answers a geometry question asynchronously&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; tells you when a target intersects a root rectangle. It is built for lazy loading, infinite scrolling, ad visibility, analytics, and scroll-linked activation without running a scroll handler on every frame. The key is that it is asynchronous: the browser computes intersections during its rendering pipeline and delivers entries later.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 Root["root viewport or scroll container"] --&gt; RootMargin["apply rootMargin"]
 Target["target border box"] --&gt; Clip["clip through ancestors"]
 RootMargin --&gt; Intersect["intersection rectangle"]
 Clip --&gt; Intersect
 Intersect --&gt; Ratio["intersectionRatio thresholds"]
 Ratio --&gt; Callback["queued observer callback"]

&lt;/pre&gt;

&lt;p&gt;This is why it scales better than manually calling &lt;code&gt;getBoundingClientRect()&lt;/code&gt; in scroll events. The engine already has layout and clipping information; the observer lets it batch work.&lt;/p&gt;</description></item><item><title>Garbage Collection Tuning: G1 vs ZGC</title><link>https://vabs.github.io/2026/03/04/garbage-collection-tuning-g1-vs-zgc/</link><pubDate>Wed, 04 Mar 2026 15:42:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/04/garbage-collection-tuning-g1-vs-zgc/</guid><description>&lt;p&gt;Garbage collection is the JVM feature most developers ignore until a production incident forces them to care. A service that hums along at p50 latency of 5ms can suddenly spike to 800ms because a stop-the-world pause froze every thread to reclaim memory. Choosing and tuning the right collector is one of the highest-leverage things you can do for a latency-sensitive Java service. This post compares the two collectors that matter most for modern server workloads: G1 (the default since Java 9) and ZGC (the low-latency contender that went production-ready and non-generational in newer releases).&lt;/p&gt;</description></item><item><title>Stale closure problem</title><link>https://vabs.github.io/2026/03/04/stale-closure-problem/</link><pubDate>Wed, 04 Mar 2026 10:05:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/04/stale-closure-problem/</guid><description>&lt;p&gt;The stale closure problem occurs when a function keeps references to values from an old render, old state transition, or old lexical scope and then runs later as if those values were current. In frontend code it appears in timers, event listeners, promises, subscriptions, memoized callbacks, and effects. The bug is not that closures are broken. The bug is that the callback&amp;rsquo;s lifetime is longer than the state snapshot it captured.&lt;/p&gt;</description></item><item><title>Streaming fetch response handling</title><link>https://vabs.github.io/2026/03/03/streaming-fetch-response-handling/</link><pubDate>Tue, 03 Mar 2026 09:55:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/03/streaming-fetch-response-handling/</guid><description>&lt;p&gt;Streaming fetch response handling lets a page process bytes as they arrive instead of waiting for the entire response body. That changes the user experience for large payloads, AI responses, logs, exports, media metadata, and progressive data formats. It also changes failure handling: once you process partial data, you need explicit rules for incomplete messages, cancellation, decoding, and backpressure.&lt;/p&gt;
&lt;p&gt;The mental model is that &lt;code&gt;fetch()&lt;/code&gt; resolves when response headers are available, not when the body is fully downloaded. The &lt;code&gt;Response.body&lt;/code&gt; is a &lt;code&gt;ReadableStream&amp;lt;Uint8Array&amp;gt;&lt;/code&gt;. You consume chunks from that stream, decode bytes into text if needed, parse message boundaries, and update UI incrementally.&lt;/p&gt;</description></item><item><title>Preload vs Prefetch vs Preconnect</title><link>https://vabs.github.io/2026/03/02/preload-vs-prefetch-vs-preconnect/</link><pubDate>Mon, 02 Mar 2026 09:50:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/02/preload-vs-prefetch-vs-preconnect/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;preload&lt;/code&gt;, &lt;code&gt;prefetch&lt;/code&gt;, and &lt;code&gt;preconnect&lt;/code&gt; are resource hints, but they solve different timing problems. &lt;code&gt;preload&lt;/code&gt; says &amp;ldquo;this resource is needed for the current navigation; start it earlier.&amp;rdquo; &lt;code&gt;prefetch&lt;/code&gt; says &amp;ldquo;this may be needed for a future navigation; fetch it when idle.&amp;rdquo; &lt;code&gt;preconnect&lt;/code&gt; says &amp;ldquo;I will need this origin soon; warm up DNS, TCP, and TLS.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Choosing the wrong hint can make performance worse by stealing bandwidth from critical resources.&lt;/p&gt;</description></item><item><title>Message-Driven Architecture with Akka and Orleans</title><link>https://vabs.github.io/2026/03/02/message-driven-architecture-akka-orleans/</link><pubDate>Mon, 02 Mar 2026 10:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/02/message-driven-architecture-akka-orleans/</guid><description>&lt;p&gt;When a system grows beyond a single machine, the comfortable abstractions of in-process method calls break down. Networks fail, machines crash, and latency becomes unpredictable. Message-driven architecture embraces these realities instead of hiding them, treating asynchronous messages as the primary unit of interaction. Two of the most influential frameworks in this space, &lt;strong&gt;Akka&lt;/strong&gt; on the JVM and &lt;strong&gt;Orleans&lt;/strong&gt; on .NET, both build on the actor model but make strikingly different choices about how much complexity the developer should manage. Comparing them illuminates the whole design space of distributed message-driven systems.&lt;/p&gt;</description></item><item><title>Edge rendering</title><link>https://vabs.github.io/2026/03/02/edge-rendering/</link><pubDate>Mon, 02 Mar 2026 08:50:00 -0500</pubDate><guid>https://vabs.github.io/2026/03/02/edge-rendering/</guid><description>&lt;h2 id="mental-model-move-the-first-decision-closer-to-the-user"&gt;Mental model: move the first decision closer to the user&lt;/h2&gt;
&lt;p&gt;Edge rendering runs request-time rendering logic in geographically distributed runtimes near the user. The goal is not simply &amp;ldquo;server-side rendering, but cooler.&amp;rdquo; The goal is to reduce latency for decisions that must happen before the first byte: locale, authentication hints, experiments, personalization, redirects, and cache selection.&lt;/p&gt;
&lt;p&gt;The edge is useful when the response varies by request but can still be computed with low latency and limited dependencies. It is a poor fit for heavy rendering that needs a private VPC database, large native modules, or long CPU bursts.&lt;/p&gt;</description></item><item><title>Web Components interoperability</title><link>https://vabs.github.io/2026/03/02/web-components-interoperability/</link><pubDate>Mon, 02 Mar 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/03/02/web-components-interoperability/</guid><description>&lt;p&gt;Web Components are most valuable at boundaries: design systems used across frameworks, embeddable widgets, long-lived platform components, and islands inside applications that change framework stacks over time. Interoperability is the main promise, but it is not automatic. You get it by designing the component API around browser primitives that every framework can understand.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 Host[React/Vue/Angular/Svelte app] --&gt;|attributes/properties| Element[Custom element]
 Element --&gt; Shadow[Shadow DOM internals]
 Element --&gt;|CustomEvent| Host
 Host --&gt;|slots| Element
 Element --&gt; CSS[CSS custom properties/parts]

&lt;/pre&gt;

&lt;h2 id="api-mental-model"&gt;API mental model&lt;/h2&gt;
&lt;p&gt;A custom element has four public channels: attributes, properties, events, and slots. Attributes are string-based and declarative. Properties can hold richer values but require imperative assignment. Events are the portable callback mechanism. Slots let host markup provide content without the component knowing the host framework.&lt;/p&gt;</description></item><item><title>Prometheus Metric Cardinality Explosion</title><link>https://vabs.github.io/2026/02/28/prometheus-metric-cardinality-explosion/</link><pubDate>Sat, 28 Feb 2026 10:42:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/28/prometheus-metric-cardinality-explosion/</guid><description>&lt;h2 id="what-cardinality-actually-means"&gt;What cardinality actually means&lt;/h2&gt;
&lt;p&gt;In Prometheus, a single metric name is not one thing. Every unique combination of label values produces a distinct time series, and each series is stored, indexed, and queried independently. The &lt;em&gt;cardinality&lt;/em&gt; of a metric is the number of distinct label-value combinations it produces. A cardinality explosion happens when that number grows far beyond what the operator anticipated, usually because a label was attached to a value that has high or unbounded variety.&lt;/p&gt;</description></item><item><title>Memory-Mapped Files vs Traditional I/O</title><link>https://vabs.github.io/2026/02/27/memory-mapped-files-vs-traditional-io/</link><pubDate>Fri, 27 Feb 2026 09:14:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/27/memory-mapped-files-vs-traditional-io/</guid><description>&lt;p&gt;When a service needs to read or write large files, the choice between traditional stream-based I/O and memory-mapped files (mmap) can change throughput, latency, and memory behavior by an order of magnitude. Both eventually move bytes between disk and process, but they take fundamentally different paths through the operating system. Understanding those paths is the difference between a database that sustains millions of reads per second and one that thrashes under load.&lt;/p&gt;</description></item><item><title>Actor Model vs Shared-Memory Concurrency</title><link>https://vabs.github.io/2026/02/26/actor-model-vs-shared-memory-concurrency/</link><pubDate>Thu, 26 Feb 2026 14:08:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/26/actor-model-vs-shared-memory-concurrency/</guid><description>&lt;p&gt;Concurrency is hard because two independent activities can touch the same data at the same time and corrupt it. Two broad philosophies have emerged to tame this. &lt;strong&gt;Shared-memory concurrency&lt;/strong&gt; lets threads access common data and uses locks to coordinate. The &lt;strong&gt;actor model&lt;/strong&gt; forbids shared mutable state entirely, replacing it with message passing between isolated entities. Understanding the trade-offs between these approaches shapes how you design everything from a single-process service to a globally distributed system.&lt;/p&gt;</description></item><item><title>Priority inversion in async code</title><link>https://vabs.github.io/2026/02/25/priority-inversion-in-async-code/</link><pubDate>Wed, 25 Feb 2026 15:10:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/25/priority-inversion-in-async-code/</guid><description>&lt;p&gt;Priority inversion happens when high-priority work waits behind low-priority work. In frontend code, it shows up when a click waits behind analytics, a keystroke waits behind JSON parsing, a route transition waits behind image processing, or an urgent state update is blocked by a long microtask chain. The main thread is a shared CPU, and JavaScript&amp;rsquo;s cooperative model means priority is only real if your code yields.&lt;/p&gt;
&lt;p&gt;The mental model: async does not automatically mean non-blocking. A promise callback still runs on the main thread. &lt;code&gt;await&lt;/code&gt; splits work into continuations, but each continuation can monopolize the event loop. Browser rendering, input handling, timers, network callbacks, and your framework scheduler all compete for turns.&lt;/p&gt;</description></item><item><title>Observability: OpenTelemetry Tracing Propagation</title><link>https://vabs.github.io/2026/02/24/observability-opentelemetry-tracing-propagation/</link><pubDate>Tue, 24 Feb 2026 13:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/24/observability-opentelemetry-tracing-propagation/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;In a monolith, a stack trace tells you the whole story of a request. In a distributed system, one user action might touch a gateway, three services, a queue, and two databases — across different processes, machines, and languages. A stack trace in any one of them shows only a fragment. Distributed tracing reassembles the fragments into a single coherent picture of the request&amp;rsquo;s journey.&lt;/p&gt;
&lt;p&gt;The unit of that picture is the &lt;strong&gt;trace&lt;/strong&gt;: a tree of &lt;strong&gt;spans&lt;/strong&gt;, where each span represents one operation (an HTTP handler, a DB query, a queue publish) with a start time, duration, attributes, and a link to its parent. The magic that lets spans created in five different processes belong to one tree is &lt;strong&gt;context propagation&lt;/strong&gt; — passing the trace identity across every process boundary the request crosses.&lt;/p&gt;</description></item><item><title>Event loop (macro vs microtasks)</title><link>https://vabs.github.io/2026/02/24/event-loop-macro-vs-microtasks/</link><pubDate>Tue, 24 Feb 2026 09:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/24/event-loop-macro-vs-microtasks/</guid><description>&lt;p&gt;The distinction between macrotasks and microtasks explains many frontend timing bugs. A task, often called a macrotask, is work such as a timer callback, input event, network callback, or script execution. A microtask is work scheduled to run immediately after the current JavaScript stack finishes and before the browser moves on to rendering or the next task. Promise callbacks, &lt;code&gt;queueMicrotask&lt;/code&gt;, and mutation observer callbacks use this queue.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Pick next task] --&gt; B[Run JS stack]
 B --&gt; C[Drain all microtasks]
 C --&gt; D{Microtasks added?}
 D --&gt;|yes| C
 D --&gt;|no| E[Render opportunity]
 E --&gt; A

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Tasks are turns. Microtasks are cleanup at the end of the current turn. The browser drains the microtask queue completely before it considers painting or handling another task. That makes microtasks useful for preserving invariants: finish a state flush, notify subscribers, or resolve promise continuations before external events observe a half-updated state.&lt;/p&gt;</description></item><item><title>CORS preflight</title><link>https://vabs.github.io/2026/02/23/cors-preflight/</link><pubDate>Mon, 23 Feb 2026 12:25:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/23/cors-preflight/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;CORS preflight is the browser asking a server for permission before sending a cross-origin request that could have side effects or expose non-simple behavior. The browser sends an &lt;code&gt;OPTIONS&lt;/code&gt; request with the intended method and headers. If the server responds with matching &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers, the real request proceeds.&lt;/p&gt;
&lt;p&gt;Preflight is not authentication and not a firewall. It is a browser-enforced read/write permission protocol. Non-browser clients can ignore it, and same-origin requests do not need it.&lt;/p&gt;</description></item><item><title>Circuit Breaker and Bulkhead Patterns</title><link>https://vabs.github.io/2026/02/22/circuit-breaker-and-bulkhead-patterns/</link><pubDate>Sun, 22 Feb 2026 10:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/22/circuit-breaker-and-bulkhead-patterns/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;In a distributed system, the dangerous failures are not the ones that crash a single service — they are the ones that &lt;em&gt;cascade&lt;/em&gt;. Service A calls service B. B gets slow. A&amp;rsquo;s threads pile up waiting on B. A runs out of threads and can no longer serve &lt;em&gt;any&lt;/em&gt; request, including ones that have nothing to do with B. Now A is down, and everything that calls A starts to fail too. A slow dependency three hops away has taken down your whole platform.&lt;/p&gt;</description></item><item><title>Rate Limiting Algorithms: Token Bucket vs Leaky Bucket</title><link>https://vabs.github.io/2026/02/20/rate-limiting-algorithms-token-bucket-vs-leaky-bucket/</link><pubDate>Fri, 20 Feb 2026 16:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/20/rate-limiting-algorithms-token-bucket-vs-leaky-bucket/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Rate limiting answers a deceptively simple question: &lt;em&gt;should this request be allowed right now?&lt;/em&gt; The hard part is the &amp;ldquo;right now.&amp;rdquo; A naive counter — &amp;ldquo;max 100 requests per minute&amp;rdquo; — is full of edge cases around how time is divided and whether bursts are allowed. The mature algorithms exist precisely to handle those edges cleanly.&lt;/p&gt;
&lt;p&gt;Two algorithms dominate the conversation, and they are often confused because both use a &amp;ldquo;bucket&amp;rdquo; metaphor. They are not the same:&lt;/p&gt;</description></item><item><title>Web Workers vs Service Workers</title><link>https://vabs.github.io/2026/02/20/web-workers-vs-service-workers/</link><pubDate>Fri, 20 Feb 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/20/web-workers-vs-service-workers/</guid><description>&lt;p&gt;Web Workers and Service Workers both run off the main thread, but they solve different problems. A Web Worker is a compute companion for a page. A Service Worker is a network proxy and lifecycle-managed background agent for an origin. Confusing them leads to brittle caching, misplaced business logic, and debugging sessions where the code you changed is not the code currently controlling the page.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart LR
 Page[Browser page] --&gt;|postMessage| WW[Web Worker]
 WW --&gt;|result| Page
 Page --&gt;|fetch/navigation| SW[Service Worker]
 SW --&gt; Cache[Cache Storage]
 SW --&gt; Network[Network]
 SW --&gt; Page

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;A Web Worker is created by a page with &lt;code&gt;new Worker()&lt;/code&gt;. It lives as long as the page keeps it alive. It is good for parsing large files, running search indexes, image processing, compression, WebAssembly, and any task that would otherwise create main-thread long tasks. It cannot intercept network requests for other pages and does not survive independently as a general daemon.&lt;/p&gt;</description></item><item><title>Concurrent rendering</title><link>https://vabs.github.io/2026/02/19/concurrent-rendering/</link><pubDate>Thu, 19 Feb 2026 11:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/19/concurrent-rendering/</guid><description>&lt;h2 id="mental-model-multiple-possible-futures"&gt;Mental model: multiple possible futures&lt;/h2&gt;
&lt;p&gt;Concurrent rendering lets React prepare a future UI without immediately committing it. The current screen remains visible while React works on another version of the tree. If a more important update arrives, React can pause or abandon the older work and prepare a better future.&lt;/p&gt;
&lt;p&gt;This is a rendering model, not a data-race model with multiple JavaScript threads. Your component code still runs on the main thread. The concurrency is about scheduling, interruption, prioritization, and choosing which completed tree becomes visible.&lt;/p&gt;</description></item><item><title>ResizeObserver loop limits</title><link>https://vabs.github.io/2026/02/19/resizeobserver-loop-limits/</link><pubDate>Thu, 19 Feb 2026 11:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/19/resizeobserver-loop-limits/</guid><description>&lt;h2 id="resizeobserver-closes-a-feedback-loop"&gt;ResizeObserver closes a feedback loop&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ResizeObserver&lt;/code&gt; reports element size changes. That sounds simple until the callback changes styles that change sizes again. The browser therefore runs ResizeObserver delivery in a guarded loop with a limit. When your callback keeps causing new resize notifications, the browser stops and reports a loop limit warning.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 Layout["style and layout"] --&gt; Gather["gather active resize observations"]
 Gather --&gt; Callback["run ResizeObserver callbacks"]
 Callback --&gt; Writes["callback writes size-affecting styles"]
 Writes --&gt; Layout
 Callback --&gt; Paint["paint when stable"]
 Gather --&gt; Limit["loop limit exceeded"] --&gt; Paint

&lt;/pre&gt;

&lt;p&gt;The warning is not random. It means the browser protected rendering from an unstable measurement-write cycle.&lt;/p&gt;</description></item><item><title>OAuth2 Token Introspection vs JWT Validation</title><link>https://vabs.github.io/2026/02/18/oauth2-token-introspection-vs-jwt-validation/</link><pubDate>Wed, 18 Feb 2026 11:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/18/oauth2-token-introspection-vs-jwt-validation/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;When a resource server receives an OAuth2 access token, it must answer one question before doing anything else: &lt;em&gt;is this token valid, and what does it authorize?&lt;/em&gt; There are two fundamentally different ways to answer it.&lt;/p&gt;
&lt;p&gt;The first is &lt;strong&gt;local JWT validation&lt;/strong&gt;: the token is a self-contained, signed JSON Web Token. The resource server verifies the signature with the authorization server&amp;rsquo;s public key and reads the claims directly. No network call.&lt;/p&gt;</description></item><item><title>Micro-frontend orchestration</title><link>https://vabs.github.io/2026/02/17/micro-frontend-orchestration/</link><pubDate>Tue, 17 Feb 2026 13:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/17/micro-frontend-orchestration/</guid><description>&lt;h2 id="mental-model-composition-is-the-product"&gt;Mental model: composition is the product&lt;/h2&gt;
&lt;p&gt;Micro-frontends are not primarily about splitting code. They are about splitting ownership while still shipping one coherent product. Orchestration is the layer that decides which independently built UI units load, where they mount, how they communicate, and what happens when one of them fails.&lt;/p&gt;
&lt;p&gt;Without orchestration, a micro-frontend system becomes a set of teams deploying JavaScript into the same page and hoping version boundaries hold. A good shell gives teams autonomy while preserving routing, identity, observability, design constraints, and failure isolation.&lt;/p&gt;</description></item><item><title>SameSite cookie modes</title><link>https://vabs.github.io/2026/02/16/samesite-cookie-modes/</link><pubDate>Mon, 16 Feb 2026 08:40:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/16/samesite-cookie-modes/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SameSite&lt;/code&gt; controls when the browser sends a cookie on cross-site requests. It is not about same-origin; it is about same-site, which is based on the registrable domain plus scheme. &lt;code&gt;app.example.com&lt;/code&gt; and &lt;code&gt;api.example.com&lt;/code&gt; are same-site, while &lt;code&gt;example.com&lt;/code&gt; and &lt;code&gt;example.net&lt;/code&gt; are cross-site.&lt;/p&gt;
&lt;p&gt;The setting answers a narrow question: &amp;ldquo;Should this cookie be attached when the request was initiated from another site?&amp;rdquo; That makes it a major CSRF mitigation and a frequent source of auth bugs in embeds, OAuth, payment redirects, and local development.&lt;/p&gt;</description></item><item><title>GraphQL Resolver Batching and the N+1 Problem</title><link>https://vabs.github.io/2026/02/15/graphql-resolver-batching-and-n-plus-1-problem/</link><pubDate>Sun, 15 Feb 2026 14:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/15/graphql-resolver-batching-and-n-plus-1-problem/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;GraphQL&amp;rsquo;s execution model is a tree walk. The server resolves the root fields, then for each returned object it resolves that object&amp;rsquo;s selected fields, recursively. Each field has a &lt;em&gt;resolver&lt;/em&gt; — a function that produces the value for that field given its parent object. This per-field resolution is what makes GraphQL flexible, and it is also exactly what creates the N+1 problem.&lt;/p&gt;
&lt;p&gt;Consider a query for a list of posts and each post&amp;rsquo;s author:&lt;/p&gt;</description></item><item><title>Deterministic rendering</title><link>https://vabs.github.io/2026/02/14/deterministic-rendering/</link><pubDate>Sat, 14 Feb 2026 13:00:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/14/deterministic-rendering/</guid><description>&lt;p&gt;Deterministic rendering means the same inputs produce the same UI output, independent of timing, machine, locale, random numbers, request order, and hydration path. It is a prerequisite for reliable server rendering, visual regression tests, replayable bugs, and confident refactoring. Modern frontend stacks make nondeterminism easy because rendering is interleaved with async data, browser APIs, concurrent scheduling, and client-only effects.&lt;/p&gt;
&lt;p&gt;The mental model: render should be a pure projection of explicit state. Anything that reads time, randomness, layout, global mutable data, storage, network state, or environment should be isolated before or after render and converted into stable inputs.&lt;/p&gt;</description></item><item><title>Browser memory leak detection</title><link>https://vabs.github.io/2026/02/14/browser-memory-leak-detection/</link><pubDate>Sat, 14 Feb 2026 11:10:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/14/browser-memory-leak-detection/</guid><description>&lt;p&gt;Browser memory leak detection is less about finding one magic number and more about proving that memory grows after repeated workflows when it should return to a stable baseline. JavaScript garbage collection is nondeterministic, browser processes share memory across systems, and DevTools changes runtime behavior. A good leak investigation controls the workflow, repeats it, forces diagnostic collections only when appropriate, and follows retaining paths to the owner.&lt;/p&gt;
&lt;p&gt;The core distinction is retained memory versus allocated memory. Allocated memory is what your code creates over time. Retained memory is what remains reachable after the workflow finishes and garbage collection has had a chance to run. Leaks are retained memory problems. Jank from allocation churn may have stable retained memory but frequent GC.&lt;/p&gt;</description></item><item><title>gRPC Streaming and Flow Control</title><link>https://vabs.github.io/2026/02/13/grpc-streaming-and-flow-control/</link><pubDate>Fri, 13 Feb 2026 09:20:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/13/grpc-streaming-and-flow-control/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;gRPC is RPC semantics layered on top of HTTP/2. Every gRPC call is an HTTP/2 stream, and every message you send is a length-prefixed frame written into that stream. Once you internalize that mapping, streaming and flow control stop being magic: they are just HTTP/2 features that gRPC exposes through a friendlier API.&lt;/p&gt;
&lt;p&gt;gRPC offers four call shapes. Unary is the classic request/response. Server streaming keeps the request single but lets the server push many messages. Client streaming reverses that. Bidirectional streaming opens both directions independently, which is the most powerful and the easiest to misuse.&lt;/p&gt;</description></item><item><title>Task starvation</title><link>https://vabs.github.io/2026/02/12/task-starvation/</link><pubDate>Thu, 12 Feb 2026 11:00:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/12/task-starvation/</guid><description>&lt;p&gt;Task starvation is what happens when important browser work cannot get a turn on the main thread. The page may not be frozen in the crash sense: JavaScript is running, promises are resolving, and state is changing. But input, rendering, timers, or lower-priority work are delayed because one source keeps scheduling more work ahead of them.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Task starts] --&gt; B[Run JS]
 B --&gt; C[Drain microtasks]
 C --&gt; D{More microtasks queued?}
 D --&gt;|yes| C
 D --&gt;|no| E[Browser may render]
 E --&gt; F[Next task]

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;The event loop processes a task, drains the microtask queue, gives the browser a chance to render, then moves to the next task. Starvation appears when one phase keeps refilling itself. A long synchronous loop starves everything until it exits. An unbounded promise chain can starve rendering because microtasks must drain before the browser advances. A flood of high-priority app work can starve user-visible updates even if each unit is individually short.&lt;/p&gt;</description></item><item><title>CSRF vs XSS mitigation</title><link>https://vabs.github.io/2026/02/09/csrf-vs-xss-mitigation/</link><pubDate>Mon, 09 Feb 2026 13:10:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/09/csrf-vs-xss-mitigation/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;CSRF and XSS are both browser security problems, but they abuse different trust relationships. Cross-Site Request Forgery makes the browser send an authenticated request the user did not intend. Cross-Site Scripting runs attacker-controlled script inside the trusted origin.&lt;/p&gt;
&lt;p&gt;CSRF asks, &amp;ldquo;Can another site cause this user&amp;rsquo;s browser to perform an action?&amp;rdquo; XSS asks, &amp;ldquo;Can attacker code run as this site?&amp;rdquo; XSS is usually more powerful because it can read page state, call same-origin APIs, and often bypass CSRF tokens by reading them.&lt;/p&gt;</description></item><item><title>Kafka Partition Rebalancing &amp; Exactly-Once Semantics</title><link>https://vabs.github.io/2026/02/09/kafka-partition-rebalancing-and-exactly-once-semantics/</link><pubDate>Mon, 09 Feb 2026 09:35:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/09/kafka-partition-rebalancing-and-exactly-once-semantics/</guid><description>&lt;p&gt;Two of the most misunderstood parts of running Apache Kafka in production are how consumer group rebalancing works and what &amp;ldquo;exactly-once&amp;rdquo; actually guarantees. Both are areas where the defaults are reasonable but the failure modes are subtle, and where a confident-sounding wrong mental model leads to duplicate processing, stalled consumers, and data loss. This post digs into the mechanics of rebalancing, why it can cripple throughput, and how Kafka&amp;rsquo;s transactional machinery delivers exactly-once semantics — within the bounds of what is actually possible.&lt;/p&gt;</description></item><item><title>SharedArrayBuffer</title><link>https://vabs.github.io/2026/02/09/sharedarraybuffer/</link><pubDate>Mon, 09 Feb 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/09/sharedarraybuffer/</guid><description>&lt;p&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt; gives multiple JavaScript agents access to the same memory. Unlike transferable &lt;code&gt;ArrayBuffer&lt;/code&gt;, ownership does not move. The main thread and Workers can observe and modify shared bytes concurrently. That makes it powerful for low-latency coordination and dangerous when treated like ordinary JavaScript state.&lt;/p&gt;
&lt;p&gt;The mental model is shared memory plus explicit synchronization. Reads and writes through typed arrays are not a message protocol. If one thread writes data and another reads it, you need a way to define when the data is ready. In browser JavaScript, that synchronization is the &lt;code&gt;Atomics&lt;/code&gt; API over integer typed arrays.&lt;/p&gt;</description></item><item><title>CRDTs &amp; Conflict-Free Replicated Data Types</title><link>https://vabs.github.io/2026/02/07/crdts-and-conflict-free-replicated-data-types/</link><pubDate>Sat, 07 Feb 2026 11:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/07/crdts-and-conflict-free-replicated-data-types/</guid><description>&lt;p&gt;When two replicas of the same data accept writes independently and then sync, something has to decide what the merged result is. The usual answer is &amp;ldquo;ask a server&amp;rdquo; or &amp;ldquo;last write wins,&amp;rdquo; and both have well-known failure modes: the server is a single point of contention, and last-write-wins silently throws away data. Conflict-free Replicated Data Types (CRDTs) take a different route. They are data structures designed so that &lt;em&gt;any&lt;/em&gt; set of concurrent updates can be merged deterministically, without coordination, with the merge function guaranteeing that all replicas converge to the same state. No central authority, no conflict prompts, no lost updates — as long as the structure is built correctly.&lt;/p&gt;</description></item><item><title>MutationObserver cost</title><link>https://vabs.github.io/2026/02/06/mutationobserver-cost/</link><pubDate>Fri, 06 Feb 2026 14:00:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/06/mutationobserver-cost/</guid><description>&lt;h2 id="mutationobserver-is-a-batch-feed-not-a-free-hook"&gt;MutationObserver is a batch feed, not a free hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;MutationObserver&lt;/code&gt; reports DOM changes after they happen. It replaced synchronous mutation events because firing callbacks during every DOM write made layout engines slow and re-entrant. The modern API batches mutation records and delivers them at a microtask checkpoint. That batching is useful, but it can hide large costs until a busy render path suddenly spends milliseconds processing records.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

sequenceDiagram
 participant JS as JavaScript task
 participant DOM as DOM mutations
 participant Q as Mutation record queue
 participant MO as Observer callback
 JS-&gt;&gt;DOM: append/remove/setAttribute
 DOM-&gt;&gt;Q: enqueue records
 JS-&gt;&gt;JS: finish current call stack
 Q-&gt;&gt;MO: deliver at microtask checkpoint
 MO-&gt;&gt;DOM: optional follow-up reads/writes

&lt;/pre&gt;

&lt;p&gt;The important mental model is &amp;ldquo;you pay for what you observe.&amp;rdquo; Broad observation turns DOM churn into record allocation, queueing, callback work, and often secondary DOM queries.&lt;/p&gt;</description></item><item><title>Time slicing</title><link>https://vabs.github.io/2026/02/05/time-slicing/</link><pubDate>Thu, 05 Feb 2026 13:40:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/05/time-slicing/</guid><description>&lt;h2 id="mental-model-share-the-main-thread-with-the-user"&gt;Mental model: share the main thread with the user&lt;/h2&gt;
&lt;p&gt;Time slicing is the renderer&amp;rsquo;s ability to split render work into smaller chunks so the browser can handle input, paint, and higher-priority tasks between chunks. It does not make JavaScript run in parallel. It makes long rendering work cooperative instead of monopolizing the main thread.&lt;/p&gt;
&lt;p&gt;The main thread has many customers: event handlers, style recalculation, layout, painting, timers, network callbacks, and framework rendering. A render that takes 80 milliseconds blocks all of them. Time slicing aims to turn that into several smaller units so a click, keypress, or animation frame can be serviced before the user perceives the page as frozen.&lt;/p&gt;</description></item><item><title>RabbitMQ Dead-Letter Queues &amp; Message Ordering</title><link>https://vabs.github.io/2026/02/05/rabbitmq-dead-letter-queues-and-message-ordering/</link><pubDate>Thu, 05 Feb 2026 13:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/05/rabbitmq-dead-letter-queues-and-message-ordering/</guid><description>&lt;p&gt;RabbitMQ gives you two capabilities that look simple on the surface and turn out to have a lot of depth: dead-letter queues for handling messages that cannot be processed, and message ordering for workloads that depend on sequence. Most teams configure the first one slightly wrong and assume the second is stronger than it is. This post covers how dead-lettering actually works, the retry-loop trap it creates, and the precise conditions under which RabbitMQ does and does not preserve order.&lt;/p&gt;</description></item><item><title>Detached DOM nodes</title><link>https://vabs.github.io/2026/02/05/detached-dom-nodes/</link><pubDate>Thu, 05 Feb 2026 08:35:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/05/detached-dom-nodes/</guid><description>&lt;p&gt;A detached DOM node is a node that is no longer connected to the document tree but is still retained by JavaScript or browser internals. Detached nodes are not automatically leaks. A framework may temporarily hold nodes during reconciliation, an animation library may stage elements before disposal, and a virtual scroller may reuse nodes. They become a leak when the application no longer needs them but something keeps them reachable.&lt;/p&gt;</description></item><item><title>CAP Theorem in Practice</title><link>https://vabs.github.io/2026/02/03/cap-theorem-in-practice/</link><pubDate>Tue, 03 Feb 2026 14:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/03/cap-theorem-in-practice/</guid><description>&lt;p&gt;Almost everyone who works with distributed databases has heard the CAP theorem reduced to a slogan: &amp;ldquo;pick two of consistency, availability, and partition tolerance.&amp;rdquo; That summary is so lossy it is actively harmful. It implies you sit down at design time and choose two letters off a menu. In reality, partition tolerance is not optional, the choice between consistency and availability only matters &lt;em&gt;during&lt;/em&gt; a partition, and the words &amp;ldquo;consistency&amp;rdquo; and &amp;ldquo;availability&amp;rdquo; in CAP mean something narrower and stranger than their everyday usage. This post unpacks what the theorem really says and how it shows up in systems you actually run.&lt;/p&gt;</description></item><item><title>Finite state modeling</title><link>https://vabs.github.io/2026/02/03/finite-state-modeling/</link><pubDate>Tue, 03 Feb 2026 11:45:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/03/finite-state-modeling/</guid><description>&lt;h2 id="mental-model-make-impossible-states-unrepresentable"&gt;Mental model: make impossible states unrepresentable&lt;/h2&gt;
&lt;p&gt;Finite-state modeling is the practice of describing UI behavior as a set of named states and allowed transitions. The point is not academic purity. The point is to stop representing contradictory UI conditions with independent booleans such as &lt;code&gt;isLoading&lt;/code&gt;, &lt;code&gt;hasError&lt;/code&gt;, &lt;code&gt;isDirty&lt;/code&gt;, &lt;code&gt;isSaving&lt;/code&gt;, and &lt;code&gt;isSuccess&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If a form can be both &lt;code&gt;isSaving: true&lt;/code&gt; and &lt;code&gt;hasError: true&lt;/code&gt;, every render branch must guess what that means. A state machine makes the mode explicit: &lt;code&gt;editing&lt;/code&gt;, &lt;code&gt;submitting&lt;/code&gt;, &lt;code&gt;submitFailed&lt;/code&gt;, or &lt;code&gt;submitted&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Idempotent UI actions</title><link>https://vabs.github.io/2026/02/03/idempotent-ui-actions/</link><pubDate>Tue, 03 Feb 2026 09:45:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/03/idempotent-ui-actions/</guid><description>&lt;p&gt;An idempotent UI action can be invoked more than once and still leave the application in the same intended state. Users double-click, mobile browsers retry taps after jank, network clients retry requests, tabs restore after crashes, and optimistic interfaces replay local mutations. If the UI action is not idempotent, those ordinary behaviors become duplicate orders, double votes, repeated messages, or corrupted client state.&lt;/p&gt;
&lt;p&gt;The frontend mental model should mirror distributed systems: every meaningful mutation has an identity, a target state, and a reconciliation path. &amp;ldquo;Add one more&amp;rdquo; is fragile. &amp;ldquo;Set this item to selected for action id X&amp;rdquo; is much easier to retry safely.&lt;/p&gt;</description></item><item><title>Layout thrashing</title><link>https://vabs.github.io/2026/02/03/layout-thrashing/</link><pubDate>Tue, 03 Feb 2026 08:45:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/03/layout-thrashing/</guid><description>&lt;p&gt;Layout thrashing happens when JavaScript repeatedly alternates between writing DOM or style changes and reading layout-dependent values. Each read asks the browser for up-to-date geometry. If there are pending writes, the browser must synchronously recalculate style and layout before returning the value. In a loop, that creates many forced layouts where one batched layout would have been enough.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

flowchart TD
 A[Write style] --&gt; B[Layout marked dirty]
 B --&gt; C[Read offsetWidth]
 C --&gt; D[Forced style and layout]
 D --&gt; E[Write style again]
 E --&gt; B

&lt;/pre&gt;

&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Browsers normally batch rendering work. JavaScript mutates the DOM, then the browser waits until the task ends and prepares the next frame. Layout thrashing defeats that batching by demanding geometry in the middle of mutation work.&lt;/p&gt;</description></item><item><title>Content Security Policy (CSP)</title><link>https://vabs.github.io/2026/02/02/content-security-policy-csp/</link><pubDate>Mon, 02 Feb 2026 09:00:00 -0500</pubDate><guid>https://vabs.github.io/2026/02/02/content-security-policy-csp/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Content Security Policy is a browser-enforced allowlist for what a page may load, execute, embed, connect to, and submit to. Its highest-value use is XSS damage reduction: even if an attacker injects markup, CSP can block inline script, remote script, plugin loads, and data exfiltration paths.&lt;/p&gt;
&lt;p&gt;CSP is not a sanitizer. It is a runtime constraint. Good CSP assumes bugs will happen and makes successful exploitation harder.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 A["HTML response"] --&gt; B["CSP header"]
 B --&gt; C["Browser policy engine"]
 C --&gt; D["script-src"]
 C --&gt; E["connect-src"]
 C --&gt; F["img/style/frame directives"]
 D --&gt; G["Allow nonce/hash scripts"]
 D --&gt; H["Block inline or unknown script"]

&lt;/pre&gt;

&lt;h2 id="internals-that-matter"&gt;Internals that matter&lt;/h2&gt;
&lt;p&gt;A policy is delivered by HTTP header or a meta tag. Prefer headers because they apply earlier and support reporting. Directives fall back to &lt;code&gt;default-src&lt;/code&gt; when absent, but not all directives behave identically. A practical baseline separates script, style, images, fonts, frames, workers, and network connections.&lt;/p&gt;</description></item><item><title>Eventual Consistency Anti-Patterns</title><link>https://vabs.github.io/2026/02/01/eventual-consistency-anti-patterns/</link><pubDate>Sun, 01 Feb 2026 16:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/02/01/eventual-consistency-anti-patterns/</guid><description>&lt;p&gt;Eventual consistency is a deal: you give up the guarantee that a read immediately reflects the latest write, and in exchange you get availability, lower latency, and horizontal scale. It is a perfectly good deal for the right workloads. The trouble starts when teams adopt an eventually consistent store — DynamoDB, Cassandra, an event-driven microservice mesh, a read replica — and then write code as if it were strongly consistent. The bugs that follow are intermittent, environment-dependent, and nearly impossible to reproduce on a developer laptop. This post catalogs the recurring anti-patterns and the patterns that actually work.&lt;/p&gt;</description></item><item><title>Distributed Locking: Redlock Pitfalls</title><link>https://vabs.github.io/2026/01/30/distributed-locking-redlock-pitfalls/</link><pubDate>Fri, 30 Jan 2026 10:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/30/distributed-locking-redlock-pitfalls/</guid><description>&lt;p&gt;Distributed locks are one of those primitives that look trivial until you deploy them. A single-node mutex protects a critical section because the operating system guarantees that only one thread holds it at a time. The moment you spread that critical section across machines, the guarantees you took for granted evaporate. Clocks drift, processes pause, networks partition, and the lock you thought you held has quietly expired and been granted to someone else.&lt;/p&gt;</description></item><item><title>Transferable objects</title><link>https://vabs.github.io/2026/01/29/transferable-objects/</link><pubDate>Thu, 29 Jan 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/29/transferable-objects/</guid><description>&lt;p&gt;Transferable objects are the difference between &amp;ldquo;send this data to a Worker&amp;rdquo; and &amp;ldquo;move ownership of this memory to a Worker.&amp;rdquo; That distinction is critical for large binary payloads. Structured cloning copies data. Transferring detaches the object from the sender and makes the receiver the owner, avoiding a large copy on the hot path.&lt;/p&gt;
&lt;p&gt;The mental model is move semantics for browser concurrency. After transfer, the sender&amp;rsquo;s buffer is intentionally unusable. That can feel surprising in JavaScript because most values are shared by reference or copied by value, but it is exactly what makes transfer cheap.&lt;/p&gt;</description></item><item><title>Garbage collection timing</title><link>https://vabs.github.io/2026/01/27/garbage-collection-timing/</link><pubDate>Tue, 27 Jan 2026 13:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/27/garbage-collection-timing/</guid><description>&lt;p&gt;Garbage collection timing is one of the least deterministic parts of frontend performance. JavaScript gives you automatic memory management, but it does not promise when memory will be reclaimed. That uncertainty matters because collection work can happen during interactions, route transitions, animation, or hydration, and the resulting pauses can look like random jank.&lt;/p&gt;
&lt;p&gt;The practical mental model is reachability. Objects are collectible only when the engine can prove they are no longer reachable from roots: global variables, active stack frames, closures, pending timers, DOM references, event listeners, and internal engine structures. Timing is separate from eligibility. An object can be garbage and still remain in memory until a later collection cycle.&lt;/p&gt;</description></item><item><title>Trusted Types</title><link>https://vabs.github.io/2026/01/26/trusted-types/</link><pubDate>Mon, 26 Jan 2026 14:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/26/trusted-types/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Trusted Types is a browser enforcement layer that moves DOM XSS prevention from &amp;ldquo;remember to sanitize every string&amp;rdquo; to &amp;ldquo;dangerous DOM sinks reject plain strings.&amp;rdquo; It does not sanitize by itself. It forces code to pass values created by approved policies, such as &lt;code&gt;TrustedHTML&lt;/code&gt;, &lt;code&gt;TrustedScript&lt;/code&gt;, or &lt;code&gt;TrustedScriptURL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The goal is to reduce the number of places where XSS can enter. Instead of auditing every &lt;code&gt;innerHTML&lt;/code&gt; assignment, you audit the small set of policies that are allowed to create trusted values.&lt;/p&gt;</description></item><item><title>Two-Phase Commit vs Saga Pattern</title><link>https://vabs.github.io/2026/01/26/two-phase-commit-vs-saga-pattern/</link><pubDate>Mon, 26 Jan 2026 10:33:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/26/two-phase-commit-vs-saga-pattern/</guid><description>&lt;h2 id="the-problem-of-distributed-atomicity"&gt;The problem of distributed atomicity&lt;/h2&gt;
&lt;p&gt;A single database gives you atomic transactions for free: a transfer that debits one account and credits another either fully commits or fully rolls back. The moment that logic spans multiple services or databases — order service, payment service, inventory service — that guarantee vanishes. There is no &lt;code&gt;COMMIT&lt;/code&gt; that spans three databases owned by three teams. You now need a protocol to make several independent commits behave as one logical unit, or to clean up convincingly when they cannot.&lt;/p&gt;</description></item><item><title>Deadlock Detection and Prevention</title><link>https://vabs.github.io/2026/01/24/deadlock-detection-and-prevention/</link><pubDate>Sat, 24 Jan 2026 16:48:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/24/deadlock-detection-and-prevention/</guid><description>&lt;h2 id="the-shape-of-a-deadlock"&gt;The shape of a deadlock&lt;/h2&gt;
&lt;p&gt;A deadlock is the concurrency equivalent of two people in a hallway, each stepping the same direction to let the other pass, forever. Formally, it is a cycle of processes each holding a resource the next one needs. No process can proceed, none will release what it holds, and without intervention they wait indefinitely.&lt;/p&gt;
&lt;p&gt;Deadlocks appear anywhere there is shared, exclusive resource acquisition: database row locks, mutexes in application code, distributed locks across services, file locks. The mechanisms differ, but the theory is universal, and it is worth understanding deeply because deadlock bugs are intermittent, load-dependent, and notoriously hard to reproduce.&lt;/p&gt;</description></item><item><title>Accessibility tree</title><link>https://vabs.github.io/2026/01/24/accessibility-tree/</link><pubDate>Sat, 24 Jan 2026 11:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/24/accessibility-tree/</guid><description>&lt;p&gt;The accessibility tree is the browser&amp;rsquo;s semantic projection of the page. It is derived from the DOM, CSS, native element semantics, ARIA, and computed state, then exposed through platform accessibility APIs. Screen readers, switch devices, voice control, automated accessibility tooling, and browser devtools all depend on this projection.&lt;/p&gt;
&lt;p&gt;The important mental model is that users of assistive technology do not consume your DOM directly. They consume roles, names, descriptions, states, relationships, and actions. A visually polished custom control can be invisible or misleading if its accessibility tree node is wrong.&lt;/p&gt;</description></item><item><title>Reconciliation algorithm</title><link>https://vabs.github.io/2026/01/22/reconciliation-algorithm/</link><pubDate>Thu, 22 Jan 2026 10:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/22/reconciliation-algorithm/</guid><description>&lt;h2 id="mental-model-preserve-identity-where-the-shape-matches"&gt;Mental model: preserve identity where the shape matches&lt;/h2&gt;
&lt;p&gt;Reconciliation is the process of turning a previous UI tree and a next UI tree into the minimal set of renderer operations React cares to compute. It is not a general tree-edit-distance algorithm. React uses practical heuristics: different component types produce different subtrees, and children with stable keys represent stable identity across renders.&lt;/p&gt;
&lt;p&gt;The goal is not theoretical minimum DOM edits; the goal is predictable component identity and fast enough diffing. When type and key match, React can reuse the existing fiber and preserve state. When either changes, React treats the old node as replaced and mounts a new one.&lt;/p&gt;</description></item><item><title>Query Planner and Cost-Based Optimization</title><link>https://vabs.github.io/2026/01/22/query-planner-and-cost-based-optimization/</link><pubDate>Thu, 22 Jan 2026 11:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/22/query-planner-and-cost-based-optimization/</guid><description>&lt;h2 id="from-declarative-to-executable"&gt;From declarative to executable&lt;/h2&gt;
&lt;p&gt;SQL is declarative: you state &lt;em&gt;what&lt;/em&gt; you want, not &lt;em&gt;how&lt;/em&gt; to get it. Between your query and the disk sits one of the most sophisticated pieces of software in a database — the query optimizer — whose job is to transform a logical request into an efficient physical execution plan. For any non-trivial query there are thousands of equivalent plans that differ in cost by orders of magnitude. Choosing well is the difference between a 5ms response and a 5-minute table scan.&lt;/p&gt;</description></item><item><title>IndexedDB</title><link>https://vabs.github.io/2026/01/22/indexeddb/</link><pubDate>Thu, 22 Jan 2026 09:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/22/indexeddb/</guid><description>&lt;h2 id="indexeddb-is-a-transactional-object-store"&gt;IndexedDB is a transactional object store&lt;/h2&gt;
&lt;p&gt;IndexedDB is the browser&amp;rsquo;s built-in durable database for structured client data. It is not localStorage with promises. It is closer to a small transactional database with object stores, indexes, versioned schema upgrades, structured cloning, and browser-managed quota. The API looks unusual because it predates promises and because transactions are tied to the event loop.&lt;/p&gt;
&lt;pre class="mermaid"&gt;

graph TD
 App["application code"] --&gt; DB["IDBDatabase connection"]
 DB --&gt; Tx["transaction: readonly/readwrite"]
 Tx --&gt; Store["object store"]
 Store --&gt; Record["structured cloned records"]
 Store --&gt; Index["secondary indexes"]
 Index --&gt; Cursor["range scans and cursors"]

&lt;/pre&gt;

&lt;p&gt;The core mental model: open a database at a numeric version, create stores and indexes only during upgrade, then do all reads and writes inside transactions. Transactions auto-commit when their request queue drains and the current task finishes.&lt;/p&gt;</description></item><item><title>Critical rendering path</title><link>https://vabs.github.io/2026/01/21/critical-rendering-path/</link><pubDate>Wed, 21 Jan 2026 10:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/21/critical-rendering-path/</guid><description>&lt;p&gt;The critical rendering path is the sequence of browser work required to turn bytes into pixels. It starts with the network response and ends with a frame on screen. The useful part of the model is that each stage can block or invalidate later stages: HTML creates the DOM, CSS creates the CSSOM, both combine into a render tree, layout computes geometry, paint records drawing commands, and compositing places layers on screen.&lt;/p&gt;</description></item><item><title>B-tree vs LSM-tree Index Internals</title><link>https://vabs.github.io/2026/01/19/b-tree-vs-lsm-tree-index-internals/</link><pubDate>Mon, 19 Jan 2026 15:18:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/19/b-tree-vs-lsm-tree-index-internals/</guid><description>&lt;h2 id="two-answers-to-the-same-question"&gt;Two answers to the same question&lt;/h2&gt;
&lt;p&gt;Every storage engine has to answer one question: given a key, how do I find its value on disk quickly, and how do I keep that structure efficient as data changes? For decades the answer was the B-tree, the structure beneath PostgreSQL, MySQL&amp;rsquo;s InnoDB, and nearly every relational database. Then the write-heavy era — logging, time series, event streams — made a different answer attractive: the Log-Structured Merge-tree (LSM-tree), which powers RocksDB, Cassandra, LevelDB, and ScyllaDB.&lt;/p&gt;</description></item><item><title>DOM clobbering</title><link>https://vabs.github.io/2026/01/19/dom-clobbering/</link><pubDate>Mon, 19 Jan 2026 11:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/19/dom-clobbering/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;DOM clobbering is a browser legacy behavior where elements with certain &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;name&lt;/code&gt; attributes become properties on global objects like &lt;code&gt;window&lt;/code&gt;, &lt;code&gt;document&lt;/code&gt;, or forms. If application code expects &lt;code&gt;window.config&lt;/code&gt; to be a trusted object, injected markup like &lt;code&gt;&amp;lt;form id=&amp;quot;config&amp;quot;&amp;gt;&lt;/code&gt; may replace that lookup with an element.&lt;/p&gt;
&lt;p&gt;This is not the same as executing script. It is a confused-reference bug: attacker-controlled markup changes what a variable resolves to. The impact depends on how that reference is used. If clobbered data becomes a URL, sanitizer option, feature flag, or script source, it can become a real security vulnerability.&lt;/p&gt;</description></item><item><title>Event sourcing in frontend</title><link>https://vabs.github.io/2026/01/19/event-sourcing-in-frontend/</link><pubDate>Mon, 19 Jan 2026 09:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/19/event-sourcing-in-frontend/</guid><description>&lt;h2 id="mental-model-state-is-a-projection"&gt;Mental model: state is a projection&lt;/h2&gt;
&lt;p&gt;Event sourcing on the frontend means the primary record of change is an append-only event stream, and the UI state is a projection derived from that stream. Instead of storing only &lt;code&gt;currentCart&lt;/code&gt;, you store facts such as &lt;code&gt;ItemAdded&lt;/code&gt;, &lt;code&gt;QuantityChanged&lt;/code&gt;, and &lt;code&gt;CouponRemoved&lt;/code&gt;, then fold them into the current view model.&lt;/p&gt;
&lt;p&gt;This is not the right default for every app. It earns its complexity when you need undo/redo, auditability, collaborative reconciliation, offline replay, or deterministic debugging. If the app is mostly forms submitted once, a normal normalized store is easier.&lt;/p&gt;</description></item><item><title>OffscreenCanvas</title><link>https://vabs.github.io/2026/01/18/offscreencanvas/</link><pubDate>Sun, 18 Jan 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/18/offscreencanvas/</guid><description>&lt;p&gt;&lt;code&gt;OffscreenCanvas&lt;/code&gt; moves canvas rendering away from the main thread. That matters when canvas work competes with input handling, layout, style recalculation, framework updates, and accessibility tree changes. The goal is not automatically higher frame rates; the goal is isolating expensive drawing so the main thread can stay responsive. A canvas can still be slow in a Worker, but its slowness no longer blocks a text input or a route transition as directly.&lt;/p&gt;</description></item><item><title>ACID vs BASE Trade-offs</title><link>https://vabs.github.io/2026/01/17/acid-vs-base-trade-offs/</link><pubDate>Sat, 17 Jan 2026 13:27:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/17/acid-vs-base-trade-offs/</guid><description>&lt;h2 id="two-philosophies-of-data"&gt;Two philosophies of data&lt;/h2&gt;
&lt;p&gt;When a system stores data that multiple clients read and write, it must make promises about what they will see. ACID and BASE are two opposing sets of promises. ACID — Atomicity, Consistency, Isolation, Durability — is the relational tradition: the database guarantees correctness even under concurrency and failure, and the application can largely ignore the messy middle. BASE — Basically Available, Soft state, Eventually consistent — emerged from web-scale systems that found ACID&amp;rsquo;s guarantees too expensive at planetary scale and chose to relax them in exchange for availability and horizontal scalability.&lt;/p&gt;</description></item><item><title>PerformanceObserver API</title><link>https://vabs.github.io/2026/01/16/performanceobserver-api/</link><pubDate>Fri, 16 Jan 2026 10:40:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/16/performanceobserver-api/</guid><description>&lt;p&gt;&lt;code&gt;PerformanceObserver&lt;/code&gt; is the browser&amp;rsquo;s streaming interface for performance timeline entries. Instead of polling &lt;code&gt;performance.getEntriesByType()&lt;/code&gt;, you subscribe to entry types and receive batches as the browser records them. That makes it the foundation for production measurement of navigation timing, resource timing, paint timing, layout shifts, long tasks, event timing, and custom marks.&lt;/p&gt;
&lt;p&gt;The key mental model is that the browser maintains performance timelines. Different subsystems append entries to those timelines. &lt;code&gt;PerformanceObserver&lt;/code&gt; lets your code consume those entries asynchronously without blocking the subsystem that produced them.&lt;/p&gt;</description></item><item><title>ARIA live regions internals</title><link>https://vabs.github.io/2026/01/16/aria-live-regions-internals/</link><pubDate>Fri, 16 Jan 2026 10:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/16/aria-live-regions-internals/</guid><description>&lt;p&gt;ARIA live regions are a bridge between DOM mutation and assistive technology announcement queues. They look deceptively small: add &lt;code&gt;aria-live=&amp;quot;polite&amp;quot;&lt;/code&gt; and update text. In real interfaces, they are a timing-sensitive contract across your framework renderer, the browser accessibility tree, platform accessibility APIs, and the screen reader&amp;rsquo;s own queueing rules.&lt;/p&gt;
&lt;p&gt;The mental model: a live region is not &amp;ldquo;read this element.&amp;rdquo; It is &amp;ldquo;when this already-known region changes, expose an announcement-worthy delta.&amp;rdquo; That means the region should exist before the update, the mutation should be meaningful, and repeated updates need throttling.&lt;/p&gt;</description></item><item><title>Database Transaction Isolation Levels: Serializable vs Snapshot</title><link>https://vabs.github.io/2026/01/16/database-transaction-isolation-levels-serializable-vs-snapshot/</link><pubDate>Fri, 16 Jan 2026 09:42:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/16/database-transaction-isolation-levels-serializable-vs-snapshot/</guid><description>&lt;h2 id="why-isolation-levels-exist"&gt;Why isolation levels exist&lt;/h2&gt;
&lt;p&gt;A database that ran every transaction one at a time would be trivially correct and uselessly slow. Real systems interleave transactions to keep CPUs and disks busy, and that interleaving is where correctness goes to die. Isolation levels are the contract the database offers about &lt;em&gt;which&lt;/em&gt; concurrency anomalies you are allowed to observe. Pick a weaker level and you trade some correctness guarantees for throughput; pick a stronger one and you pay in aborts, latency, or lock contention.&lt;/p&gt;</description></item><item><title>Render blocking resources</title><link>https://vabs.github.io/2026/01/14/render-blocking-resources/</link><pubDate>Wed, 14 Jan 2026 09:10:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/14/render-blocking-resources/</guid><description>&lt;p&gt;Render-blocking resources are files the browser must fetch, parse, or execute before it can safely paint useful pixels. The common examples are stylesheets in the document head and synchronous scripts that appear before content. The deeper model is dependency management: the browser is trying to avoid painting a page with incorrect style or running script against a document state that later changes underneath it.&lt;/p&gt;
&lt;p&gt;The cost is not only network time. A stylesheet blocks first paint while it is discovered, downloaded, parsed, and matched against the DOM. A classic script blocks HTML parsing while it downloads and executes, and if that script reads computed style it may also force style and layout work that depends on earlier CSS.&lt;/p&gt;</description></item><item><title>Zero-Downtime Deployment Strategies</title><link>https://vabs.github.io/2026/01/13/zero-downtime-deployment-strategies/</link><pubDate>Tue, 13 Jan 2026 13:05:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/13/zero-downtime-deployment-strategies/</guid><description>&lt;h2 id="what-zero-downtime-actually-requires"&gt;What &amp;ldquo;zero downtime&amp;rdquo; actually requires&lt;/h2&gt;
&lt;p&gt;Zero-downtime deployment means rolling out a new version of a service without any request failing because of the deployment itself. That is a stricter requirement than it sounds. It is not enough to start the new version before stopping the old one. You also have to handle in-flight requests on the instances you are about to kill, keep the load balancer&amp;rsquo;s view of healthy instances accurate, and ensure the database schema is compatible with both the old and new code at every instant during the rollout.&lt;/p&gt;</description></item><item><title>Prototype pollution</title><link>https://vabs.github.io/2026/01/12/prototype-pollution/</link><pubDate>Mon, 12 Jan 2026 10:45:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/12/prototype-pollution/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;Prototype pollution is a JavaScript object graph bug where attacker-controlled input writes properties onto &lt;code&gt;Object.prototype&lt;/code&gt; or another shared prototype. Once polluted, ordinary objects appear to have attacker-chosen defaults. The dangerous part is not the write itself; it is later code that trusts property lookup.&lt;/p&gt;
&lt;p&gt;The classic payload is a nested key like &lt;code&gt;__proto__.isAdmin=true&lt;/code&gt;, &lt;code&gt;constructor.prototype.debug=true&lt;/code&gt;, or JSON shaped to trick a merge function. If a parser or deep merge helper treats those keys as normal object paths, it mutates the prototype chain instead of only the target object.&lt;/p&gt;</description></item><item><title>HTTP/3 and QUIC Packet Loss Recovery</title><link>https://vabs.github.io/2026/01/11/http-3-and-quic-packet-loss-recovery/</link><pubDate>Sun, 11 Jan 2026 16:50:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/11/http-3-and-quic-packet-loss-recovery/</guid><description>&lt;h2 id="why-quic-reinvented-loss-recovery"&gt;Why QUIC reinvented loss recovery&lt;/h2&gt;
&lt;p&gt;HTTP/3 runs over QUIC, and QUIC runs over UDP. UDP gives you nothing: no ordering, no retransmission, no congestion control, no connection concept. QUIC rebuilds all of it in user space, on top of UDP, and in doing so it gets to fix the parts of TCP that were impossible to change because TCP is baked into operating system kernels and middleboxes.&lt;/p&gt;
&lt;p&gt;The most important thing QUIC fixes is the interaction between loss recovery and stream multiplexing. HTTP/2 multiplexes streams over a single TCP connection, but TCP delivers a single, ordered byte stream. If one TCP segment is lost, the kernel holds back every later byte, across all HTTP/2 streams, until the missing segment is retransmitted. That is transport-layer head-of-line blocking, and HTTP/2 cannot escape it because it does not control TCP. QUIC controls its own transport, so it can make loss on one stream affect only that stream.&lt;/p&gt;</description></item><item><title>Service Worker lifecycle traps</title><link>https://vabs.github.io/2026/01/09/service-worker-lifecycle-traps/</link><pubDate>Fri, 09 Jan 2026 10:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/09/service-worker-lifecycle-traps/</guid><description>&lt;h2 id="the-lifecycle-is-a-deployment-protocol"&gt;The lifecycle is a deployment protocol&lt;/h2&gt;
&lt;p&gt;A service worker is not just a background script. It is a versioned proxy that the browser installs, validates, pauses, restarts, and swaps independently from page JavaScript. Most production bugs come from treating it like an immediately loaded bundle. The browser treats it more like an update transaction: a candidate worker installs, waits until old controlled clients go away, then activates and begins handling fetches.&lt;/p&gt;</description></item><item><title>TLS 1.3 Handshake Internals</title><link>https://vabs.github.io/2026/01/08/tls-1-3-handshake-internals/</link><pubDate>Thu, 08 Jan 2026 14:40:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/08/tls-1-3-handshake-internals/</guid><description>&lt;h2 id="what-tls-13-changed-and-why-it-matters"&gt;What TLS 1.3 changed and why it matters&lt;/h2&gt;
&lt;p&gt;TLS 1.3 (RFC 8446) is not an incremental tweak of TLS 1.2. It is a redesign that removed a decade of accumulated insecurity and shaved a full round trip off connection setup. The two headline numbers: a full handshake costs one round trip (1-RTT) instead of two, and resumed connections can send application data immediately (0-RTT). To understand how it achieves this, you need to follow the messages and the key derivation in lockstep.&lt;/p&gt;</description></item><item><title>Optimistic UI rollback strategy</title><link>https://vabs.github.io/2026/01/08/optimistic-ui-rollback-strategy/</link><pubDate>Thu, 08 Jan 2026 10:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/08/optimistic-ui-rollback-strategy/</guid><description>&lt;h2 id="mental-model-speculative-state-with-an-audit-trail"&gt;Mental model: speculative state with an audit trail&lt;/h2&gt;
&lt;p&gt;Optimistic UI is not &amp;ldquo;update the screen before the server responds.&amp;rdquo; That is only the visible part. The useful mental model is speculative execution: the client applies a predicted mutation, records enough context to undo or reconcile it, and later commits, patches, or rolls it back when the authoritative response arrives.&lt;/p&gt;
&lt;p&gt;The mistake is treating optimistic state as a boolean flag. A real rollback strategy needs an operation log. Each optimistic operation should have an id, target entity, before snapshot or inverse patch, predicted after state, request status, and conflict policy. Without that metadata, failures turn into hand-written edge cases scattered across components.&lt;/p&gt;</description></item><item><title>Race conditions in UI state</title><link>https://vabs.github.io/2026/01/08/race-conditions-in-ui-state/</link><pubDate>Thu, 08 Jan 2026 09:30:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/08/race-conditions-in-ui-state/</guid><description>&lt;h2 id="mental-model"&gt;Mental model&lt;/h2&gt;
&lt;p&gt;A UI race condition happens when two or more state transitions are valid in isolation but arrive in an order the user, product, or component did not intend. The browser is single-threaded for most JavaScript, but it is not single-causal. User input, network responses, timers, animation frames, workers, and framework schedulers all enqueue work. The bug is rarely &amp;ldquo;two lines ran at the same time&amp;rdquo;; it is &amp;ldquo;an old result committed after the UI had already moved on.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Fiber architecture</title><link>https://vabs.github.io/2026/01/08/fiber-architecture/</link><pubDate>Thu, 08 Jan 2026 09:20:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/08/fiber-architecture/</guid><description>&lt;h2 id="mental-model-rendering-as-interruptible-work"&gt;Mental model: rendering as interruptible work&lt;/h2&gt;
&lt;p&gt;Fiber is React&amp;rsquo;s internal representation of a component tree and the unit of work used by the renderer. The old stack reconciler behaved like a recursive function call: once rendering started, it ran until the call stack unwound. Fiber turns that stack into a linked data structure that React can pause, resume, discard, and prioritize.&lt;/p&gt;
&lt;p&gt;Think of a fiber node as a work record for one component or host element. It stores the component type, props, state, pending updates, child and sibling links, effects, lanes, and a pointer to the previous committed version. Rendering is not simply &amp;ldquo;call all components&amp;rdquo;; it is building a work-in-progress tree that can later be committed if it still represents the best answer.&lt;/p&gt;</description></item><item><title>Long tasks API</title><link>https://vabs.github.io/2026/01/08/long-tasks-api/</link><pubDate>Thu, 08 Jan 2026 09:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/08/long-tasks-api/</guid><description>&lt;p&gt;The Long Tasks API is a browser performance API for answering a narrow but important question: when was the main thread unavailable long enough for users to feel it? It does not tell you every function call, every layout, or every promise continuation. It reports tasks that block the main thread for more than 50 ms, which is the threshold browsers use to identify work that can delay input handling, rendering, timers, and other user-visible activity.&lt;/p&gt;</description></item><item><title>Pointer events</title><link>https://vabs.github.io/2026/01/08/pointer-events/</link><pubDate>Thu, 08 Jan 2026 09:15:00 -0500</pubDate><guid>https://vabs.github.io/2026/01/08/pointer-events/</guid><description>&lt;p&gt;Pointer Events are the browser&amp;rsquo;s unification layer for mouse, touch, pen, and trackpad-like pointing input. They are not just &amp;ldquo;mouse events with a different name.&amp;rdquo; They expose a stream model that carries device identity, pressure, contact geometry, capture state, cancellation, and compatibility behavior. If you build draggable surfaces, drawing tools, sliders, resizers, maps, or gesture-heavy components, Pointer Events are usually the right primitive.&lt;/p&gt;
&lt;p&gt;The mental model is simple: a pointer is a single active contact. A mouse usually has one persistent pointer. A touchscreen can have many simultaneous pointers. A stylus has one pointer with richer metadata. Your code should track pointer state by &lt;code&gt;pointerId&lt;/code&gt;, not by global booleans such as &lt;code&gt;isDragging&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>WebAssembly integration</title><link>https://vabs.github.io/2026/01/08/webassembly-integration/</link><pubDate>Thu, 08 Jan 2026 09:00:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/08/webassembly-integration/</guid><description>&lt;p&gt;WebAssembly integration is not &amp;ldquo;rewrite the frontend in Rust.&amp;rdquo; In a browser application it is usually a narrow acceleration boundary: JavaScript keeps ownership of UI, routing, networking, storage, and orchestration, while a WebAssembly module owns a small deterministic core such as parsing, image processing, compression, cryptography, simulation, or rules evaluation.&lt;/p&gt;
&lt;p&gt;The useful mental model is a foreign function interface inside the page. Calls cross from JavaScript into a linear memory owned by the module. That crossing has overhead. The module is fast once it is running, but strings, objects, callbacks, and DOM access still live on the JavaScript side. Good integrations therefore minimize crossings and move batches of primitive data through memory.&lt;/p&gt;</description></item><item><title>HTTP/2 Multiplexing and HPACK</title><link>https://vabs.github.io/2026/01/05/http-2-multiplexing-and-hpack/</link><pubDate>Mon, 05 Jan 2026 11:25:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/05/http-2-multiplexing-and-hpack/</guid><description>&lt;h2 id="the-problem-http2-set-out-to-solve"&gt;The problem HTTP/2 set out to solve&lt;/h2&gt;
&lt;p&gt;HTTP/1.1 has a structural flaw: a single TCP connection can carry only one request-response exchange at a time. The connection processes requests strictly in order. If the first response is slow, everything behind it waits. This is head-of-line blocking at the application layer, and it is brutal for modern pages that pull dozens or hundreds of resources.&lt;/p&gt;
&lt;p&gt;Browsers worked around it by opening six or more parallel connections per origin. That helps, but each connection has its own TCP slow start, its own congestion window, and its own setup cost, and the browser still runs out of connections long before it runs out of resources to fetch. Sharding assets across multiple domains to get more connections was a common, ugly hack.&lt;/p&gt;</description></item><item><title>TCP Congestion Control Algorithms</title><link>https://vabs.github.io/2026/01/03/tcp-congestion-control-algorithms/</link><pubDate>Sat, 03 Jan 2026 09:15:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/03/tcp-congestion-control-algorithms/</guid><description>&lt;h2 id="why-congestion-control-exists"&gt;Why congestion control exists&lt;/h2&gt;
&lt;p&gt;A TCP sender has two limits on how fast it can transmit. The first is the receiver&amp;rsquo;s advertised window (rwnd), which protects the receiver&amp;rsquo;s buffer. The second is the congestion window (cwnd), which protects the network. Without the second limit, every sender would dump packets into shared links as fast as the receiver could absorb them, queues would overflow, routers would drop packets en masse, and the whole network would collapse into a state where almost everything retransmits and almost nothing makes progress. That scenario actually happened on the early internet in 1986, and congestion control is the response.&lt;/p&gt;</description></item><item><title>Connection Pooling Pitfalls</title><link>https://vabs.github.io/2026/01/02/connection-pooling-pitfalls/</link><pubDate>Fri, 02 Jan 2026 08:30:00 -0400</pubDate><guid>https://vabs.github.io/2026/01/02/connection-pooling-pitfalls/</guid><description>&lt;h2 id="why-pools-exist-and-why-they-bite"&gt;Why pools exist and why they bite&lt;/h2&gt;
&lt;p&gt;Opening a database connection is expensive. There is a TCP handshake, often a TLS handshake, authentication, and server-side allocation of a backend process or thread plus memory. For Postgres specifically, each connection is a full OS process. Establishing one can take tens of milliseconds, which is catastrophic if you do it per request.&lt;/p&gt;
&lt;p&gt;A connection pool amortizes that cost. The application keeps a set of open connections, hands one to a request that needs it, and returns it to the pool when the request finishes. In the happy path this is invisible. The pitfalls show up under load, during failures, and in the gaps between what the pool thinks is true and what the database actually believes.&lt;/p&gt;</description></item><item><title>Job Search Nightmare</title><link>https://vabs.github.io/2018/12/19/job-search-nightmare/</link><pubDate>Wed, 19 Dec 2018 09:49:35 -0500</pubDate><guid>https://vabs.github.io/2018/12/19/job-search-nightmare/</guid><description>&lt;h2 id="rant-post"&gt;Rant Post&lt;/h2&gt;
&lt;p&gt;I have been looking for opportunities in technology/design sector for a while now. This post entails the pain and suffering which I have faced in last 5 months.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Recruiters only contact you when you are happy at your workplace and when you want to move on, it becomes like screaming in a void and there is no one to listen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The usual sources for finding the opportunities are LinkedIn, Indeed, Glassdoor. Been browsing these websites for months now I have experienced they put in a lot of effort in just dumping the data without proper formatting or analysis. They both suffer from massive user experience issues, but that&amp;rsquo;s for another post. Let the rant begin.&lt;/p&gt;</description></item><item><title>Mule Transaction Management</title><link>https://vabs.github.io/2018/11/09/mule-transaction-management/</link><pubDate>Fri, 09 Nov 2018 14:05:20 -0500</pubDate><guid>https://vabs.github.io/2018/11/09/mule-transaction-management/</guid><description>&lt;h3 id="definition"&gt;Definition&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Defines a context to execute all the steps in a mule flow. The scope enables none or all functionality. If any error occurs in any of the step, the whole flow is reverted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Transactions management in mule has always been a topic of interest for many. It gives the flexibility of using a pre-defined rollback strategy if doing multiple database operations. Though the &lt;code&gt;Transactional&lt;/code&gt; scope is only available when using &lt;code&gt;Database Connector&lt;/code&gt; or &lt;code&gt;JMS connector&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Three Layered Architecture</title><link>https://vabs.github.io/2018/07/05/three-layered-architecture/</link><pubDate>Thu, 05 Jul 2018 21:03:51 -0400</pubDate><guid>https://vabs.github.io/2018/07/05/three-layered-architecture/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Whatever good things we build end up building us.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Taking inspiration from the quote above; API design decisions should be driven by what precisely the API will link and what will be on either side of the interface. The architecture explained in this post is being popularized by Mulesoft API design architecture.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://vabs.github.io/images/post/layered-architecture.png" alt="Layered Architecture"&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s explore this architecture and explain about what is the purpose of each layer and how are they interlinked.&lt;/p&gt;</description></item><item><title>API Design Guidelines</title><link>https://vabs.github.io/2018/06/01/api-design-guidelines/</link><pubDate>Fri, 01 Jun 2018 08:00:22 -0400</pubDate><guid>https://vabs.github.io/2018/06/01/api-design-guidelines/</guid><description>&lt;h1 id="all-good-things-must-come-to-an-api-endpoint"&gt;&lt;code&gt;All good things must come to an api endpoint&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Most of the real world application these days work by calling some sort of API to display or process data. API led connectivity has increased the pace of development. It is very similar to putting lego blocks together to build something useful.&lt;/p&gt;
&lt;p&gt;With the evolution of API, there are 2 major principles which drives the success&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platform Agnostic&lt;/strong&gt;: A client should be able to call the API, regardless of how the API is implemented internally. The complexity should be hidden and the contract between the API and the client should define the mechanism of data exchange.&lt;/p&gt;</description></item><item><title>Canonical Data Model</title><link>https://vabs.github.io/2018/05/30/canonical-data-model/</link><pubDate>Wed, 30 May 2018 21:59:50 -0400</pubDate><guid>https://vabs.github.io/2018/05/30/canonical-data-model/</guid><description>&lt;h3 id="definition"&gt;Definition&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s the model is a design pattern which defines the communication protocol between various enterprise systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With software industry switching focus from monolithic apps to micro-services, there is always a need for the better communication model between each other. Most of the API based connectivity is architect for following proper REST principles and single responsibility. There is not much thought given for the communication model between the services.&lt;/p&gt;
&lt;p&gt;Been in a team of 20 software engineers, I have experienced that every developer has a way to write the definition for the service.&lt;/p&gt;</description></item><item><title>About</title><link>https://vabs.github.io/page/about/</link><pubDate>Tue, 29 May 2018 07:53:53 -0400</pubDate><guid>https://vabs.github.io/page/about/</guid><description>&lt;img src="https://vabs.github.io/images/vaibhav.png" align="left" style="margin:0px 10px 0px 0px" &gt;
&lt;p&gt;Have been working in Software development industry for 7+ years.
Experienced in FinTech and Retail PLM development.&lt;/p&gt;
&lt;p&gt;Currently focussing on API led development and Service Oriented Architecture.&lt;/p&gt;</description></item><item><title>Contact</title><link>https://vabs.github.io/page/contact/</link><pubDate>Mon, 21 May 2018 08:50:06 -0400</pubDate><guid>https://vabs.github.io/page/contact/</guid><description>&lt;p&gt;Have any question, suggestions or jokes ?!?
&lt;br/&gt;
Please contact me at: &lt;a href="mailto:vaibhavsomani@live.in"&gt;&lt;a href="mailto:vaibhavsomani@live.in"&gt;vaibhavsomani@live.in&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>