<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Hongster</title>
    <description>The latest articles on Forem by Hongster (@hongster85).</description>
    <link>https://forem.com/hongster85</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1600971%2Fe50d3487-f18f-404f-85ed-c5618bbd2777.jpeg</url>
      <title>Forem: Hongster</title>
      <link>https://forem.com/hongster85</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hongster85"/>
    <language>en</language>
    <item>
      <title>Critical Rendering Path : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 26 May 2026 14:00:26 +0000</pubDate>
      <link>https://forem.com/hongster85/critical-rendering-path-understand-in-3-minutes-cd</link>
      <guid>https://forem.com/hongster85/critical-rendering-path-understand-in-3-minutes-cd</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Critical Rendering Path&lt;/strong&gt; is the sequence of steps the browser takes to convert HTML, CSS, and JavaScript into pixels on the screen—and the reason your site feels sluggish, even if your code is “correct,” is that every byte you send forces the browser through this pipeline, often blocking the user from seeing anything useful.&lt;/p&gt;

&lt;p&gt;You’ve shipped a fast backend, optimized database queries, and minimized assets, yet the page still takes a second to load. The culprit? The browser can’t paint a single pixel until it finishes parsing, styling, and laying out the page. Understanding the Critical Rendering Path helps you identify exactly which step is causing the delay and what to do about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Think of the Critical Rendering Path like an assembly line in a factory. The browser starts with raw materials (your HTML and CSS), processes each piece step-by-step, and finally outputs a finished product (the visible page). If any station is slow, the entire line stalls.&lt;/p&gt;

&lt;p&gt;Here are the key steps in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DOM (Document Object Model) construction&lt;/strong&gt; – The browser reads HTML and creates a tree of elements. Every &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; becomes a node. This step is blocked until all HTML is parsed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSSOM (CSS Object Model) construction&lt;/strong&gt; – The browser reads CSS (inline, &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;, or linked files) and builds a separate tree of style rules. This step blocks rendering because the browser won’t paint anything until it knows the final styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render Tree construction&lt;/strong&gt; – The browser combines the DOM and CSSOM into a single tree of visible elements. Hidden nodes (&lt;code&gt;display: none&lt;/code&gt;) are excluded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout&lt;/strong&gt; – The browser calculates the exact position and size of each visible element on the page. This is where you pay for complex CSS (e.g., floats, grids, large tables).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paint&lt;/strong&gt; – The browser fills in pixels: text, colors, images, borders. It rasterizes the render tree into actual visual layers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composite&lt;/strong&gt; – The browser combines all painted layers into the final screen image. This step is where transparency, transforms, and &lt;code&gt;opacity&lt;/code&gt; are resolved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; JavaScript can block both DOM and CSSOM construction if it appears before style or script tags that modify the DOM. By default, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags pause the assembly line until the script is fetched and executed.&lt;/p&gt;

&lt;p&gt;The “critical” part refers to the initial paint—the first time the user sees anything. If you can minimize or reorder the steps before that first paint, your page feels instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use the Critical Rendering Path:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’re optimizing page load time for a public-facing site (e.g., landing page, e-commerce product page).
&lt;/li&gt;
&lt;li&gt;You’re debugging why a page flashes a white screen for hundreds of milliseconds.
&lt;/li&gt;
&lt;li&gt;You’re measuring performance with tools like Lighthouse or WebPageTest and see high “Render-Blocking Resources” or “Largest Contentful Paint (LCP)” scores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When &lt;em&gt;not&lt;/em&gt; to focus on it:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app is an internal tool where users accept moderate load times (e.g., a CI dashboard).
&lt;/li&gt;
&lt;li&gt;You’re working on a single-page app that loads once and then navigates via JavaScript (the initial load still matters, but subsequent renders follow a different path).
&lt;/li&gt;
&lt;li&gt;Your bottleneck is clearly on the server side (latency, large images, unoptimized API calls)—fix those first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world use cases:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deferring non-critical CSS using &lt;code&gt;media="print"&lt;/code&gt; or &lt;code&gt;rel="preload"&lt;/code&gt; so the browser doesn’t wait for it to paint.
&lt;/li&gt;
&lt;li&gt;Inlining critical CSS (the styles needed above the fold) into &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; to avoid an extra request.
&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;defer&lt;/code&gt; or &lt;code&gt;async&lt;/code&gt; to &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags to prevent them from blocking DOM and CSSOM construction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why you should care:&lt;/strong&gt; Even a 0.5-second improvement in initial paint can boost conversion rates by 10–20% on e-commerce sites. Users expect pages to be interactive in under 2 seconds, and the Critical Rendering Path is the ultimate gatekeeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before (blocking script blocks paint):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"analytics.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Welcome to the site.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the browser downloads &lt;code&gt;styles.css&lt;/code&gt;, then parses HTML until it hits &lt;code&gt;analytics.js&lt;/code&gt;. It stops to fetch and execute the script (which might modify the DOM or CSSOM). Only after that does it continue parsing and painting. The user waits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After (defer non-blocking script):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Welcome to the site.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"analytics.js"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By moving the script to the bottom and adding &lt;code&gt;defer&lt;/code&gt;, the browser can finish parsing, build the render tree, and paint the first frame before the script ever runs. The user sees “Hello World” immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this demonstrates:&lt;/strong&gt; The position and attribute of a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag directly controls how much the Critical Rendering Path is blocked. Small changes make big performance differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Optimize the Critical Rendering Path by prioritizing the order in which you load HTML, CSS, and JavaScript—reduce blocking resources above the fold, and let everything else load asynchronously.&lt;/strong&gt; For a deeper dive, read Google’s web.dev article on &lt;a href="https://web.dev/critical-rendering-path/" rel="noopener noreferrer"&gt;Critical Rendering Path&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>criticalrenderingpath</category>
      <category>renderblockingresources</category>
      <category>largestcontentfulpaint</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Intersection Observer API : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 21 May 2026 14:00:26 +0000</pubDate>
      <link>https://forem.com/hongster85/intersection-observer-api-understand-in-3-minutes-abk</link>
      <guid>https://forem.com/hongster85/intersection-observer-api-understand-in-3-minutes-abk</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Intersection Observer API&lt;/strong&gt; lets you efficiently detect when an element enters or leaves the viewport (or another parent element). You need this because the old way—listening to scroll events and manually calculating positions—is slow, janky, and wastes battery life on mobile devices. Every time you've built an infinite scroll, lazy-loaded images, or a “when do I animate this?” feature, you've probably either suffered scroll-performance pain or written hacky throttled code. The Intersection Observer gives you a clean, performant, browser-native solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Think of it as a surveillance camera for your webpage. You give the camera (the observer) a target element and say, “Tell me the moment this box enters or leaves the screen (or any other container).” The browser handles the math for you—no manual scroll listeners, no &lt;code&gt;getBoundingClientRect()&lt;/code&gt; in a loop.&lt;/p&gt;

&lt;p&gt;Here’s how the core pieces fit together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observer&lt;/strong&gt;: You create one instance of &lt;code&gt;IntersectionObserver&lt;/code&gt;. It’s your watchtower.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Callback&lt;/strong&gt;: You pass a function that fires every time the &lt;strong&gt;visibility&lt;/strong&gt; of any observed element changes. The callback receives an array of &lt;code&gt;IntersectionObserverEntry&lt;/code&gt; objects—one per observed element that changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thresholds&lt;/strong&gt;: You tell the observer &lt;em&gt;how much&lt;/em&gt; of the element must be visible before it triggers. A single number like &lt;code&gt;0.5&lt;/code&gt; means “fire when at least 50% of the element is visible.” You can also pass an array like &lt;code&gt;[0, 0.25, 0.5, 0.75, 1]&lt;/code&gt; for multiple checkpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root&lt;/strong&gt;: By default, the observer checks against the browser viewport. But you can set a custom &lt;strong&gt;root&lt;/strong&gt;—any scrollable container—so you can track visibility inside a scrollable div.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root Margin&lt;/strong&gt;: Think of it as a buffer zone around the root. Use &lt;code&gt;rootMargin: "100px"&lt;/code&gt; to trigger the callback when the element is &lt;em&gt;100 pixels&lt;/em&gt; outside the viewport—useful for pre-loading content before the user scrolls to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic? The browser runs this in a separate, optimized thread. No blocking main-thread work. Your callback fires only when the intersection state actually changes, not on every pixel scroll.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use the Intersection Observer API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy-loading images or iframes&lt;/strong&gt;: Only fetch the resource when the element is close to entering the viewport. Combine with &lt;code&gt;rootMargin&lt;/code&gt; to start loading early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinite scrolling&lt;/strong&gt;: Detect when a sentinel element (a small invisible div at the bottom of a list) becomes visible, then append more items. Much cleaner than scroll-event hacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ads or analytics&lt;/strong&gt;: Track how long an element was visible or when a user first saw an ad unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations on scroll&lt;/strong&gt;: Trigger a CSS transition or class change when an element enters the viewport. Great for “scroll-triggered fade-ins.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sticky or fixed positioning&lt;/strong&gt;: Know exactly when an element stops being visible and swap to a fixed position.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you need to know the element’s exact X/Y position&lt;/strong&gt; (use &lt;code&gt;getBoundingClientRect()&lt;/code&gt; or &lt;code&gt;ResizeObserver&lt;/code&gt;). Intersection Observer only tells you “it’s intersecting” or “it’s not.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you’re building a parallax effect that needs pixel-level scroll offsets&lt;/strong&gt;. The callback doesn’t fire continuously—only at threshold crossings. For smooth parallax, a scroll-based approach is still better (but use &lt;code&gt;requestAnimationFrame&lt;/code&gt; to throttle).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you need real-time tracking of visibility percentage&lt;/strong&gt; (e.g., a progress bar showing how much of an article is read). You can approximate it with many thresholds, but it’s not a continuous stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why should you care? Because it turns a notoriously expensive, error-prone task into a handful of lines that run in low overhead. Your users get smoother scrolling, your app uses less CPU, and your code becomes more declarative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Here’s how to lazy-load an image when it enters the viewport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// swap placeholder for real URL&lt;/span&gt;
        &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// stop watching after load&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rootMargin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;200px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;           &lt;span class="c1"&gt;// start loading 200px before visible&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.lazy-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s happening? We create an observer that fires when a watched element intersects. Inside the callback, we check &lt;code&gt;entry.isIntersecting&lt;/code&gt;. If true, we set the real &lt;code&gt;src&lt;/code&gt; (stored in a &lt;code&gt;data-src&lt;/code&gt; attribute) and then stop observing that element so we don’t re-trigger. The &lt;code&gt;rootMargin&lt;/code&gt; gives us a head start so images load just before the user scrolls to them. No scroll listener, no &lt;code&gt;getBoundingClientRect()&lt;/code&gt;—the browser does the heavy lifting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stop listening to scroll events for visibility checks—let the browser do it for you.&lt;/strong&gt; The Intersection Observer API is the standard, performant way to know when an element appears or disappears from a container. For a deeper dive, read the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" rel="noopener noreferrer"&gt;MDN documentation on Intersection Observer&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>intersectionobserver</category>
      <category>lazyloading</category>
      <category>scrollanimation</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Web Workers : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 19 May 2026 14:00:27 +0000</pubDate>
      <link>https://forem.com/hongster85/web-workers-understand-in-3-minutes-5gb9</link>
      <guid>https://forem.com/hongster85/web-workers-understand-in-3-minutes-5gb9</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Web Workers&lt;/strong&gt; let you run JavaScript in the background, on a separate thread, so your main page stays responsive. Have you ever clicked a button on a web app and watched the whole page freeze while some heavy logic runs? Or felt that annoying lag while a large dataset gets processed? That frozen feeling happens because JavaScript normally runs everything—UI updates, click handlers, data crunching—on a single thread. Web Workers fix this by handing off the heavy lifting to a background helper, leaving the main thread free to handle user interactions smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Think of your browser tab as a single-lane road. Without Web Workers, every task—rendering a button, parsing a JSON file, animating a chart—has to wait in the same lane. If one task takes too long (say, processing 10,000 records), everything else stalls.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Web Worker&lt;/strong&gt; is like a parallel service lane. You send work to it, it does the job independently, and then it sends the result back. Meanwhile, your main lane keeps flowing with user interactions, animations, and DOM updates.&lt;/p&gt;

&lt;p&gt;Here’s how it works in simple terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You create a Worker&lt;/strong&gt; by pointing it to a separate JavaScript file (e.g., &lt;code&gt;new Worker('worker.js')&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication happens via messages.&lt;/strong&gt; Your main script sends data to the worker using &lt;code&gt;postMessage()&lt;/code&gt;. The worker receives it through a &lt;code&gt;message&lt;/code&gt; event, processes the data, and &lt;code&gt;postMessage&lt;/code&gt;s the result back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The worker has no access to the DOM&lt;/strong&gt; (no &lt;code&gt;document&lt;/code&gt;, no &lt;code&gt;window&lt;/code&gt;). It’s purely for computation. It can use &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;XMLHttpRequest&lt;/code&gt;, and the &lt;code&gt;File API&lt;/code&gt;, but it can’t touch your page or UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple workers&lt;/strong&gt; can run in parallel, but keep in mind each worker gets its own JavaScript engine instance, so it’s not free in terms of memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: &lt;strong&gt;Web Workers are about parallelism, not concurrency.&lt;/strong&gt; They let you offload CPU-heavy work (like image processing, data sorting, or encryption) so your app stays responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use Web Workers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy computation that takes more than ~50ms (e.g., parsing a large CSV, calculating a hash, or generating a complex visualization).&lt;/li&gt;
&lt;li&gt;Real-time data processing in the background (e.g., a chat app that compresses/decompresses messages).&lt;/li&gt;
&lt;li&gt;Running long polling or WebSocket data handling without blocking UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use Web Workers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For quick operations (a few milliseconds). The overhead of creating a worker and serializing data to send it outweighs any benefit.&lt;/li&gt;
&lt;li&gt;For tasks that need DOM access. Workers can’t touch the DOM—you’d have to send results back and update the UI manually.&lt;/li&gt;
&lt;li&gt;For trivial parallel tasks when your app already runs fine. Premature parallelism adds complexity without payoff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why should you care?&lt;/strong&gt; A sluggish app frustrates users and hurts engagement. Web Workers let you deliver smooth, professional experiences even during heavy workloads. If you’ve ever been told “the page freezes when I click Calculate,” Workers are your solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal before/after comparison:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (blocking main thread):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computeHeavyStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bigData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// freezes UI until done&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (with a Web Worker):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bigData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// UI stays smooth&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// worker.js&lt;/span&gt;
&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computeHeavyStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example shows the pattern: you send data, the worker processes it in the background, and only when it’s done do you update the UI. Meanwhile, scrolling, clicking, and animations remain buttery smooth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use Web Workers when you need to keep your UI responsive during CPU-heavy tasks.&lt;/strong&gt; They’re not for every situation, but they’re an essential tool for any app that processes large amounts of data in the browser. For a deeper dive, check out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API" rel="noopener noreferrer"&gt;MDN documentation on Web Workers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webworkers</category>
      <category>javascriptparallelism</category>
      <category>backgroundthreads</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>HTTP/2 vs HTTP/3 : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 14 May 2026 14:01:14 +0000</pubDate>
      <link>https://forem.com/hongster85/http2-vs-http3-understand-in-3-minutes-3pl7</link>
      <guid>https://forem.com/hongster85/http2-vs-http3-understand-in-3-minutes-3pl7</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTTP/2 vs HTTP/3&lt;/strong&gt; is the debate between two major versions of the web’s foundational protocol—the rules that govern how your browser and a server exchange data. You encounter this problem because your web app feels slow on mobile networks, video streams buffer unpredictably, or your team is debating whether to upgrade infrastructure. If you’ve ever debugged a “slow API call” only to find the network itself is the bottleneck, you’ve lived this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Both HTTP/2 and HTTP/3 aim to make web requests faster, but they solve the problem in fundamentally different ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP/2&lt;/strong&gt; introduced &lt;strong&gt;multiplexing&lt;/strong&gt;: it can send multiple requests and responses over a single &lt;strong&gt;TCP connection&lt;/strong&gt;. That’s a huge improvement over HTTP/1.1, which forced browsers to open dozens of parallel connections. But HTTP/2 still runs on &lt;strong&gt;TCP&lt;/strong&gt;, which has a fatal flaw: &lt;strong&gt;head-of-line blocking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine a single-lane highway carrying multiple delivery trucks. If one truck (a lost TCP packet) crashes, every truck behind it must stop and wait for the crash to be cleared. Even though HTTP/2 multiplexes requests, TCP forces them to share that single lane. One dropped packet delays &lt;em&gt;all&lt;/em&gt; simultaneous streams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP/3&lt;/strong&gt; replaces TCP with &lt;strong&gt;QUIC&lt;/strong&gt; (Quick UDP Internet Connections), which runs over &lt;strong&gt;UDP&lt;/strong&gt;. QUIC treats each request as an independent lane on the highway. If one lane has an accident, only that truck slows down—the rest keep flowing.&lt;/p&gt;

&lt;p&gt;Here’s the practical difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2&lt;/strong&gt; multiplexes over TCP → one lost packet blocks everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/3&lt;/strong&gt; multiplexes over QUIC/UDP → lost packets affect only their specific stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QUIC also brings two other game-changers out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0-RTT handshake&lt;/strong&gt; – For repeat connections, data starts flowing immediately (vs. TCP’s multi-round-trip setup).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection migration&lt;/strong&gt; – Switching from Wi-Fi to mobile data doesn’t kill the connection. Your video call doesn’t drop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it this way: HTTP/2 is a fast single-lane road, HTTP/3 is a multi-lane highway where each request gets its own lane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use HTTP/3:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app is mobile-first (users on unreliable 4G/5G networks).&lt;/li&gt;
&lt;li&gt;You serve real-time features (live chat, collaborative editing, gaming).&lt;/li&gt;
&lt;li&gt;You stream video or large assets where packet loss is common.&lt;/li&gt;
&lt;li&gt;You care about first-byte latency (e.g., improving Time to First Byte).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use HTTP/3:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your infrastructure (load balancers, CDNs, firewalls) doesn’t support QUIC yet.&lt;/li&gt;
&lt;li&gt;You work in a tightly controlled corporate network that blocks UDP traffic.&lt;/li&gt;
&lt;li&gt;You’re building for legacy clients that don’t support HTTP/3 (very old browsers or embedded devices).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why should you care?&lt;/strong&gt; If your users face high latency or spotty connections, HTTP/3 can dramatically improve perceived performance without any code changes on your side—it’s a transport-layer upgrade. In practice, most major CDNs and browsers already support it, so enabling it is often a configuration change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Real-world scenario:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You’re loading a page with 100 small assets (images, CSS, scripts) over a mobile network with 2% packet loss.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2&lt;/strong&gt;: The TCP connection sees a lost packet. All 100 assets wait while TCP retransmits that single packet. That’s a delay of ~50-100ms &lt;em&gt;per loss event&lt;/em&gt;. Your page load time jumps from 500ms to 1.5s.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/3&lt;/strong&gt;: Only the stream affected by the lost packet pauses. The other 99 assets continue loading. Your page load time might only increase by 50ms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example demonstrates that &lt;strong&gt;HTTP/3’s independent streams make it dramatically more resilient on lossy networks&lt;/strong&gt;—which is exactly how most mobile users experience the internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTTP/3 over QUIC effectively eliminates the head-of-line blocking problem that still plagues HTTP/2 on unreliable networks.&lt;/strong&gt; If your users are on mobile or poor connections, enabling HTTP/3 is one of the highest-leverage performance improvements you can make—and it requires zero application code changes.&lt;/p&gt;

&lt;p&gt;For deeper investigation, read the &lt;a href="https://datatracker.ietf.org/doc/html/rfc9114" rel="noopener noreferrer"&gt;HTTP/3 specification (RFC 9114)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>http3</category>
      <category>quic</category>
      <category>headoflineblocking</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>TLS/SSL Handshake : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 12 May 2026 14:00:45 +0000</pubDate>
      <link>https://forem.com/hongster85/tlsssl-handshake-understand-in-3-minutes-2fee</link>
      <guid>https://forem.com/hongster85/tlsssl-handshake-understand-in-3-minutes-2fee</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;TLS/SSL Handshake&lt;/strong&gt; is the cryptographic negotiation that happens between a client (like your browser) and a server before any encrypted data is exchanged—and every time you call an HTTPS API, deploy a web app, or debug a certificate error, you’re watching it happen (or fail).&lt;/p&gt;

&lt;p&gt;Imagine typing “&lt;a href="https://api.example.com%E2%80%9D" rel="noopener noreferrer"&gt;https://api.example.com”&lt;/a&gt; in your browser. In the ~100 milliseconds before the page loads, the client and server have already agreed on encryption algorithms, exchanged digital certificates, and generated session keys—without you lifting a finger. As a developer, you encounter this handshake whenever you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure HTTPS for a web server (e.g., Nginx, Apache)&lt;/li&gt;
&lt;li&gt;Set up mTLS for microservice-to-microservice communication&lt;/li&gt;
&lt;li&gt;Debug SSL/TLS errors like &lt;code&gt;ERR_CERT_AUTHORITY_INVALID&lt;/code&gt; or &lt;code&gt;SSL_HANDSHAKE_FAILURE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tune performance because a slow handshake costs users time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve ever wondered “what’s really going on in that initial connection?”, or needed to explain it in a stand-up, this is your 3-minute answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;The TLS/SSL handshake is a &lt;strong&gt;three-phase dance&lt;/strong&gt; that takes place over the TCP connection. Think of it like two strangers meeting in a dark room, each proving their identity and agreeing on a secret code before talking.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hello &amp;amp; Cipher Suite Selection&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The client sends a &lt;code&gt;ClientHello&lt;/code&gt; message listing its supported TLS versions, cipher suites (e.g., &lt;code&gt;TLS_AES_128_GCM_SHA256&lt;/code&gt;), and a random number. The server responds with a &lt;code&gt;ServerHello&lt;/code&gt;, picking the strongest mutually supported version and cipher suite, plus its own random number. &lt;em&gt;They’ve now agreed on the rules of the conversation.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Certificate Exchange &amp;amp; Authentication&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The server sends its &lt;strong&gt;digital certificate&lt;/strong&gt; (signed by a Certificate Authority) and, optionally, a request for the client’s certificate (for mTLS). The client verifies the certificate’s chain, checks expiration, and confirms the domain matches. This step proves the server is who it claims to be. &lt;em&gt;One side has shown ID.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Key Exchange &amp;amp; Finalizing&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Using the two random numbers and the agreed-upon key exchange algorithm (e.g., &lt;strong&gt;Diffie-Hellman&lt;/strong&gt; or &lt;strong&gt;RSA&lt;/strong&gt;), both sides compute a shared &lt;strong&gt;session key&lt;/strong&gt;—without ever sending the key itself over the wire. They then send a &lt;code&gt;Finished&lt;/code&gt; message encrypted with that key. If both sides can decrypt it, the handshake is successful and encrypted data flows. &lt;em&gt;They now share a secret code.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why this matters to you:&lt;/strong&gt; The handshake adds &lt;strong&gt;one round trip&lt;/strong&gt; of latency (in modern TLS 1.3, it’s one round trip plus optional resumption). That’s why you see HTTP/2 and session resumption optimizations—they reuse previously established keys to skip the full dance on repeat visits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When to use it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Any public-facing web service&lt;/strong&gt; that handles sensitive data (passwords, payment info, personal data). Today that’s &lt;strong&gt;every HTTPS site&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal microservice communication&lt;/strong&gt; where you need mutual authentication (mTLS) to prevent rogue services from impersonating legitimate ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API integrations&lt;/strong&gt; with third-party services (e.g., Stripe, GitHub) that require TLS—you’re already using it whether you realize it or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When NOT to use it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development-only environments&lt;/strong&gt; on localhost (e.g., &lt;code&gt;http://localhost:3000&lt;/code&gt;) where a self-signed certificate adds friction with no real security benefit. Tools like &lt;code&gt;mkcert&lt;/code&gt; can help if needed, but don’t force TLS in dev unless testing handshake behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-performance internal networks&lt;/strong&gt; with extremely low-latency requirements and trusted physical isolation. Even then, consider &lt;strong&gt;TLS 1.3&lt;/strong&gt;’s 0-RTT mode to minimize overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legacy systems&lt;/strong&gt; that cannot be updated to support modern TLS 1.2/1.3—but be aware that continuing to use TLS 1.0/1.1 exposes you to known vulnerabilities (e.g., POODLE, BEAST).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why you should care
&lt;/h3&gt;

&lt;p&gt;The handshake is &lt;strong&gt;the single most expensive operation&lt;/strong&gt; in an HTTPS connection. Misconfigured cipher suites, expired certificates, or too many round trips can add hundreds of milliseconds to page loads. As a developer, understanding the handshake helps you &lt;strong&gt;diagnose connectivity issues&lt;/strong&gt; (&lt;code&gt;openssl s_client -connect example.com:443&lt;/code&gt;) and &lt;strong&gt;tune performance&lt;/strong&gt; (e.g., enabling session resumption).&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Here’s a real-world scenario: your web app’s API calls suddenly fail with &lt;code&gt;SSL_ERROR_BAD_CERT_DOMAIN&lt;/code&gt;. Using &lt;code&gt;curl&lt;/code&gt; with verbose output reveals the handshake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://api.example.com/v1/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output, you’d see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*  SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
*  Server certificate:
*    subject: CN=*.example.com
*    start date: Feb 20 00:00:00 2024 GMT
*    expire date: Feb 20 23:59:59 2025 GMT
*    issuer: C=US, O=Let's Encrypt, CN=R3
*  SSL certificate verify ok.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The handshake succeeded: client and server agreed on TLS 1.3, the certificate is valid for &lt;code&gt;*.example.com&lt;/code&gt;, and the key exchange is complete. If instead you see &lt;code&gt;curl: (60) SSL certificate problem: unable to get local issuer certificate&lt;/code&gt;, the handshake failed at the certificate validation step—likely a self-signed or untrusted certificate. This is exactly what you’d debug by examining the handshake flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The TLS/SSL handshake is a one-time cryptographic negotiation that establishes trust and shared encryption keys—and understanding its three phases (hello, certificate, key exchange) is the single most effective way to debug HTTPS failures and optimize connection latency.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For deeper exploration, read the &lt;a href="https://datatracker.ietf.org/doc/html/rfc8446" rel="noopener noreferrer"&gt;TLS 1.3 RFC 8446&lt;/a&gt; or watch a WireShark capture of a live handshake. But for now, you know enough to hold a conversation about it.&lt;/p&gt;

</description>
      <category>tlshandshake</category>
      <category>certificateverification</category>
      <category>keyexchange</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Browser Caching Strategies : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 07 May 2026 14:00:33 +0000</pubDate>
      <link>https://forem.com/hongster85/browser-caching-strategies-understand-in-3-minutes-52hl</link>
      <guid>https://forem.com/hongster85/browser-caching-strategies-understand-in-3-minutes-52hl</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browser Caching Strategies&lt;/strong&gt; are the rules you set to tell a user’s browser how long to keep copies of your site’s files (like images, CSS, JavaScript) before asking for fresh ones. You encounter this problem every time you deploy a new version of your app and users still see the old page, or when you notice your site feels sluggish because every visitor re-downloads the same logo on every page load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Think of browser caching like a lunchbox. You pack food (files) in the morning so you don’t have to go to the cafeteria (your server) every time you’re hungry. The trick is deciding what to pack, how long it stays fresh, and when to swap it out.&lt;/p&gt;

&lt;p&gt;At its heart, caching strategies control two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Freshness&lt;/strong&gt; – How long the browser can use a cached file without asking the server if it’s still valid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt; – A lightweight check the browser can do to ask the server “Is my copy still good?” without downloading the whole file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common strategies use HTTP headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Cache-Control&lt;/code&gt;&lt;/strong&gt; – The modern boss. You set &lt;code&gt;max-age&lt;/code&gt; (seconds) to define freshness. Example: &lt;code&gt;Cache-Control: public, max-age=31536000&lt;/code&gt; tells the browser “keep this file for a year.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/strong&gt; – A fingerprint (hash) of the file. The browser sends the old &lt;code&gt;ETag&lt;/code&gt; with a &lt;code&gt;If-None-Match&lt;/code&gt; request. The server responds “304 Not Modified” if the file hasn’t changed – no download needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/strong&gt; – Similar, but uses a timestamp. Browser sends &lt;code&gt;If-Modified-Since&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: &lt;strong&gt;you don’t have to pick one strategy for everything&lt;/strong&gt;. You can mix them. Short-lived HTML needs a small &lt;code&gt;max-age&lt;/code&gt; (or &lt;code&gt;no-cache&lt;/code&gt;), while long-lived assets like images get huge &lt;code&gt;max-age&lt;/code&gt; plus fingerprinting (e.g., &lt;code&gt;style.abc123.css&lt;/code&gt;). When the file changes, the URL changes, so the cache is automatically invalidated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use browser caching strategies when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have static assets that change infrequently (images, fonts, CSS/JS bundles).&lt;/li&gt;
&lt;li&gt;You want to reduce server load and improve page load time for returning visitors.&lt;/li&gt;
&lt;li&gt;You want to serve a reliable offline experience (progressive web apps).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don’t use aggressive caching when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content changes frequently and unpredictably (real-time dashboards, user-specific data).&lt;/li&gt;
&lt;li&gt;You can’t control cache-busting via file versioning (e.g., you rely on old URLs that must always reflect the latest version).&lt;/li&gt;
&lt;li&gt;You’re building APIs that need immediate correctness – caching headers there can cause stale data nightmares.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common real-world use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SPA with versioned builds&lt;/strong&gt; – Set &lt;code&gt;max-age=1 year&lt;/code&gt; on all assets, but include a content hash in the filename (e.g., &lt;code&gt;app.7f3a2b.js&lt;/code&gt;). On deploy, new hashes mean new URLs → cache is automatically broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image-heavy blog&lt;/strong&gt; – Cache images for a week (&lt;code&gt;max-age=604800&lt;/code&gt;), but use &lt;code&gt;ETag&lt;/code&gt; for validation so you can roll out small edits without forcing full redownloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing landing page&lt;/strong&gt; – Use &lt;code&gt;no-cache&lt;/code&gt; for the HTML (forces revalidation every visit) but aggressively cache the hero image and CSS.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why should you care? Because a well-tuned caching strategy can cut your time-to-interactive by 50–80% on repeat visits, and lower your server bandwidth costs. It’s one of the highest-ROI optimizations you can make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal Node.js/Express server that sets caching headers for static assets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Cache CSS/JS/images for 1 year, with ETag validation&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;etag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// HTML: never cache, always revalidate&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; The &lt;code&gt;/static&lt;/code&gt; route serves your bundled assets with a one-year expiration. Browsers will reuse them without any server round trip – until you change the filename (e.g., via Webpack’s content hash). The homepage HTML uses &lt;code&gt;no-cache&lt;/code&gt;, forcing a quick &lt;code&gt;If-Modified-Since&lt;/code&gt; check every visit, so users always get the latest markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The golden rule:&lt;/strong&gt; Cache static assets with long &lt;code&gt;max-age&lt;/code&gt; and unique filenames; validate dynamic HTML with &lt;code&gt;no-cache&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt;. For a deep dive, start with Google’s &lt;a href="https://web.dev/http-cache/" rel="noopener noreferrer"&gt;HTTP caching guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>browsercaching</category>
      <category>cachecontrol</category>
      <category>etag</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Content Delivery Networks (CDNs) : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 05 May 2026 14:00:31 +0000</pubDate>
      <link>https://forem.com/hongster85/content-delivery-networks-cdns-understand-in-3-minutes-2c6c</link>
      <guid>https://forem.com/hongster85/content-delivery-networks-cdns-understand-in-3-minutes-2c6c</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Content Delivery Network (CDN)&lt;/strong&gt; is a globally distributed network of servers that caches and serves your static content from locations closest to your users. You encounter the need for a CDN the moment your app loads slowly for users on the other side of the world, your origin server starts struggling under traffic spikes, or you hit bandwidth limits just from serving images and scripts. It’s that frustrating feeling when a user in Tokyo blames you for a 5-second page load—while your server sits comfortably in Virginia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;A CDN works by storing copies of your static files (images, CSS, JavaScript, fonts, videos) on hundreds of servers spread across the globe. These servers are called &lt;strong&gt;Points of Presence (PoPs)&lt;/strong&gt; . When a user requests your site, the CDN routes the request to the nearest PoP (geographically) instead of your single origin server. If that PoP already has the file cached, it serves it instantly. If not, it fetches a fresh copy from your origin, caches it for future requests, and delivers it.&lt;/p&gt;

&lt;p&gt;Here are the key pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Edge servers&lt;/strong&gt; – The actual servers in PoPs that store and serve cached content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS routing&lt;/strong&gt; – The CDN’s DNS system automatically resolves the user’s request to the closest edge server based on their IP location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching rules&lt;/strong&gt; – You control what gets cached and for how long using HTTP headers (like &lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;Expires&lt;/code&gt;). Your origin server stays the authoritative source; the CDN is just a smart middle layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; Think of a CDN like a chain of local bookstores. You write one book (your content) and keep the master copy at your publisher’s warehouse (origin server). Instead of every reader traveling to the warehouse, you ship copies to local bookstores around the world. Readers walk to the nearest bookstore—fast, no traffic jams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use a CDN when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your user base is global (even a single other continent justifies it).&lt;/li&gt;
&lt;li&gt;You serve a lot of static assets (images, videos, libraries, fonts).&lt;/li&gt;
&lt;li&gt;You expect traffic spikes (product launches, viral content, Black Friday).&lt;/li&gt;
&lt;li&gt;You want to reduce load on your origin server and save on bandwidth costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don’t use a CDN when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your content is entirely dynamic and personalized per user (e.g., a dashboard that changes every request with no common cacheable elements). CDNs can still accelerate dynamic content via edge compute or API caching, but that’s a more advanced setup.&lt;/li&gt;
&lt;li&gt;Your audience is extremely small and all in one region—standard hosting with a good cache layer might be enough.&lt;/li&gt;
&lt;li&gt;You need real-time, low-latency writes (CDNs are optimized for read-heavy, cache-friendly workloads).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce product images&lt;/strong&gt; – A CDN serves catalog thumbnails instantly, regardless of where the customer shops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video streaming platforms&lt;/strong&gt; – Edge servers buffer and deliver video chunks, reducing buffering and origin load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API responses&lt;/strong&gt; – Cacheable API endpoints (e.g., public product listings) can be served from edge caches, slashing response times.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before CDN:&lt;/strong&gt; A user in Sydney fetches &lt;code&gt;https://your-app.com/styles.css&lt;/code&gt; from your single server in Virginia. RTT (round-trip time) is ~250ms, and the server may need to compress and send the file each time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After CDN:&lt;/strong&gt; You configure a CDN to cache &lt;code&gt;styles.css&lt;/code&gt;. The user’s request goes to a Sydney PoP. The PoP serves the file in &amp;lt;10ms.&lt;/p&gt;

&lt;p&gt;Here’s a simple HTML snippet showing how you reference a CDN-delivered file (using a popular CDN for a front-end library):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Without CDN (self-hosted) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/react.development.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- With CDN (served from nearest edge) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second line automatically routes the user to the nearest edge server hosting that React file—no infrastructure changes on your side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;Use a CDN to dramatically cut global latency and take the heat off your origin server—but only for content that can be cached. Cache aggressively, set proper TTLs, and treat the CDN as a reliable, scalable middle layer you don’t have to manage yourself.&lt;/p&gt;

&lt;p&gt;For deeper learning, check out &lt;a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/" rel="noopener noreferrer"&gt;Cloudflare’s CDN overview&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>contentdeliverynetwork</category>
      <category>edgeservers</category>
      <category>cachingrules</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Hydration in React/Next.js : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 30 Apr 2026 14:00:29 +0000</pubDate>
      <link>https://forem.com/hongster85/hydration-in-reactnextjs-understand-in-3-minutes-3917</link>
      <guid>https://forem.com/hongster85/hydration-in-reactnextjs-understand-in-3-minutes-3917</guid>
      <description>&lt;h2&gt;
  
  
  Hydration in React/Next.js
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem Statement
&lt;/h3&gt;

&lt;p&gt;Hydration is the process where a server-rendered HTML page becomes an interactive React application on the client. You hit this problem when your Next.js page loads instantly (thanks to server-side rendering) but then suddenly flickers, loses state, or feels janky as JavaScript kicks in. Sound familiar? You’ve likely seen the dreaded “hydration mismatch” warning in your console. It happens because the static HTML the server sent doesn’t perfectly match the React tree the browser tries to build. Why does this matter? Because without proper hydration, your app can break functionality like click handlers, form inputs, or third-party widgets that rely on client-side JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Explanation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Hydration is the bridge between static HTML and dynamic React.&lt;/strong&gt; Here’s how it works in three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server sends dry HTML&lt;/strong&gt;: Next.js renders your React components on the server, producing plain HTML with no JavaScript. This HTML is fast to display—users see content immediately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser renders that HTML&lt;/strong&gt;: The browser paints the page. It looks complete, but nothing is interactive yet—no buttons work, no dropdowns open.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React “waters” the HTML&lt;/strong&gt;: React’s JavaScript bundle downloads and runs. React attaches event listeners (like &lt;code&gt;onClick&lt;/code&gt;), initializes component state, and connects the virtual DOM to the existing DOM nodes. This is hydration—React takes the server’s static markup and brings it to life.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The catch? React expects the server-sent HTML structure to exactly match what it would render on the client. If there’s any difference—say, a &lt;code&gt;useEffect&lt;/code&gt; that changes something on mount, or a component that uses &lt;code&gt;window.innerWidth&lt;/code&gt;—React throws a mismatch error and re-renders the whole tree. That’s where performance issues and user-facing glitches start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple analogy&lt;/strong&gt;: Think of a pre-filled form on paper. Server sends you a printed form with all fields filled. Hydration is you taking that paper form, scanning it, and turning it into an editable digital document where you can click buttons and type. If the digital version has a different layout (extra field, missing label), the scan fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Practical Context
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use hydration when you need fast initial page loads and SEO&lt;/strong&gt;, which is almost every server-rendered Next.js app. Hydration is automatic in Next.js for pages using &lt;code&gt;getServerSideProps&lt;/code&gt; or &lt;code&gt;getStaticProps&lt;/code&gt;. You don’t opt in—you opt out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid hydration when your page has no dynamic content at all.&lt;/strong&gt; If every visitor sees exactly the same static marketing page, skip React entirely and use a plain HTML/CSS approach. Also, avoid heavy hydration for pages that rely heavily on client-only data (like dashboards) – consider using &lt;code&gt;next/dynamic&lt;/code&gt; with &lt;code&gt;ssr: false&lt;/code&gt; to skip server rendering entirely for those components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world use cases&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce product pages&lt;/strong&gt;: SEO needs server-rendered content, but “Add to Cart” buttons and image galleries need hydration. Mismatches here cause cart logic to break silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blog with comments&lt;/strong&gt;: Server renders the article; hydration enables live comment submission without a page reload. Mismatch often happens if the server shows a logout button but the client knows the user is logged in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin dashboards&lt;/strong&gt;: You may prefer client-only rendering for authenticated pages to avoid hydration mismatch with user-specific data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why should you care?&lt;/strong&gt; Hydration mismatches cause bugs that are hard to reproduce—they happen only on first load, then disappear on subsequent navigations. They degrade Core Web Vitals (Layout Shifts from re-renders) and user trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Quick Example
&lt;/h3&gt;

&lt;p&gt;Here’s a common hydration mismatch and how to fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Problem: uses client-only data during server render&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This runs only on client – server sends empty name&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Fix: ensure server output matches client initial render&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Same logic, but initial state is 'User' – both sides match&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this demonstrates&lt;/strong&gt;: The server renders &lt;code&gt;&amp;lt;h1&amp;gt;Hello, &amp;lt;/h1&amp;gt;&lt;/code&gt; (empty name). The client tries to build the same, but &lt;code&gt;useEffect&lt;/code&gt; runs and sets &lt;code&gt;name&lt;/code&gt; to a stored value. React detects a difference (&lt;code&gt;''&lt;/code&gt; vs &lt;code&gt;'Alice'&lt;/code&gt;) and throws a hydration mismatch. By initializing &lt;code&gt;useState&lt;/code&gt; with a fallback value that matches server output, you prevent the mismatch. The &lt;code&gt;useEffect&lt;/code&gt; will still update the UI after hydration—but without re-rendering the whole page.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key Takeaway
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Always make your server-rendered output identical to your component’s initial client render&lt;/strong&gt;—ensure &lt;code&gt;useState&lt;/code&gt; default values and any conditions based on &lt;code&gt;typeof window&lt;/code&gt; are consistent. For deeper dives, read &lt;a href="https://react.dev/reference/react-dom/hydrate" rel="noopener noreferrer"&gt;React’s official hydration documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>reacthydration</category>
      <category>nextjs</category>
      <category>hydrationmismatch</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Progressive Web Apps (PWAs) : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 28 Apr 2026 14:00:27 +0000</pubDate>
      <link>https://forem.com/hongster85/progressive-web-apps-pwas-understand-in-3-minutes-3ohc</link>
      <guid>https://forem.com/hongster85/progressive-web-apps-pwas-understand-in-3-minutes-3ohc</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Progressive Web App (PWA)&lt;/strong&gt; is a website that behaves like a native mobile app — it loads instantly, works offline, and can send push notifications — without requiring users to visit an app store. You’ve probably shipped a web app only to hear “it feels sluggish” or “why can’t I use it without internet?” Meanwhile, your product lead wants the engagement of a native app but can’t justify two separate codebases. PWAs bridge that gap, giving you app-like experiences from a single web codebase, but only if you know when and how to use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;A PWA is a website enhanced with three core technologies that together unlock native-like capabilities. Think of it like a Swiss Army knife: your regular website is the blade (content and logic), and the PWA features are the extra tools (offline, push, home screen) that fold out when needed.&lt;/p&gt;

&lt;p&gt;Here’s what makes a PWA work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service Worker&lt;/strong&gt; – A JavaScript file that runs in the background, separate from your web page. It intercepts network requests and acts as a smart cache. When the user has connectivity, it updates cached resources. When offline, it serves the last-known-good version of your app. This is the engine behind offline support and fast loading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web App Manifest&lt;/strong&gt; – A JSON file that tells the browser how your app should look when installed on the home screen. It defines the icon, splash screen, theme color, and display mode (e.g., full-screen). Without this, the user can’t “install” your PWA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS&lt;/strong&gt; – Service workers only run on secure origins (HTTPS). This ensures that the code intercepting network traffic hasn’t been tampered with. Non-negotiable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic happens when a user first visits your site. The browser silently installs the service worker. On subsequent visits, the service worker serves cached assets, making load times near-instant (even on flaky networks). If the user taps “Add to Home Screen,” the manifest kicks in, and your app appears in their app drawer — no store required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy&lt;/strong&gt;: A PWA is like a library book you photocopy. The original (server) might be far away, but you keep a copy in your backpack (cache). You can read it anywhere, even in a tunnel. When you get back to WiFi, you update your copy with new pages (background sync).&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use PWAs when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need offline or poor-network capability (e.g., a news reader, a field-service checklist, a travel guide).&lt;/li&gt;
&lt;li&gt;You want to reduce friction to re-engage users (push notifications + home screen install = higher retention).&lt;/li&gt;
&lt;li&gt;You’re building a content-driven or lightweight app and want to skip the app store approval process.&lt;/li&gt;
&lt;li&gt;You have a web app already and want to improve performance — adding a service worker can be incremental.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don’t use PWAs when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app requires deep device hardware access (Bluetooth, NFC, camera in background) — PWAs still can’t do everything native apps can (though APIs are expanding).&lt;/li&gt;
&lt;li&gt;You need sophisticated background processing (e.g., a fitness tracker recording GPS continuously) — service workers have limited background execution time.&lt;/li&gt;
&lt;li&gt;Your audience heavily relies on iOS — Safari’s PWA support has historically lagged (push notifications only arrived in iOS 16.4, and some features still differ). For enterprise/B2B apps on Android, PWAs are a no-brainer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce&lt;/strong&gt; – Pinterest’s PWA saw a 60% increase in core engagement and 44% increase in user-generated ad revenue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;News/Media&lt;/strong&gt; – The Washington Post’s PWA reduced load time from 4 seconds to &amp;lt;1 second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Travel/Offline-first&lt;/strong&gt; – Trivago’s PWA achieved a 150% increase in user engagement by providing offline hotel search.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why you should care&lt;/strong&gt;: PWAs can boost conversion rates, reduce bounce rates (because pages load fast), and shrink your development and maintenance costs. If your metric is “user action” (click, purchase, read), a PWA often outperforms both a slow website and a minimal native app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Here’s the minimal code to register a service worker — the first step to making any site a PWA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your main script (e.g., app.js)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sw.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SW registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SW failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the corresponding &lt;code&gt;sw.js&lt;/code&gt; (service worker) for offline fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/offline.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it demonstrates&lt;/strong&gt;: The first script checks if the browser supports service workers (modern browsers do), then registers the file &lt;code&gt;sw.js&lt;/code&gt;. The &lt;code&gt;sw.js&lt;/code&gt; intercepts every network request. If the fetch fails (user is offline), it serves a cached &lt;code&gt;offline.html&lt;/code&gt; page instead of showing a browser error. That’s the core of offline resilience — about 10 lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A PWA is not a framework or a rewrite; it’s a progressive enhancement you add to your existing website using a service worker and a manifest.&lt;/strong&gt; You can ship offline support and “installability” incrementally, starting with just a few lines of JavaScript. If you want to dive deeper, read the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers" rel="noopener noreferrer"&gt;MDN guide on service workers&lt;/a&gt; — it covers caching strategies and lifecycle.&lt;/p&gt;

</description>
      <category>progressivewebapp</category>
      <category>serviceworker</category>
      <category>offlinesupport</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Service Workers : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 23 Apr 2026 14:00:28 +0000</pubDate>
      <link>https://forem.com/hongster85/service-workers-understand-in-3-minutes-2m7m</link>
      <guid>https://forem.com/hongster85/service-workers-understand-in-3-minutes-2m7m</guid>
      <description>&lt;h2&gt;
  
  
  Problem Statement
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Service Worker&lt;/strong&gt; is a script that runs in the background of your web browser, separate from your web page, acting as a programmable network proxy. You hit this problem when you need your web app to work offline, load instantly even on slow networks, or send push notifications—things traditional web pages simply can't do. Every developer has faced that moment when a user tabs away, loses signal, and the app becomes a blank white page. Service Workers are the solution to that broken experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Explanation
&lt;/h2&gt;

&lt;p&gt;Think of a Service Worker as a &lt;strong&gt;network traffic manager&lt;/strong&gt; that sits between your web app and the internet. Unlike regular JavaScript that dies when you close the tab, a Service Worker lives on in the browser, listening for events and intercepting network requests even when your page isn't open.&lt;/p&gt;

&lt;p&gt;Here's how it works in three key steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Registration &amp;amp; Installation&lt;/strong&gt;: Your web app tells the browser to register a Service Worker script. The browser installs it in the background, giving you a chance to pre-cache critical assets (HTML, CSS, JS, images) so they're ready for offline use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Activation &amp;amp; Interception&lt;/strong&gt;: Once installed, the Service Worker activates and begins intercepting every network request your app makes. It can respond from its cache, forward to the network, or do a hybrid of both.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lifecycle Control&lt;/strong&gt;: The Service Worker runs on its own thread, completely independent from your UI. It can handle push events, sync data in the background, and even update itself silently when you deploy a new version.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analogy&lt;/strong&gt;: Imagine a smart butler who memorizes your favorite meals. When you ask for one, they check the kitchen (cache) first. If it's there, you get it instantly. If not, they order from the restaurant (network). And if the restaurant is closed (offline), they still serve you from what's already in the kitchen. That's a Service Worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Context
&lt;/h2&gt;

&lt;p&gt;Use Service Workers when you need &lt;strong&gt;reliable performance&lt;/strong&gt; under poor network conditions, &lt;strong&gt;offline functionality&lt;/strong&gt;, or &lt;strong&gt;background capabilities&lt;/strong&gt; like push notifications. They're essential for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Web Apps (PWAs)&lt;/strong&gt; offering offline-first experiences (like a notes app or news reader)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media-heavy sites&lt;/strong&gt; where users expect instant loading from cache (like an image gallery)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time data apps&lt;/strong&gt; that need background sync (like an email client posting drafts when connectivity returns)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't use&lt;/strong&gt; Service Workers for simple static brochure sites where the network is always reliable, or for apps that need to access the DOM (they can't). Also avoid if your user base uses older browsers without HTTPS support (Service Workers require HTTPS or localhost).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why care?&lt;/strong&gt; A Service Worker transforms your web app from "works when online" to "works when human." Users with flaky connections won't abandon your app. And you get push notification superpowers without needing a native app store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Registration - typically in your main page script&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sw.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// sw.js - A simple cache-first strategy&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Try cache first&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Fallback to network&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows the minimal pattern: the &lt;code&gt;fetch&lt;/code&gt; event listener intercepts every request, checks the cache, and only goes to the network as a fallback. Users get instant loading from cache, and the app works offline for anything already visited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Service Workers let you turn your web app into a reliable, offline-capable experience&lt;/strong&gt; without building a native mobile app. Start by adding one to a single route with a cache-first strategy—you'll see instant performance wins. For deeper dives, check out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;MDN Service Worker documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>serviceworker</category>
      <category>offlinefirst</category>
      <category>progressivewebapp</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Logging Best Practices : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Tue, 21 Apr 2026 14:00:57 +0000</pubDate>
      <link>https://forem.com/hongster85/logging-best-practices-understand-in-3-minutes-39f7</link>
      <guid>https://forem.com/hongster85/logging-best-practices-understand-in-3-minutes-39f7</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Problem Statement&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Logging best practices are a set of guiding principles for creating log output that is genuinely useful for troubleshooting and monitoring, rather than just generating noise. You encounter this problem every time you’re staring at a massive, chaotic log file trying to find why a customer’s request failed, or when an "error" alert wakes you up at 2 AM, only to discover it was a minor, expected issue. It’s the pain of having data but no insight, because your logs tell you &lt;em&gt;something&lt;/em&gt; happened, but not &lt;em&gt;why&lt;/em&gt; or &lt;em&gt;in what context&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Core Explanation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Think of good logging like a well-organized detective’s notebook. A bad log is a single, scrawled line: "Saw suspect." A good log provides the structured, essential facts: "Who, What, When, Where, and Why." Implementing logging best practices means intentionally crafting those log entries to be immediately actionable.&lt;/p&gt;

&lt;p&gt;Here’s how it works by focusing on a few key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Structure Your Data:&lt;/strong&gt; Instead of writing long, free-text sentences, log in a structured format like JSON. This turns a log line from &lt;code&gt;"User login failed for john@doe.com"&lt;/code&gt; into machine-readable key-value pairs: &lt;code&gt;{"event": "login_failed", "user": "john@doe.com", "reason": "invalid_password", "ip": "192.168.1.1"}&lt;/code&gt;. This allows you to search, filter, and aggregate logs effortlessly in tools like Elasticsearch or Datadog.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Use Meaningful Log Levels:&lt;/strong&gt; Not everything is an &lt;strong&gt;ERROR&lt;/strong&gt;. Use levels deliberately:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;ERROR:&lt;/strong&gt; A serious failure in the application that needs immediate attention (e.g., a database connection is lost).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;WARN:&lt;/strong&gt; An unexpected event that doesn’t break functionality but might indicate a future problem (e.g., a deprecated API was called).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;INFO:&lt;/strong&gt; High-level events that track normal application flow (e.g., "Order 1234 completed").&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DEBUG:&lt;/strong&gt; Detailed information valuable only during active development or troubleshooting.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Add Context, Not Just Messages:&lt;/strong&gt; Every log entry should include a unique correlation ID (like a request ID) that ties together all logs for a single user transaction across different services. Always include relevant identifiers (user ID, transaction ID, file name) so you can trace the full story of an event.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Practical Context&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You should adopt these practices for any application that runs in a non-local environment, especially production. They are &lt;strong&gt;critical for distributed systems&lt;/strong&gt; (microservices, serverless), where tracing a request across services is impossible without structured, correlated logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When are simpler logs okay?&lt;/strong&gt; For a tiny, personal script you run once, or during the earliest prototyping phase, you can skip the ceremony. The overhead might outweigh the benefit.&lt;/p&gt;

&lt;p&gt;You should care about this because good logs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Slash Debugging Time:&lt;/strong&gt; Find the root cause of production issues in minutes, not hours.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enable Effective Monitoring:&lt;/strong&gt; Power your alerting dashboards so you're alerted on real problems, not noise.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Provide Business Insights:&lt;/strong&gt; Logged events (e.g., &lt;code&gt;"purchase_completed"&lt;/code&gt;) can be analyzed to understand user behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you spend more than a few minutes searching for a problem in your logs, it's time to invest in these practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Quick Example&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s a before-and-after comparison of logging an error in an API endpoint:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (Unstructured, No Context):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to process order&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This tells you a failure occurred, but nothing more. Which order? Why? For whom?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After (Structured &amp;amp; Contextual):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Order processing failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_processing_failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment_gateway_tx_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correlation_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;correlation_id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This single entry provides all the forensic data needed to diagnose the issue, find the user, and trace the request across the system.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your logs are a primary diagnostic tool; treat them with the same care as your code by making them &lt;strong&gt;structured, contextual, and appropriately leveled&lt;/strong&gt; so you can solve problems faster. For a definitive guide, review the &lt;strong&gt;Twelve-Factor App&lt;/strong&gt; methodology’s section on &lt;a href="https://12factor.net/logs" rel="noopener noreferrer"&gt;logs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>loggingbestpractices</category>
      <category>structuredlogging</category>
      <category>loglevels</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Configuration Management : Understand in 3 Minutes</title>
      <dc:creator>Hongster</dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:59 +0000</pubDate>
      <link>https://forem.com/hongster85/configuration-management-understand-in-3-minutes-1n1j</link>
      <guid>https://forem.com/hongster85/configuration-management-understand-in-3-minutes-1n1j</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Problem Statement&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Configuration management&lt;/strong&gt; is the systematic practice of handling the settings, options, and environment variables that your software needs to run, without baking them directly into your code. You encounter this problem every time you need to run the same application in different places—like when your code works perfectly on your laptop with &lt;code&gt;localhost&lt;/code&gt; but crashes in production because the database password is hardcoded, or when a teammate can't run the project because they use a different API key. It’s the mess of manually changing files for each environment, which is tedious and a breeding ground for errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Core Explanation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At its heart, configuration management separates the &lt;strong&gt;"what"&lt;/strong&gt; your app does from the &lt;strong&gt;"where"&lt;/strong&gt; and &lt;strong&gt;"how"&lt;/strong&gt; it runs. Instead of writing &lt;code&gt;database = "localhost"&lt;/code&gt; in your source files, you externalize those values. The system then loads the correct values based on the current context (e.g., development, testing, production).&lt;/p&gt;

&lt;p&gt;Think of it like a recipe. The source code is the list of instructions (sauté, bake, mix). The configuration is the list of ingredients and quantities. You wouldn't rewrite the entire recipe to double it; you just refer to a different ingredient list. Configuration management provides that separate, swappable list.&lt;/p&gt;

&lt;p&gt;It typically involves three key parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Configuration Sources:&lt;/strong&gt; The files, environment variables, or secret vaults where key-value pairs (like &lt;code&gt;DB_HOST&lt;/code&gt;, &lt;code&gt;API_URL&lt;/code&gt;) are stored.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;A Management Tool/Library:&lt;/strong&gt; The code or system that knows how to find, load, validate, and merge these values from different sources into a single, usable set for your application. Examples include simple &lt;code&gt;.env&lt;/code&gt; files with a library like &lt;code&gt;dotenv&lt;/code&gt;, or dedicated tools like &lt;strong&gt;Ansible&lt;/strong&gt;, &lt;strong&gt;Chef&lt;/strong&gt;, or cloud-native services.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Environment Isolation:&lt;/strong&gt; A clear rule that different environments (dev, staging, prod) get entirely different configuration data, even though the code remains identical.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Practical Context&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use configuration management when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You work on a team (everyone needs consistent setups).&lt;/li&gt;
&lt;li&gt;  Your app runs in multiple environments (like your laptop, a CI server, and a production cloud).&lt;/li&gt;
&lt;li&gt;  You use sensitive data (API keys, passwords) that shouldn't be in your source code repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You might &lt;em&gt;not&lt;/em&gt; need a formal system for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A tiny, one-person script that runs in only one place and has no secrets.&lt;/li&gt;
&lt;li&gt;  When the overhead of managing configuration files outweighs the benefit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common real-world use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Database Connections:&lt;/strong&gt; Swapping connection strings between local, test, and production databases automatically.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Feature Flags:&lt;/strong&gt; Turning features on or off for specific users or environments without a code deployment.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Third-Party Service Config:&lt;/strong&gt; Pointing to different external API endpoints (e.g., a sandbox vs. a live payment gateway).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should care because it makes your application more &lt;strong&gt;portable, secure, and less error-prone&lt;/strong&gt;. It’s a foundational practice for reliable deployments and team collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Quick Example&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s a simple before-and-after look at connecting to a database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (Hardcoded - The Problem):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app.py
&lt;/span&gt;&lt;span class="n"&gt;db_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;db_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;supersecret123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Oops, now in git history!
&lt;/span&gt;&lt;span class="nf"&gt;connect_to_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db_password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (With Configuration Management - The Solution):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Loads values from a `.env` file
&lt;/span&gt;&lt;span class="n"&gt;db_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DB_HOST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Value is read from the environment
&lt;/span&gt;&lt;span class="nf"&gt;connect_to_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db_password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env file (NOT committed to git)
&lt;/span&gt;&lt;span class="n"&gt;DB_HOST&lt;/span&gt;=&lt;span class="n"&gt;localhost&lt;/span&gt;
&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt;=&lt;span class="n"&gt;supersecret123&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrates the core principle: &lt;strong&gt;separating secret and environment-specific values from the application source code.&lt;/strong&gt; The code is now environment-agnostic and secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The single most important rule is this: &lt;strong&gt;Your application's configuration should always be separate from its code, allowing you to deploy the same build artifact anywhere.&lt;/strong&gt; If you want to explore a simple, universal starting point, learn about the &lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;12-Factor App methodology for configuration&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>configurationmanagement</category>
      <category>environmentisolation</category>
      <category>twelvefactorapp</category>
      <category>abotwrotethis</category>
    </item>
  </channel>
</rss>
