<?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: Abdullah al Mubin</title>
    <description>The latest articles on Forem by Abdullah al Mubin (@abdullahmubin).</description>
    <link>https://forem.com/abdullahmubin</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%2F686450%2F8f53a410-dbdb-4374-b5f2-4af547df32a9.jpg</url>
      <title>Forem: Abdullah al Mubin</title>
      <link>https://forem.com/abdullahmubin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/abdullahmubin"/>
    <language>en</language>
    <item>
      <title>The Diet Your App Deserves: Tree Shaking vs Dead Code Elimination</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Thu, 07 May 2026 18:43:15 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/the-diet-your-app-deserves-tree-shaking-vs-dead-code-elimination-4a55</link>
      <guid>https://forem.com/abdullahmubin/the-diet-your-app-deserves-tree-shaking-vs-dead-code-elimination-4a55</guid>
      <description>&lt;p&gt;We’ve all done this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install a huge library
&lt;/li&gt;
&lt;li&gt;Use ONE function
&lt;/li&gt;
&lt;li&gt;Ship 300KB of JavaScript &lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;In modern web apps:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Shipping less code = faster apps&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Two terms always come up here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tree Shaking &lt;/li&gt;
&lt;li&gt;Dead Code Elimination (DCE)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They sound similar…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But they work in very different ways.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s break it down with a real-world example so it actually sticks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Problem: Bloated Bundles&lt;/li&gt;
&lt;li&gt;Real-World Scenario: The Overloaded App&lt;/li&gt;
&lt;li&gt;Dead Code Elimination (DCE): The Surgeon&lt;/li&gt;
&lt;li&gt;Tree Shaking: The Gardener&lt;/li&gt;
&lt;li&gt;Why ES Modules Matter&lt;/li&gt;
&lt;li&gt;Key Differences&lt;/li&gt;
&lt;li&gt;How to Make Your Code Shakeable&lt;/li&gt;
&lt;li&gt;Mental Model&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem: Bloated Bundles
&lt;/h2&gt;

&lt;p&gt;Imagine your app loads slowly.&lt;/p&gt;

&lt;p&gt;Users wait…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bounce rate increases&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;You check your bundle:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;500KB JavaScript&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;But your actual logic?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Maybe 50KB&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;So what happened?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unused code is being shipped&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: The Overloaded App
&lt;/h2&gt;

&lt;p&gt;You’re building:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;quickdash.com&lt;/strong&gt; (a dashboard app)&lt;/p&gt;




&lt;p&gt;You install a utility library:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&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;br&gt;
`&lt;/p&gt;

&lt;p&gt;But you only use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
_.debounce()&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  What gets shipped?
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The ENTIRE library&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bigger bundle&lt;/li&gt;
&lt;li&gt;Slower load time&lt;/li&gt;
&lt;li&gt;Worse performance&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;This is where optimization kicks in.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Dead Code Elimination (DCE): The Surgeon
&lt;/h2&gt;

&lt;p&gt;DCE is the classic optimization technique.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;Removes code that will &lt;strong&gt;never run&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
if (false) {&lt;br&gt;
  console.log("This will never run");&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;DCE removes it completely&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Another Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
function unusedFunction() {&lt;br&gt;
  return 42;&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If never called → removed&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Analogy
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;A surgeon removing useless organs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Precise. Logical. Necessary.&lt;/p&gt;




&lt;h3&gt;
  
  
  What DCE Targets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Unreachable code&lt;/li&gt;
&lt;li&gt;Unused variables&lt;/li&gt;
&lt;li&gt;Functions never called&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;It works at &lt;strong&gt;code level&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tree Shaking: The Gardener
&lt;/h2&gt;

&lt;p&gt;Tree Shaking works differently.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Removes &lt;strong&gt;unused imports/modules&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
import { debounce, throttle } from "lodash-es";&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you only use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
debounce()&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;throttle&lt;/code&gt; gets removed&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Analogy
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Shaking a tree so dead leaves fall off&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Only what’s needed stays.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Idea
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Include ONLY what you use&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Works at &lt;strong&gt;module level&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why ES Modules Matter
&lt;/h2&gt;

&lt;p&gt;Tree Shaking depends on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ES6 modules (import/export)&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;Because they are:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Static (analyzable at build time)&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  CommonJS (bad for tree shaking)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
const lib = require("lodash");&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dynamic → bundler can’t analyze usage&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  ES Modules (good)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
import { debounce } from "lodash-es";&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bundler knows exactly what’s used&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Dead Code Elimination&lt;/th&gt;
&lt;th&gt;Tree Shaking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Level&lt;/td&gt;
&lt;td&gt;Code / function&lt;/td&gt;
&lt;td&gt;Module / import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removes&lt;/td&gt;
&lt;td&gt;Unreachable code&lt;/td&gt;
&lt;td&gt;Unused exports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with&lt;/td&gt;
&lt;td&gt;Any JS&lt;/td&gt;
&lt;td&gt;ES Modules only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;After code analysis&lt;/td&gt;
&lt;td&gt;During bundling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to Make Your Code Shakeable
&lt;/h2&gt;

&lt;p&gt;Using a bundler isn’t enough.&lt;/p&gt;

&lt;p&gt;You need to write &lt;strong&gt;shake-friendly code&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Avoid Side Effects
&lt;/h3&gt;

&lt;p&gt;Bad:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
import "./init"; // modifies global state&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bundler won’t remove it&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Good
&lt;/h3&gt;

&lt;p&gt;Mark in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;json&lt;br&gt;
{&lt;br&gt;
  "sideEffects": false&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Use Named Exports
&lt;/h3&gt;

&lt;p&gt;Bad:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
export default {&lt;br&gt;
  a,&lt;br&gt;
  b,&lt;br&gt;
  c&lt;br&gt;
};&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Good:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
export const a = ...&lt;br&gt;
export const b = ...&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bundler can pick only what’s needed&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Import Only What You Need
&lt;/h3&gt;

&lt;p&gt;Bad:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
import _ from "lodash";&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Good:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;br&gt;
import { debounce } from "lodash-es";&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Smaller bundle instantly&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Impact
&lt;/h2&gt;

&lt;p&gt;Without optimization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large JS bundles&lt;/li&gt;
&lt;li&gt;Slow page load&lt;/li&gt;
&lt;li&gt;Poor mobile performance&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;With Tree Shaking + DCE:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller bundles&lt;/li&gt;
&lt;li&gt;Faster load times&lt;/li&gt;
&lt;li&gt;Better user experience&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember just this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DCE&lt;/strong&gt; → Removes code that can’t run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree Shaking&lt;/strong&gt; → Removes code you didn’t import&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DCE cleans inside your code&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Tree Shaking trims your dependencies&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Tree Shaking and DCE are invisible…&lt;/p&gt;

&lt;p&gt;But powerful.&lt;/p&gt;

&lt;p&gt;They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce bundle size&lt;/li&gt;
&lt;li&gt;Improve performance&lt;/li&gt;
&lt;li&gt;Make apps faster&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The fastest code is the code you never ship.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What About You?
&lt;/h2&gt;

&lt;p&gt;Do you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check your bundle size?&lt;/li&gt;
&lt;li&gt;Use tools like Webpack Analyzer?&lt;/li&gt;
&lt;li&gt;Optimize imports?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s discuss in comment...&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Stop Making Users Wait: Streaming SSR Explained with a Real-World Example</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Fri, 01 May 2026 09:52:59 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/stop-making-users-wait-streaming-ssr-explained-with-a-real-world-example-4hk4</link>
      <guid>https://forem.com/abdullahmubin/stop-making-users-wait-streaming-ssr-explained-with-a-real-world-example-4hk4</guid>
      <description>&lt;p&gt;Have you ever clicked a page and just… stared at a blank screen?&lt;/p&gt;

&lt;p&gt;For 2–3 seconds… nothing happens.&lt;/p&gt;

&lt;p&gt;That’s the &lt;strong&gt;old way of Server-Side Rendering (SSR)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The server waits for everything… before sending anything.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But modern apps don’t work like that anymore.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;&lt;em&gt;stream the page in parts&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s break this down using a real-world example you already know:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An e-commerce product page (like Amazon).&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Problem: The All-or-Nothing Bottleneck&lt;/li&gt;
&lt;li&gt;Real-World Scenario: Product Page Loading&lt;/li&gt;
&lt;li&gt;The Solution: Streaming SSR&lt;/li&gt;
&lt;li&gt;How the Page Loads in Chunks&lt;/li&gt;
&lt;li&gt;Code Example (Next.js + Suspense)&lt;/li&gt;
&lt;li&gt;What “Streaming” Actually Means&lt;/li&gt;
&lt;li&gt;Why This Is a Game Changer&lt;/li&gt;
&lt;li&gt;Mental Model&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem: The All-or-Nothing Bottleneck
&lt;/h2&gt;

&lt;p&gt;Traditional SSR works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server gathers ALL data
&lt;/li&gt;
&lt;li&gt;Builds the FULL HTML
&lt;/li&gt;
&lt;li&gt;Sends it to the browser
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Real-Life Analogy
&lt;/h3&gt;

&lt;p&gt;Imagine a restaurant:&lt;/p&gt;

&lt;p&gt;You order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drinks
&lt;/li&gt;
&lt;li&gt;Appetizer
&lt;/li&gt;
&lt;li&gt;Main course
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the restaurant says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We’ll serve everything only when the steak is ready.”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  What Happens?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You sit there doing nothing
&lt;/li&gt;
&lt;li&gt;Table is empty
&lt;/li&gt;
&lt;li&gt;You get frustrated
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Same Problem in SSR
&lt;/h3&gt;

&lt;p&gt;If your page has:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product title
&lt;/li&gt;
&lt;li&gt;Images
&lt;/li&gt;
&lt;li&gt;Basic info
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Slow data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviews
&lt;/li&gt;
&lt;li&gt;Recommendations
&lt;/li&gt;
&lt;li&gt;Personalized content
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The fast data is blocked by slow data&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Blank screen
&lt;/li&gt;
&lt;li&gt;Slow Time To First Byte (TTFB)
&lt;/li&gt;
&lt;li&gt;Poor user experience
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: Product Page Loading
&lt;/h2&gt;

&lt;p&gt;Let’s say a user opens a product page.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Headphones product&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The page needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navbar (fast)
&lt;/li&gt;
&lt;li&gt;Product info (medium)
&lt;/li&gt;
&lt;li&gt;Reviews (slow API)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Traditional SSR waits for ALL of this&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: Streaming SSR &amp;amp; Suspense
&lt;/h2&gt;

&lt;p&gt;Streaming SSR changes everything.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of waiting for everything…&lt;/li&gt;
&lt;li&gt;The server sends HTML in &lt;strong&gt;chunks&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How the Page Loads in Chunks
&lt;/h2&gt;

&lt;p&gt;Here’s what actually happens:&lt;/p&gt;




&lt;h3&gt;
  
  
  Chunk 1: Layout (Instant)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navbar
&lt;/li&gt;
&lt;li&gt;Search bar
&lt;/li&gt;
&lt;li&gt;Page structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Sent immediately&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User feels: “Page is fast”&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Chunk 2: Product Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Product image
&lt;/li&gt;
&lt;li&gt;Price
&lt;/li&gt;
&lt;li&gt;Title
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Loads next&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User can already start browsing&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Chunk 3: Heavy Data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reviews
&lt;/li&gt;
&lt;li&gt;Recommendations
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Loads later&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page keeps growing smoothly&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No blank screen
&lt;/li&gt;
&lt;li&gt;No waiting
&lt;/li&gt;
&lt;li&gt;Progressive loading
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Feels instant&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Example (Next.js + Suspense)
&lt;/h2&gt;

&lt;p&gt;Here’s how you implement this:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&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;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"layout"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Loads instantly */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navbar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Product section */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductHero&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Slow section */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReviewSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Reviews&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;br&gt;
`&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Happening Here?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; creates a &lt;strong&gt;boundary&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;React sends content as it becomes ready&lt;/li&gt;
&lt;li&gt;Fallback UI prevents layout shift&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;You define &lt;em&gt;what can load later&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;React handles &lt;em&gt;how to stream it&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What “Streaming” Actually Means
&lt;/h2&gt;

&lt;p&gt;Streaming doesn’t mean:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Breaking HTML randomly into chunks&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;It means:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sending &lt;strong&gt;logical UI pieces&lt;/strong&gt; as they’re ready&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Under the Hood
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Server keeps HTTP connection open&lt;/li&gt;
&lt;li&gt;React renders components progressively&lt;/li&gt;
&lt;li&gt;Sends HTML + small scripts&lt;/li&gt;
&lt;li&gt;Browser injects content in the right place&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;It’s like &lt;strong&gt;progressive page assembly&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is a Game Changer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Faster First Paint
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Users see something instantly&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Better Perceived Performance
&lt;/h3&gt;

&lt;p&gt;Even if backend is slow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI feels fast&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Better SEO
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Search engines see content earlier&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Selective Hydration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Header becomes interactive first&lt;/li&gt;
&lt;li&gt;Slow parts hydrate later&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Reduced TTFB Impact
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;No more waiting for full page render&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember just this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Old SSR&lt;/strong&gt; = Wait → Send everything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming SSR&lt;/strong&gt; = Send → Continue sending&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;“Render now, stream the rest”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Streaming SSR is not just a performance trick.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;It’s a UX improvement.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blank screens&lt;/li&gt;
&lt;li&gt;Waiting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You give users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instant feedback&lt;/li&gt;
&lt;li&gt;Progressive content&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;The best websites don’t make users wait.&lt;br&gt;
They show something immediately—and improve it over time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What About You?
&lt;/h2&gt;

&lt;p&gt;Are you using &lt;strong&gt;Streaming SSR&lt;/strong&gt; yet?&lt;/p&gt;

&lt;p&gt;Or still relying on traditional SSR?&lt;/p&gt;

&lt;p&gt;Let’s discuss in comment...&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>nextjs</category>
      <category>performance</category>
    </item>
    <item>
      <title>Beyond SSR vs SSG: Partial Prerendering (PPR) Explained with a Real-World Story</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Fri, 01 May 2026 09:30:45 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/beyond-ssr-vs-ssg-partial-prerendering-ppr-explained-with-a-real-world-story-2ibj</link>
      <guid>https://forem.com/abdullahmubin/beyond-ssr-vs-ssg-partial-prerendering-ppr-explained-with-a-real-world-story-2ibj</guid>
      <description>&lt;p&gt;For years, frontend developers have been stuck in an annoying trade-off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSG (Static Site Generation)&lt;/strong&gt;: Fast, but data gets stale
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSR (Server-Side Rendering)&lt;/strong&gt;: Fresh data, but slower
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It always felt like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;“Pick speed OR freshness… you can’t have both.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But what if you didn’t have to choose?&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;Partial Prerendering (PPR)&lt;/strong&gt; comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Problem: Blank Screen vs Spinner Hell&lt;/li&gt;
&lt;li&gt;The Idea: The Swiss Cheese Model&lt;/li&gt;
&lt;li&gt;Real-World Scenario: Buying Concert Tickets&lt;/li&gt;
&lt;li&gt;How PPR Actually Works&lt;/li&gt;
&lt;li&gt;Code Example (Next.js + Suspense)&lt;/li&gt;
&lt;li&gt;Why PPR is a Game Changer&lt;/li&gt;
&lt;li&gt;Mental Model&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem: Blank Screen vs Spinner Hell
&lt;/h2&gt;

&lt;p&gt;Let’s say you're building something like an e-commerce site.&lt;/p&gt;

&lt;p&gt;A user clicks on a product page.&lt;/p&gt;

&lt;p&gt;Now depending on your rendering strategy…&lt;/p&gt;




&lt;h3&gt;
  
  
  ❌ SSR (The Waiting Game)
&lt;/h3&gt;

&lt;p&gt;The server waits to fetch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User name
&lt;/li&gt;
&lt;li&gt;Personalized price
&lt;/li&gt;
&lt;li&gt;Cart count
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then sends the page&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;White screen for 1–2 seconds
&lt;/li&gt;
&lt;li&gt;User thinks: &lt;em&gt;“Is this site slow?”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ❌ CSR (Spinner Chaos)
&lt;/h3&gt;

&lt;p&gt;The page loads instantly…&lt;/p&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Price loads later
&lt;/li&gt;
&lt;li&gt;Cart loads later
&lt;/li&gt;
&lt;li&gt;Recommendations load later
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything appears in pieces&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout shifts
&lt;/li&gt;
&lt;li&gt;Janky experience
&lt;/li&gt;
&lt;li&gt;Feels unpolished
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;So you’re stuck between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blank screen (SSR)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spinner hell (CSR)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Idea: The Swiss Cheese Model
&lt;/h2&gt;

&lt;p&gt;Partial Prerendering solves this beautifully.&lt;/p&gt;

&lt;p&gt;Think of your page like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swiss Cheese&lt;/strong&gt;🧀 &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;solid part (cheese)&lt;/strong&gt; = Static content
&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;holes&lt;/strong&gt; = Dynamic content
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What Happens?
&lt;/h3&gt;

&lt;p&gt;At build time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static parts are pre-rendered
&lt;/li&gt;
&lt;li&gt;Dynamic parts are left as “holes”
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static loads instantly
&lt;/li&gt;
&lt;li&gt;Dynamic content streams in later
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Best of both worlds.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: Buying Concert Tickets
&lt;/h2&gt;

&lt;p&gt;Imagine you're on a ticket booking site during a huge sale.&lt;/p&gt;

&lt;p&gt;50,000 people are trying to buy tickets at the same time.&lt;/p&gt;




&lt;h3&gt;
  
  
  What Loads Instantly (Static Shell)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Artist name
&lt;/li&gt;
&lt;li&gt;Event details
&lt;/li&gt;
&lt;li&gt;Venue map
&lt;/li&gt;
&lt;li&gt;Page layout
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is pre-rendered and served from CDN&lt;/p&gt;




&lt;h3&gt;
  
  
  What Loads Dynamically (The “Holes”)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Remaining ticket count
&lt;/li&gt;
&lt;li&gt;Your personalized price
&lt;/li&gt;
&lt;li&gt;“Buy Now” button state
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What You Experience
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Page appears instantly
&lt;/li&gt;
&lt;li&gt;You can already read and interact
&lt;/li&gt;
&lt;li&gt;Dynamic data fills in smoothly
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Even if the database takes 1 second…&lt;/p&gt;

&lt;p&gt;The page &lt;em&gt;feels&lt;/em&gt; like it loaded in &lt;strong&gt;0.1 seconds&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How PPR Actually Works
&lt;/h2&gt;

&lt;p&gt;Under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static HTML is served immediately
&lt;/li&gt;
&lt;li&gt;Dynamic components are &lt;strong&gt;streamed in later&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;React fills in the gaps without reloading the page
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This is powered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React Suspense&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming rendering&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Example (Next.js + Suspense)
&lt;/h2&gt;

&lt;p&gt;Here’s a simple example:&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&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;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Static content (instant) */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductNavigation&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductDetails&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Dynamic part (hole) */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PriceSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DynamicUserPrice&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Another dynamic part */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RecommendationSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RecommendedProducts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;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;br&gt;
`&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Happening Here?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Static components load immediately&lt;/li&gt;
&lt;li&gt;Suspense creates “holes”&lt;/li&gt;
&lt;li&gt;Fallback UI (skeletons) prevents layout shift&lt;/li&gt;
&lt;li&gt;Data streams in and fills the gaps&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Smooth, fast, and user-friendly&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why PPR is a Game Changer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Instant First Paint
&lt;/h3&gt;

&lt;p&gt;Users see something immediately&lt;br&gt;
→ Feels fast&lt;/p&gt;




&lt;h3&gt;
  
  
  Better SEO
&lt;/h3&gt;

&lt;p&gt;Search engines see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Titles&lt;/li&gt;
&lt;li&gt;Content&lt;/li&gt;
&lt;li&gt;Structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;No waiting for JavaScript&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  No Layout Shift
&lt;/h3&gt;

&lt;p&gt;Skeletons reserve space&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No jumping UI&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Better Perceived Performance
&lt;/h3&gt;

&lt;p&gt;Even if backend is slow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI feels instant&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember just this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSG&lt;/strong&gt; = Everything ready early&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSR&lt;/strong&gt; = Everything waits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PPR&lt;/strong&gt; = Load what you can now, stream the rest&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;PPR = &lt;strong&gt;&lt;em&gt;“Render now, stream later”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Partial Prerendering is a big shift in how we think about rendering.&lt;/p&gt;

&lt;p&gt;It’s not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static vs Dynamic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static + Dynamic together&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;The future of the web isn’t about loading pages.&lt;br&gt;
It’s about making them feel instant.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Do You Think?
&lt;/h2&gt;

&lt;p&gt;Are you planning to try &lt;strong&gt;PPR in your next project&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Or still sticking with SSR/CSR?&lt;/p&gt;

&lt;p&gt;Let’s discuss in comment...&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>javascript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>PostgreSQL Design at Scale: Normalization vs JSONB (A Real-World Guide)</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Tue, 21 Apr 2026 17:00:25 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/postgresql-design-at-scale-normalization-vs-jsonb-a-real-world-guide-21k9</link>
      <guid>https://forem.com/abdullahmubin/postgresql-design-at-scale-normalization-vs-jsonb-a-real-world-guide-21k9</guid>
      <description>&lt;p&gt;When you start building an app, everyone gives the same advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Normalize your database.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And they’re right… at the beginning.&lt;/p&gt;

&lt;p&gt;But once your app starts scaling?&lt;/p&gt;

&lt;p&gt;That same “clean design” can become your biggest bottleneck.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;denormalization (especially JSONB in PostgreSQL)&lt;/strong&gt; becomes a powerful tool.&lt;/p&gt;

&lt;p&gt;Let’s break this down with a real-world example.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Scenario: A High-Traffic Food Delivery App&lt;/li&gt;
&lt;li&gt;Part 1: Normalization — The Clean Approach&lt;/li&gt;
&lt;li&gt;The Problem with JOINs at Scale&lt;/li&gt;
&lt;li&gt;Part 2: Denormalization (JSONB) — The Fast Approach&lt;/li&gt;
&lt;li&gt;Better Query Example (Real-World)&lt;/li&gt;
&lt;li&gt;The Trade-Off (This Is Important)&lt;/li&gt;
&lt;li&gt;When Should You Use JSONB&lt;/li&gt;
&lt;li&gt;When to Use Normalization&lt;/li&gt;
&lt;li&gt;Hybrid Approach&lt;/li&gt;
&lt;li&gt;JSONB Indexing&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Scenario: A High-Traffic Food Delivery App
&lt;/h2&gt;

&lt;p&gt;Imagine you built:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bitedash.com&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Millions of users
&lt;/li&gt;
&lt;li&gt;Millions of orders
&lt;/li&gt;
&lt;li&gt;Heavy traffic during peak hours
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now a user opens:&lt;/p&gt;

&lt;p&gt;“Order History”&lt;/p&gt;

&lt;p&gt;Seems simple, right?&lt;/p&gt;

&lt;p&gt;But under the hood, your database might be struggling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Normalization — The Clean Approach
&lt;/h2&gt;

&lt;p&gt;Normalization is like a &lt;strong&gt;perfectly organized filing system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every piece of data has exactly one place.&lt;/p&gt;




&lt;h2&gt;
  
  
  Typical Schema
&lt;/h2&gt;

&lt;p&gt;You design your database like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;orders&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;order_items&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;products&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;users&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is clean, structured, and reusable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with JOINs at Scale
&lt;/h2&gt;

&lt;p&gt;To show one "Order History" page, PostgreSQL has to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join orders
&lt;/li&gt;
&lt;li&gt;Join order_items
&lt;/li&gt;
&lt;li&gt;Join products
&lt;/li&gt;
&lt;li&gt;Join users
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s a &lt;strong&gt;4-table JOIN&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  At Small Scale
&lt;/h3&gt;

&lt;p&gt;Works perfectly.&lt;/p&gt;




&lt;h3&gt;
  
  
  At Large Scale
&lt;/h3&gt;

&lt;p&gt;When your database grows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orders → 10 million rows
&lt;/li&gt;
&lt;li&gt;Order_items → 50 million rows
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every request now requires expensive JOIN operations&lt;/p&gt;




&lt;h3&gt;
  
  
  The Cost
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High CPU usage
&lt;/li&gt;
&lt;li&gt;Slower queries
&lt;/li&gt;
&lt;li&gt;Increased latency
&lt;/li&gt;
&lt;li&gt;Poor user experience
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Mental Model
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Normalization = Clean but computationally expensive at scale&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Denormalization (JSONB) — The Fast Approach
&lt;/h2&gt;

&lt;p&gt;Now let’s flip the approach.&lt;/p&gt;

&lt;p&gt;Instead of storing data separately…&lt;/p&gt;

&lt;p&gt;Store everything together.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is JSONB?
&lt;/h2&gt;

&lt;p&gt;In PostgreSQL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binary JSON format
&lt;/li&gt;
&lt;li&gt;Faster than plain JSON
&lt;/li&gt;
&lt;li&gt;Supports indexing
&lt;/li&gt;
&lt;li&gt;Efficient querying
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  New Schema
&lt;/h2&gt;

&lt;p&gt;Instead of multiple tables:&lt;/p&gt;

&lt;p&gt;You store everything inside one table:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orders&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With a column:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;order_details (JSONB)&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pizza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Coke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;17.00&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;order_details&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;No JOINs&lt;/li&gt;
&lt;li&gt;Single query&lt;/li&gt;
&lt;li&gt;Extremely fast&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Why It’s Fast
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One row fetch&lt;/li&gt;
&lt;li&gt;No table stitching&lt;/li&gt;
&lt;li&gt;Less CPU work&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Mental Model
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;JSONB = Pre-packaged data ready to serve&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Better Query Example (Real-World)
&lt;/h2&gt;

&lt;p&gt;Let’s say your product team asks:&lt;/p&gt;

&lt;p&gt;“Show all orders where the user bought &lt;em&gt;Pizza&lt;/em&gt; and total is greater than $10”&lt;/p&gt;




&lt;h3&gt;
  
  
  With Normalization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;order_items&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Pizza'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple JOINs&lt;/li&gt;
&lt;li&gt;Large tables&lt;/li&gt;
&lt;li&gt;Slower at scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  With JSONB (use numeric cast for totals)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;order_details&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'total'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;order_details&lt;/span&gt; &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'{"items":[{"name":"Pizza"}]}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  More robust match using jsonb_path_exists (recommended for arrays of objects)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;order_details&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'total'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;jsonb_path_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'$.items[*] ? (@.name == "Pizza")'&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;jsonb_path_exists is more flexible for matching nested arrays/objects than the simple @&amp;gt; containment operator.&lt;/p&gt;




&lt;h3&gt;
  
  
  Add Index for Speed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- GIN index for general JSONB containment/search&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_orders_order_details_gin&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Expression index for numeric total (fast range/greater-than queries)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_orders_total_numeric&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'total'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fast filtering&lt;/li&gt;
&lt;li&gt;No joins&lt;/li&gt;
&lt;li&gt;Efficient queries&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Trade-Off (This Is Important)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Normalization&lt;/th&gt;
&lt;th&gt;JSONB (Denormalization)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read Speed&lt;/td&gt;
&lt;td&gt;Slower (JOINs)&lt;/td&gt;
&lt;td&gt;Very fast (single read)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write Speed&lt;/td&gt;
&lt;td&gt;Faster (small rows)&lt;/td&gt;
&lt;td&gt;Slower (large JSON writes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Integrity&lt;/td&gt;
&lt;td&gt;Strong (FK constraints)&lt;/td&gt;
&lt;td&gt;Risk of inconsistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Efficient&lt;/td&gt;
&lt;td&gt;Larger (data duplication)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no “perfect” solution. It’s always a trade-off.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: When Should You Use JSONB?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use JSONB strategically, not everywhere&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Use JSONB for: “Snapshots of the Past”
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;A user places an order.&lt;/p&gt;

&lt;p&gt;Tomorrow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pizza price changes&lt;/li&gt;
&lt;li&gt;Product name changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you rely on JOINs:&lt;/p&gt;

&lt;p&gt;Old orders will show &lt;strong&gt;new values&lt;/strong&gt; and its Wrong&lt;/p&gt;




&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;Store order as JSONB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Captures exact state at that moment&lt;/li&gt;
&lt;li&gt;Keeps historical data correct&lt;/li&gt;
&lt;li&gt;Makes reads extremely fast&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Accurate history&lt;/li&gt;
&lt;li&gt;Faster dashboards&lt;/li&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 4: When to Use Normalization
&lt;/h2&gt;

&lt;p&gt;Normalization is still critical.&lt;/p&gt;

&lt;p&gt;Use it for &lt;strong&gt;live, changing data&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User accounts&lt;/li&gt;
&lt;li&gt;Passwords&lt;/li&gt;
&lt;li&gt;Emails&lt;/li&gt;
&lt;li&gt;Inventory&lt;/li&gt;
&lt;li&gt;Account balances&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;You need a &lt;strong&gt;single source of truth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You cannot afford:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate data&lt;/li&gt;
&lt;li&gt;Inconsistent updates&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 5: The Hybrid Approach (Best of Both Worlds)
&lt;/h2&gt;

&lt;p&gt;At scale, real systems use &lt;strong&gt;both approaches together&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Example Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users → Normalized&lt;/li&gt;
&lt;li&gt;Products → Normalized&lt;/li&gt;
&lt;li&gt;Orders → JSONB snapshot&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Practical performance note
&lt;/h3&gt;

&lt;p&gt;If you frequently filter by fields inside the JSONB (for example user_id or total), store those as first-class columns too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;orders.user_id (bigint)&lt;/li&gt;
&lt;li&gt;orders.total (numeric)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then keep order_details (JSONB) as the immutable snapshot. This gives you indexable scalars for fast filters/ranges and a JSON snapshot for state and flexible reads.&lt;/p&gt;




&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fast reads&lt;/li&gt;
&lt;li&gt;Data consistency&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro Tip: Indexing JSONB
&lt;/h2&gt;

&lt;p&gt;You can still make JSONB queries fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_order_user_name&lt;/span&gt; 
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;order_details&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'user_name'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast search inside JSON&lt;/li&gt;
&lt;li&gt;Works like a normal column index&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine GIN indexes for general JSONB containment with expression indexes for frequently filtered scalars.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Normalization = Clean + consistent&lt;/li&gt;
&lt;li&gt;JSONB = Fast + flexible&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Database design is always a balancing act.&lt;/p&gt;

&lt;p&gt;Early stage:&lt;/p&gt;

&lt;p&gt;Normalize everything&lt;/p&gt;

&lt;p&gt;At scale:&lt;/p&gt;

&lt;p&gt;Denormalize strategically&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best systems aren’t fully normalized or fully denormalized.&lt;br&gt;
They’re carefully designed hybrids.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>database</category>
      <category>performance</category>
      <category>postgres</category>
    </item>
    <item>
      <title>WebRTC vs WebSocket Explained: When to Use What (A Real-World Story)</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sat, 18 Apr 2026 07:06:04 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/webrtc-vs-websocket-explained-when-to-use-what-a-real-world-story-5de9</link>
      <guid>https://forem.com/abdullahmubin/webrtc-vs-websocket-explained-when-to-use-what-a-real-world-story-5de9</guid>
      <description>&lt;p&gt;If you’re building real-time apps, you’ve probably heard of &lt;strong&gt;WebSocket&lt;/strong&gt; and &lt;strong&gt;WebRTC&lt;/strong&gt;. At first, they seem similar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both enable real-time communication
&lt;/li&gt;
&lt;li&gt;Both avoid constant HTTP requests
&lt;/li&gt;
&lt;li&gt;Both feel “live”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in reality? They solve &lt;strong&gt;very different problems&lt;/strong&gt;. Let’s break it down the simplest way possible using a real world story you won’t forget.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scenario: A Remote Team Workspace
&lt;/h2&gt;

&lt;p&gt;Imagine you built a product called &lt;strong&gt;worksync123.com&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your team uses it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chatting
&lt;/li&gt;
&lt;li&gt;Notifications
&lt;/li&gt;
&lt;li&gt;Video meetings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rahim (Engineer) and Aisha (Product Manager) are working together.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Chat System (WebSocket World)
&lt;/h2&gt;

&lt;p&gt;Rahim sends a message:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hey, did you push the latest code?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aisha instantly sees it. No refresh. No delay.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does this work?
&lt;/h3&gt;

&lt;p&gt;Instead of making repeated HTTP requests, the app opens a &lt;strong&gt;persistent connection&lt;/strong&gt;. Think of it like a phone call that stays open, not sending a new letter every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What WebSocket Does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Creates a &lt;strong&gt;continuous connection&lt;/strong&gt; between client and server
&lt;/li&gt;
&lt;li&gt;Allows &lt;strong&gt;instant two-way communication&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Server can push updates anytime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat apps
&lt;/li&gt;
&lt;li&gt;Notifications
&lt;/li&gt;
&lt;li&gt;Live dashboards
&lt;/li&gt;
&lt;li&gt;Multiplayer game state&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Simple Code Idea
&lt;/h3&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;socket&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;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://worksync123.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;socket&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;event&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;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="s2"&gt;New message:&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="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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from Rahim&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mental Model
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WebSocket = Live messaging pipe between client and server&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Video Meeting (WebRTC World)
&lt;/h2&gt;

&lt;p&gt;Now Rahim clicks “Start Meeting”. Aisha joins the same room. They turn on cameras.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does WebSocket handle this?
&lt;/h3&gt;

&lt;p&gt;No. Because video is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy
&lt;/li&gt;
&lt;li&gt;Continuous
&lt;/li&gt;
&lt;li&gt;Requires low latency
&lt;/li&gt;
&lt;li&gt;Needs direct peer connection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  WebRTC Enters
&lt;/h3&gt;

&lt;p&gt;Instead of sending video through the server, &lt;strong&gt;WebRTC connects users directly&lt;/strong&gt;. Think of it like people sitting in the same meeting room rather than passing video through a middle office.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Happens Behind the Scenes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Exchange info via server (signaling)
&lt;/li&gt;
&lt;li&gt;Try direct connection (STUN)
&lt;/li&gt;
&lt;li&gt;Use fallback if needed (TURN)
&lt;/li&gt;
&lt;li&gt;Start streaming video peer-to-peer&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Mental Model
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WebRTC = Direct video/audio pipe between users&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  WebSocket vs WebRTC (Simple Comparison)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;WebSocket&lt;/th&gt;
&lt;th&gt;WebRTC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection Type&lt;/td&gt;
&lt;td&gt;Client ↔ Server&lt;/td&gt;
&lt;td&gt;Peer ↔ Peer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Case&lt;/td&gt;
&lt;td&gt;Data / messages&lt;/td&gt;
&lt;td&gt;Media (video / audio)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Ultra-low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server Load&lt;/td&gt;
&lt;td&gt;High (all data passes through server)&lt;/td&gt;
&lt;td&gt;Low (direct communication)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;TCP-based&lt;/td&gt;
&lt;td&gt;UDP-based (mostly)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Real World Mapping
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Chat Feature
&lt;/h3&gt;

&lt;p&gt;Rahim sends message → Server → Aisha&lt;br&gt;&lt;br&gt;
Uses &lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Call
&lt;/h3&gt;

&lt;p&gt;Rahim camera → Aisha directly&lt;br&gt;&lt;br&gt;
Uses &lt;strong&gt;WebRTC&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How They Work Together (Important)
&lt;/h2&gt;

&lt;p&gt;Here’s the part most beginners miss: &lt;strong&gt;WebRTC still needs WebSocket&lt;/strong&gt; for signaling. WebRTC handles the media stream, but peers must exchange the initial offer/answer and ICE candidates via some signaling channel, commonly WebSocket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combined Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;WebSocket sends:

&lt;ul&gt;
&lt;li&gt;Offer
&lt;/li&gt;
&lt;li&gt;Answer
&lt;/li&gt;
&lt;li&gt;ICE candidates
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WebRTC handles:

&lt;ul&gt;
&lt;li&gt;Actual video/audio streaming&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket = Setup communication&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebRTC = Real time media transfer&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Should You Use WebSocket?
&lt;/h2&gt;

&lt;p&gt;Use WebSocket when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time messaging
&lt;/li&gt;
&lt;li&gt;Notifications
&lt;/li&gt;
&lt;li&gt;Live updates
&lt;/li&gt;
&lt;li&gt;Multiplayer game state
&lt;/li&gt;
&lt;li&gt;Collaborative editing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data is small, frequent, and server-controlled.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use WebRTC?
&lt;/h2&gt;

&lt;p&gt;Use WebRTC when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video calls
&lt;/li&gt;
&lt;li&gt;Voice calls
&lt;/li&gt;
&lt;li&gt;Screen sharing
&lt;/li&gt;
&lt;li&gt;Peer-to-peer file transfer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data is heavy and needs ultra-low latency.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistake
&lt;/h2&gt;

&lt;p&gt;Beginners often think: “I’ll just stream video using WebSocket.”&lt;/p&gt;

&lt;p&gt;Bad idea. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High latency
&lt;/li&gt;
&lt;li&gt;Huge server cost
&lt;/li&gt;
&lt;li&gt;Poor scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always use &lt;strong&gt;WebRTC for media&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Product Architecture
&lt;/h2&gt;

&lt;p&gt;In a real app like &lt;strong&gt;worksync123.com&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;WebSocket handles:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat messages
&lt;/li&gt;
&lt;li&gt;Typing indicators
&lt;/li&gt;
&lt;li&gt;Notifications
&lt;/li&gt;
&lt;li&gt;Signaling for WebRTC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WebRTC handles:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video calls
&lt;/li&gt;
&lt;li&gt;Audio streaming
&lt;/li&gt;
&lt;li&gt;Screen sharing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Tip
&lt;/h2&gt;

&lt;p&gt;Instead of building everything manually, consider using platforms like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LiveKit
&lt;/li&gt;
&lt;li&gt;Agora
&lt;/li&gt;
&lt;li&gt;Twilio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They combine signaling (WebSocket) and media (WebRTC).&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember just this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket = Talking through a server (messages)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebRTC = Talking directly (video/audio)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Think of it like a workplace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat messages go through company servers
&lt;/li&gt;
&lt;li&gt;Meetings happen directly between people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s exactly how modern real-time apps work.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Fri, 17 Apr 2026 18:33:02 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/postgresql-performance-optimization-why-connection-pooling-is-critical-at-scale-27bk</link>
      <guid>https://forem.com/abdullahmubin/postgresql-performance-optimization-why-connection-pooling-is-critical-at-scale-27bk</guid>
      <description>&lt;p&gt;If you’ve ever scaled an app and suddenly your database starts struggling even though your queries are optimized, you’re not alone.&lt;/p&gt;

&lt;p&gt;The issue often isn’t your SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s your connections.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s break this down with a real-world story so it actually sticks.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Scenario: A Busy Food Delivery App&lt;/li&gt;
&lt;li&gt;The Problem Appears&lt;/li&gt;
&lt;li&gt;The Hidden Problem: Too Many Connections&lt;/li&gt;
&lt;li&gt;What Actually Happens&lt;/li&gt;
&lt;li&gt;Do the Math&lt;/li&gt;
&lt;li&gt;The CPU Problem: Context Switching&lt;/li&gt;
&lt;li&gt;Why This Breaks at Scale&lt;/li&gt;
&lt;li&gt;The Solution: Connection Pooling&lt;/li&gt;
&lt;li&gt;Think of It Like a Restaurant Kitchen&lt;/li&gt;
&lt;li&gt;How It Works&lt;/li&gt;
&lt;li&gt;The Magic&lt;/li&gt;
&lt;li&gt;Real Impact&lt;/li&gt;
&lt;li&gt;Deep Dive: Pooling Modes&lt;/li&gt;
&lt;li&gt;Why Transaction Pooling Wins&lt;/li&gt;
&lt;li&gt;PgBouncer vs Odyssey&lt;/li&gt;
&lt;li&gt;Real Architecture (Modern Apps)&lt;/li&gt;
&lt;li&gt;Pro Tip: Double Pooling Strategy&lt;/li&gt;
&lt;li&gt;Common Mistake&lt;/li&gt;
&lt;li&gt;Mental Model&lt;/li&gt;
&lt;li&gt;Final Thought&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Scenario: A Busy Food Delivery App
&lt;/h2&gt;

&lt;p&gt;Imagine you built:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;quickbite.com&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At lunchtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5,000 users open the app
&lt;/li&gt;
&lt;li&gt;They browse menus
&lt;/li&gt;
&lt;li&gt;Place orders
&lt;/li&gt;
&lt;li&gt;Check delivery status
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every action hits your PostgreSQL database.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Appears
&lt;/h2&gt;

&lt;p&gt;Everything works perfectly at low traffic.&lt;/p&gt;

&lt;p&gt;But during peak hours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API response time increases
&lt;/li&gt;
&lt;li&gt;Database CPU usage spikes
&lt;/li&gt;
&lt;li&gt;Memory usage grows rapidly
&lt;/li&gt;
&lt;li&gt;Requests start timing out
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You start wondering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Is my database too slow?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the real problem is something else.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hidden Problem: Too Many Connections
&lt;/h2&gt;

&lt;p&gt;PostgreSQL works differently from many other databases.&lt;/p&gt;

&lt;p&gt;It uses a &lt;strong&gt;process-per-connection model&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  What Actually Happens
&lt;/h3&gt;

&lt;p&gt;Every time your app connects to PostgreSQL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new OS process is created
&lt;/li&gt;
&lt;li&gt;Each process consumes ~10MB–20MB of RAM
&lt;/li&gt;
&lt;li&gt;That process stays alive for the entire connection
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Do the Math
&lt;/h3&gt;

&lt;p&gt;If you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;500 active users → 500 processes
&lt;/li&gt;
&lt;li&gt;Each process uses ~20MB
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s &lt;strong&gt;10GB of RAM consumed&lt;/strong&gt; just for connections  &lt;/p&gt;

&lt;p&gt;And you haven’t even executed a single query yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CPU Problem: Context Switching
&lt;/h2&gt;

&lt;p&gt;Now imagine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hundreds (or thousands) of processes
&lt;/li&gt;
&lt;li&gt;CPU constantly switching between them
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The database spends more time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing processes
&lt;/li&gt;
&lt;li&gt;Than executing actual queries
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Breaks at Scale
&lt;/h2&gt;

&lt;p&gt;In modern systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each API request may open a DB connection
&lt;/li&gt;
&lt;li&gt;Microservices multiply connection counts
&lt;/li&gt;
&lt;li&gt;Autoscaling creates sudden spikes
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suddenly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1,000+ connections hit PostgreSQL at once&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And everything slows down.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Solution: Connection Pooling
&lt;/h1&gt;

&lt;p&gt;Instead of letting every request connect directly to the database…&lt;/p&gt;

&lt;p&gt;Introduce a &lt;strong&gt;middle layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection Pooler (PgBouncer / Odyssey)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Think of It Like a Restaurant Kitchen
&lt;/h2&gt;

&lt;p&gt;Without pooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 customers → 1,000 chefs
&lt;/li&gt;
&lt;li&gt;The kitchen becomes chaotic
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With pooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 customers
&lt;/li&gt;
&lt;li&gt;Only 50 chefs
&lt;/li&gt;
&lt;li&gt;Orders are handled efficiently
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s connection pooling.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Without Pooling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;App → PostgreSQL&lt;br&gt;&lt;br&gt;
(Each request opens a new connection)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Pooling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;App → Pooler → PostgreSQL  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pooler maintains a small pool (50–100 connections)
&lt;/li&gt;
&lt;li&gt;Thousands of users share these connections
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Magic
&lt;/h2&gt;

&lt;p&gt;When a request comes in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pooler borrows a connection
&lt;/li&gt;
&lt;li&gt;Executes the query
&lt;/li&gt;
&lt;li&gt;Returns the connection to the pool
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fast reuse, minimal overhead&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Impact
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Without Connection Pooling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~1000 active database connections
&lt;/li&gt;
&lt;li&gt;~20GB RAM consumed just for connections
&lt;/li&gt;
&lt;li&gt;High CPU usage due to context switching
&lt;/li&gt;
&lt;li&gt;Slower query performance
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  With Connection Pooling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only ~50 active database connections
&lt;/li&gt;
&lt;li&gt;~1GB RAM usage
&lt;/li&gt;
&lt;li&gt;Stable and efficient CPU usage
&lt;/li&gt;
&lt;li&gt;Faster query throughput
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Deep Dive: Pooling Modes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Session Pooling (Basic, but inefficient)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One user = one connection (entire session)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle users hold connections unnecessarily
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You rely on session-specific features
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Transaction Pooling (Best Option)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection is used only during a transaction
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Flow:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BEGIN → query runs
&lt;/li&gt;
&lt;li&gt;COMMIT → connection released
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1000 users can share 50 connections
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Statement Pooling (Extreme Mode)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection released after each query
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-step transactions break
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use only for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-volume, simple read workloads
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Transaction Pooling Wins
&lt;/h2&gt;

&lt;p&gt;Not all users query at the same time  &lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1000 users ≠ 1000 active queries
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pooling takes advantage of this timing gap&lt;/p&gt;




&lt;h2&gt;
  
  
  PgBouncer vs Odyssey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PgBouncer (Most Common)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple and lightweight
&lt;/li&gt;
&lt;li&gt;Extremely stable
&lt;/li&gt;
&lt;li&gt;Industry standard
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for 90% of applications  &lt;/p&gt;




&lt;h3&gt;
  
  
  Odyssey (Advanced)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-threaded
&lt;/li&gt;
&lt;li&gt;Better for high-core systems
&lt;/li&gt;
&lt;li&gt;More complex setup
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for very high-scale systems  &lt;/p&gt;




&lt;h2&gt;
  
  
  Real Architecture (Modern Apps)
&lt;/h2&gt;

&lt;p&gt;In production, it looks like this,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App Servers → Connection Pooler → PostgreSQL&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Pro Tip: Double Pooling Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. App-Level Pool
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HikariCP (Java)
&lt;/li&gt;
&lt;li&gt;Node.js connection pools
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reduces connection overhead  &lt;/p&gt;




&lt;h3&gt;
  
  
  2. Database-Level Pool
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PgBouncer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protects PostgreSQL from spikes  &lt;/p&gt;




&lt;h3&gt;
  
  
  Combined Flow
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;App → App Pool → PgBouncer → PostgreSQL&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, Maximum efficiency + stability&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistake
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Let’s just increase max_connections”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This makes things worse&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More connections = more memory usage
&lt;/li&gt;
&lt;li&gt;More processes = more CPU overhead
&lt;/li&gt;
&lt;li&gt;Performance degrades further
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Connection pooling is the real solution&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL = expensive connections
&lt;/li&gt;
&lt;li&gt;Pooler = smart connection sharing
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Connection pooling isn’t just an optimization.&lt;/p&gt;

&lt;p&gt;It’s often the difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A system that crashes under load
&lt;/li&gt;
&lt;li&gt;And one that scales smoothly
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of giving every user their own database process,&lt;br&gt;&lt;br&gt;
you let them share a small, efficient pool.&lt;/p&gt;

&lt;p&gt;That’s how modern high-scale systems survive traffic spikes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>postgres</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>WebRTC Video Calls Explained: Simpler Than You Think</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Tue, 14 Apr 2026 07:11:03 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/webrtc-video-calls-explained-simpler-than-you-think-158k</link>
      <guid>https://forem.com/abdullahmubin/webrtc-video-calls-explained-simpler-than-you-think-158k</guid>
      <description>&lt;p&gt;Building real-time video apps sounds intimidating at first. You hear terms like &lt;strong&gt;&lt;em&gt;SDP, ICE candidates, STUN, TURN&lt;/em&gt;&lt;/strong&gt;, and suddenly it feels like you’re diving into networking hell.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But here’s the truth:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;WebRTC becomes much easier when you stop thinking like an engineer and start thinking like a human.&lt;/p&gt;

&lt;p&gt;Let’s walk through it as a simple, memorable story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Real-World Scenario&lt;/li&gt;
&lt;li&gt;Step 1: They Don’t Talk Directly (At First)&lt;/li&gt;
&lt;li&gt;Step 2: “Here’s My Setup”&lt;/li&gt;
&lt;li&gt;Step 3: The Handshake&lt;/li&gt;
&lt;li&gt;Step 4: The Real Problem is Network Barriers&lt;/li&gt;
&lt;li&gt;Step 5: Asking for Public Address (STUN)&lt;/li&gt;
&lt;li&gt;Step 6: When Direct Connection Fails&lt;/li&gt;
&lt;li&gt;Step 7: The Middleman (TURN)&lt;/li&gt;
&lt;li&gt;Step 8: The Magic Moment (Video Starts)&lt;/li&gt;
&lt;li&gt;Receive Remote Video&lt;/li&gt;
&lt;li&gt;The Entire Flow in One View&lt;/li&gt;
&lt;li&gt;The Simplest Mental Model&lt;/li&gt;
&lt;li&gt;Real Product View (Corporate Meeting)&lt;/li&gt;
&lt;li&gt;The Reality Most Tutorials Don’t Tell You&lt;/li&gt;
&lt;li&gt;What Professionals Actually Do&lt;/li&gt;
&lt;li&gt;Final Thought&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Real-World Scenario
&lt;/h2&gt;

&lt;p&gt;Imagine you’ve built a corporate meeting platform called:&lt;/p&gt;

&lt;p&gt;meet123.com&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Rahim *&lt;/em&gt;(a software engineer) joins a team meeting with *&lt;em&gt;Aisha *&lt;/em&gt;(product manager).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;At exactly 10 AM&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Rahim opens: meet123.com/room/team-sync&lt;/p&gt;

&lt;p&gt;Aisha opens the same link&lt;/p&gt;

&lt;p&gt;They’re now “in the same meeting.”&lt;/p&gt;

&lt;p&gt;But… nothing happens yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The real question is:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do their cameras actually connect?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1: They Don’t Talk Directly (At First)
&lt;/h2&gt;

&lt;p&gt;Here’s the key idea:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Browsers don’t connect directly immediately.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Instead:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rahim connects to a meeting server&lt;/li&gt;
&lt;li&gt;Aisha connects to the same server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of this server like a meeting coordinator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is called the Signaling Server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 2: “Here’s My Setup”
&lt;/h2&gt;

&lt;p&gt;Before the meeting starts, both participants share their setups.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rahim says:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;“I’ve got camera, mic, and these formats.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aisha says:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;“Same here.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This exchange is called:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SDP (Session Description Protocol)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It includes:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video/audio formats (codecs)&lt;/li&gt;
&lt;li&gt;Resolution&lt;/li&gt;
&lt;li&gt;Device capabilities&lt;/li&gt;
&lt;li&gt;Network info&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here’s how I can communicate.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3: The Handshake
&lt;/h2&gt;

&lt;p&gt;Now they formally agree on how to communicate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Flow:&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rahim creates an offer&lt;/li&gt;
&lt;li&gt;Sends it to the backend (via WebSocket)&lt;/li&gt;
&lt;li&gt;Backend forwards it to Aisha&lt;/li&gt;
&lt;li&gt;Aisha creates an answer&lt;/li&gt;
&lt;li&gt;Backend sends it back to Rahim&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Now both sides agree on:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Formats&lt;/li&gt;
&lt;li&gt;Communication rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But they still aren’t connected yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: The Real Problem is Network Barriers
&lt;/h2&gt;

&lt;p&gt;Here’s where reality hits.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rahim might be:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On home WiFi&lt;/li&gt;
&lt;li&gt;Behind a router&lt;/li&gt;
&lt;li&gt;Using a private IP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Aisha might be:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In an office network&lt;/li&gt;
&lt;li&gt;Behind a firewall&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Problem:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They don’t know how to reach each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 5: Asking for Public Address (STUN)
&lt;/h2&gt;

&lt;p&gt;To solve this, both ask a helper:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STUN server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rahim asks:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;“What’s my public address?”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;STUN replies:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;“You appear as: 103.xx.xx.xx:54321”&lt;/p&gt;

&lt;p&gt;Aisha does the same.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now both know how they appear on the internet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They attempt a direct connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: When Direct Connection Fails
&lt;/h2&gt;

&lt;p&gt;Sometimes it works and sometimes it doesn’t.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reasons:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Office firewalls block traffic&lt;/li&gt;
&lt;li&gt;Strict corporate networks&lt;/li&gt;
&lt;li&gt;Mobile data restrictions&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;So WebRTC needs a fallback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 7: The Middleman (TURN)
&lt;/h2&gt;

&lt;p&gt;If the direct connection fails, both sides use a relay:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TURN server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now the flow becomes:&lt;/p&gt;

&lt;p&gt;Rahim → TURN → Aisha&lt;/p&gt;

&lt;p&gt;It’s like saying:&lt;/p&gt;

&lt;p&gt;“We can’t connect directly, so let’s use a central meeting room.”&lt;/p&gt;

&lt;p&gt;This guarantees connectivity but adds some latency and cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: The Magic Moment (Video Starts)
&lt;/h2&gt;

&lt;p&gt;Once the connection is established:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Camera captures video&lt;/li&gt;
&lt;li&gt;Audio is recorded&lt;/li&gt;
&lt;li&gt;Data is encoded&lt;/li&gt;
&lt;li&gt;Sent over the network&lt;/li&gt;
&lt;li&gt;Decoded on the other side&lt;/li&gt;
&lt;li&gt;Displayed instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the meeting is live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mapping This to Real Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Turn on Camera &amp;amp; Microphone&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;video&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;audio&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="nx"&gt;videoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create Peer Connection&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pc&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;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;iceServers&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;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stun:stun.l.google.com:19302&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Add Media Tracks&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="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTracks&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;track&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&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;4. Create Offer (Rahim)&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offer&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;5. Aisha Responds with Answer&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRemoteDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&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;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createAnswer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;answer&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;6. Rahim Receives Answer&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRemoteDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&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;7. Exchange ICE Candidates&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="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&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="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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ice-candidate&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&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;8. Receive Remote Video&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="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ontrack&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;remoteVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&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;streams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;h2&gt;
  
  
  The Entire Flow in One View
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rahim sends offer&lt;/li&gt;
&lt;li&gt;Aisha sends answer&lt;/li&gt;
&lt;li&gt;Both exchange ICE candidates&lt;/li&gt;
&lt;li&gt;Try direct connection (STUN)&lt;/li&gt;
&lt;li&gt;Fallback to TURN if needed&lt;/li&gt;
&lt;li&gt;Meeting starts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Simplest Mental Model
&lt;/h2&gt;

&lt;p&gt;If you remember just this, you understand WebRTC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebRTC → Direct video pipe&lt;/li&gt;
&lt;li&gt;Signaling server → Meeting coordinator&lt;/li&gt;
&lt;li&gt;STUN → Finds your public identity&lt;/li&gt;
&lt;li&gt;TURN → Backup relay when direct fails&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Product View (Corporate Meeting)
&lt;/h2&gt;

&lt;p&gt;In your actual app:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Participant:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicks “Join Meeting”&lt;/li&gt;
&lt;li&gt;Camera starts&lt;/li&gt;
&lt;li&gt;Waits in room&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Team Members:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join the same room&lt;/li&gt;
&lt;li&gt;Instantly connect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else happens behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality Most Tutorials Don’t Tell You
&lt;/h2&gt;

&lt;p&gt;Raw WebRTC is powerful but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hard to scale&lt;/li&gt;
&lt;li&gt;Full of edge cases&lt;/li&gt;
&lt;li&gt;Painful to debug&lt;/li&gt;
&lt;li&gt;Requires TURN infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where most developers get stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Professionals Actually Do
&lt;/h2&gt;

&lt;p&gt;Instead of building everything manually, most teams use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LiveKit&lt;/li&gt;
&lt;li&gt;Agora&lt;/li&gt;
&lt;li&gt;Twilio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these, your code becomes:&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;room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localParticipant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableCameraAndMicrophone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No need to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers &amp;amp; answers&lt;/li&gt;
&lt;li&gt;ICE candidates&lt;/li&gt;
&lt;li&gt;Network traversal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Thought&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At its core, WebRTC is beautifully simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Team members trying to join a meeting,&lt;br&gt;
using a coordinator to exchange info,&lt;br&gt;
figuring out how to reach each other,&lt;br&gt;
and using a central room only if needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you see it this way, everything clicks.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>techtalks</category>
      <category>web3</category>
    </item>
    <item>
      <title>Dictionary C#. Easier than we think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sat, 05 Aug 2023 14:25:49 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/dictionary-c-easier-than-we-think-52bp</link>
      <guid>https://forem.com/abdullahmubin/dictionary-c-easier-than-we-think-52bp</guid>
      <description>&lt;h2&gt;
  
  
  What is Dictionary:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Dictionary&lt;/strong&gt; is a generic collection of key-value pair of data. It contains a unique key, we can easily get our specific data using that unique key. The dictionary is the most useful and popular data structure whenever we need to find value based on key.. &lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax:
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Dictionary&amp;lt;TKey, TValue&amp;gt; dictionaryObj = new Dictionary&amp;lt;TKey, TValue&amp;gt;();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in the above line, &lt;em&gt;dictionaryObj&lt;/em&gt; is name of &lt;strong&gt;the dictionary&lt;/strong&gt;, &lt;em&gt;Tkey&lt;/em&gt; is The type of key we pass in the dictionaryObj and &lt;em&gt;TValue&lt;/em&gt; is The type of value we pass in the &lt;strong&gt;dictionaryObj&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TKey and TValue&lt;/em&gt; can be any data type. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Characteristics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comes under System.Collections.Generic namespace.&lt;/li&gt;
&lt;li&gt;Dictionary stores key-value pairs.&lt;/li&gt;
&lt;li&gt;Implements IDictionary interface.&lt;/li&gt;
&lt;li&gt;Keys must be unique and cannot be null.&lt;/li&gt;
&lt;li&gt;Values can be null or duplicate.&lt;/li&gt;
&lt;li&gt;Values can be accessed by passing associated key in the indexer e.g. myDictionary[key]&lt;/li&gt;
&lt;li&gt;Elements are stored as KeyValuePair objects.&lt;/li&gt;
&lt;li&gt;It is faster than a Hashtable because there is no boxing and unboxing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a Dictionary
&lt;/h2&gt;

&lt;p&gt;We have already seen the syntax, let's try to create a dictionary,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;int, string&amp;gt; myDictionary = new Dictionary&amp;lt;int, string&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, key will be int and value will be string.&lt;/p&gt;

&lt;p&gt;let's add some value on it, here, 1 is key and value is myName&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myDictionary.Add(1, "myName");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;put below code in our compiler and run the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;int, string&amp;gt; myDictionary = new Dictionary&amp;lt;int, string&amp;gt;();
myDictionary.Add(1, "mubin");

foreach (var item in myDictionary)
{
Console.WriteLine(item.Key + ": and value is: " + item.Value);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the output will be,&lt;br&gt;
&lt;code&gt;1: and value is: mubin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiyavb2vp6lupphtnk5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiyavb2vp6lupphtnk5h.png" alt=" " width="378" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;let's put an object in a dictionary,&lt;/p&gt;

&lt;p&gt;Declare a class UserDetails&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserDetails
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Address { get; set; }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now declare a dictionary using that class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;int, UserDetails&amp;gt; userDetails = new Dictionary&amp;lt;int, UserDetails&amp;gt;();
userDetails.Add(1, new UserDetails { Name = "Galib", Age = 123, Address = "Naogaon" });

foreach (var item in userDetails)
{
Console.WriteLine("Key is: "+item.Key + " Name " + item.Value.Name + " Age: " + item.Value.Age + " Address: " + item.Value.Address);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if we run above code then the result will be &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cky4vl0t9azbm710k1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cky4vl0t9azbm710k1o.png" alt=" " width="482" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Data from Dictionary:
&lt;/h2&gt;

&lt;p&gt;To get data from dictionary we can use the square bracket notation to access an item data in the dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;int, string&amp;gt; myDictionary = new Dictionary&amp;lt;int, string&amp;gt;();
myDictionary.Add(1, "mubin");

string userName = myDictionary[1]; 
// Here 1 is a key, using 1 we can get value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update Data in a Dictionary
&lt;/h2&gt;

&lt;p&gt;To update data, We can use square bracket and notation then assign new value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;int, string&amp;gt; myDictionary = new Dictionary&amp;lt;int, string&amp;gt;();
myDictionary.Add(1, "mubin");
myDictionary[1] = "Update Username";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Delete Data in a Dictionary
&lt;/h2&gt;

&lt;p&gt;We can use remove method to delete data in a dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myDictionary.Remove(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Properties of Dictionary:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Count&lt;/strong&gt; &lt;br&gt;
Count used to get the total length/number of key-value pairs in the Dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int count = myDictionary.Count;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Values&lt;/strong&gt;&lt;br&gt;
Values used to get a collection of all the values in the Dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var values = myDictionary.Values;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Keys&lt;/strong&gt;&lt;br&gt;
Get a collection of all the keys in the Dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var keys = myDictionary.Keys;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  C# Dictionary Methods
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Add()&lt;/strong&gt;&lt;br&gt;
Add(TKey key, TValue value): Add a new key-value pair item to the Dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dictionary&amp;lt;string, int&amp;gt; bookPrice = new Dictionary&amp;lt;string, int&amp;gt;();
bookPrice.Add("Physics", 2.20);
bookPrice.Add("Chemistry", 1.80);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ContainsKey()&lt;/strong&gt;&lt;br&gt;
ContainsKey(TKey key): Returns a boolean indicating whether the Dictionary contains the specified key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bool containsPhysics = bookPrice.ContainsKey("Physics"); // returns  true;
bool containsHistory = bookPrice.ContainsKey("History"); // returns false;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: If the key is null, an ArgumentNullException will be thrown, and if the requested key is not in the dictionary, a KeyNotFoundException will be thrown.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;ContainsValue()&lt;/strong&gt;&lt;br&gt;
Returns a boolean indicating whether the Dictionary contains the specified value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bool value = bookPrice.ContainsValue(1.80); // returns true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Remove()&lt;/strong&gt;&lt;br&gt;
Remove() method deletes the value with the specified key from the Dictionary.&lt;br&gt;
If the key is found and the item is successfully removed, it returns true; otherwise false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Use the Remove method to remove a key / value pair.
Console.WriteLine("\nRemove(\"107\")\n");
bookPrice.Remove("Physics");

// Check if item is removed from the dictionary object.
if (!bookPrice.ContainsKey("Physics"))
{
  Console.WriteLine("Key \"107\" is not found.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;TryGetValue()&lt;/strong&gt;&lt;br&gt;
This method is used to get the value for a specific key, which allows you to handle the case where the key does not exist. It will not throw an error if the key doesn’t exist in the collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int physicsPrice;
if (bookPrice.TryGetValue("Physics", out physicsPrice))
{
    Console.WriteLine($"The price of a Physics book is {physicsPrice}.");
}
else
{
    Console.WriteLine("The Physics book is not available.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clear()&lt;/strong&gt;&lt;br&gt;
Removes all key-value pairs from the Dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bookPrice.Clear();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all for today.. seee ya. &lt;/p&gt;

</description>
      <category>csharp</category>
      <category>oop</category>
      <category>webdev</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>react useContext. Easier than we think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sun, 23 Jul 2023 17:48:10 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/react-usecontext-easier-than-we-think-3cpc</link>
      <guid>https://forem.com/abdullahmubin/react-usecontext-easier-than-we-think-3cpc</guid>
      <description>&lt;p&gt;Here, we will learn about &lt;strong&gt;useContext&lt;/strong&gt; in details with examples. we also learn about &lt;em&gt;When and how&lt;/em&gt; we need to use &lt;em&gt;useContext&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have added &lt;strong&gt;github demo&lt;/strong&gt; &lt;a href="https://github.com/abdullahmubin/useContext" rel="noopener noreferrer"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  useContext Hook
&lt;/h2&gt;

&lt;p&gt;Sometimes we use props to pass data from parent to child. It's a complex process and it is also inconvenient if we need to pass them through many components. The &lt;em&gt;React Context API&lt;/em&gt; provides a way to share data inside the React component tree. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passing data deeply into the tree.&lt;/li&gt;
&lt;li&gt;Overriding context for a part of the tree.&lt;/li&gt;
&lt;li&gt;Optimizing re-renders when passing objects and functions.&lt;/li&gt;
&lt;li&gt;Updating data passed via context.&lt;/li&gt;
&lt;li&gt;Specifying a fallback default value.&lt;/li&gt;
&lt;li&gt;useContext can pass data to our entire application and also it can use at any part of the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Syntax:
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;const value = useContext(SomeContext)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;let's try &lt;strong&gt;useContext&lt;/strong&gt; with simple application. let's &lt;em&gt;change&lt;/em&gt; some &lt;em&gt;font sizes&lt;/em&gt; and try to understand its data flow. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Result&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzns0jurcfulx2kcsvzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzns0jurcfulx2kcsvzx.png" alt=" " width="382" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first, we need to &lt;strong&gt;create a context&lt;/strong&gt; using &lt;em&gt;React.createContext&lt;/em&gt; and this context will pass to the hook. I have created a folder called Context and put a file &lt;em&gt;index.js&lt;/em&gt; inside the folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext } from "react";

//initial fontSize as 16.
const fontSizeContext = createContext(16);
export default fontSizeContext;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the above code, we used &lt;em&gt;createContext&lt;/em&gt; and set the &lt;em&gt;initial value 16&lt;/em&gt;. It assign to fontSizeContext constant and export as a default. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is createContext&lt;/strong&gt;&lt;br&gt;
It creates a context object and used to make sure that every component at different levels (inside tree) can use the same context to fetch data. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;let's make some changes in &lt;strong&gt;app.js&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import FontSizeContext from "./Context/context";
import { useState } from "react";
import UseContextExample from "./UseContextExample";

const App = () =&amp;gt; {
  const [size, setSize] = useState(16);
  return (
    &amp;lt;FontSizeContext.Provider value={size}&amp;gt;
      &amp;lt;div style={{ width: '500px', margin: 'auto' }}&amp;gt;
        &amp;lt;UseContextExample /&amp;gt;

        &amp;lt;button onClick={() =&amp;gt; setSize(size + 5)}&amp;gt;Increase font size&amp;lt;/button&amp;gt;
        &amp;lt;button
          onClick={() =&amp;gt;
            setSize((prevSize) =&amp;gt; Math.min(prevSize - 5))
          }
        &amp;gt;
          Decrease font size
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/FontSizeContext.Provider&amp;gt;
  );
};
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we use Font Size &lt;strong&gt;Context.Provider value={size}&lt;/strong&gt; here, we wrapped our component with &lt;em&gt;FontSize Context.Provider&lt;/em&gt; and make our &lt;em&gt;size/value&lt;/em&gt; available to every component inside the tree.&lt;/p&gt;

&lt;p&gt;we also added two buttons, &lt;strong&gt;one to increase&lt;/strong&gt; the size and the other used to &lt;strong&gt;decrease the size&lt;/strong&gt;. Whenever someone clicks on a button it &lt;em&gt;updates its state&lt;/em&gt;  and &lt;em&gt;change&lt;/em&gt; the &lt;strong&gt;value of font size&lt;/strong&gt; and then it passes to the entire component tree. So any component can easily access the value of font size. &lt;/p&gt;

&lt;p&gt;Now, create a folder called &lt;strong&gt;UseContextExample&lt;/strong&gt; inside the directory create a file called &lt;strong&gt;index.js&lt;/strong&gt; and put the below code inside index.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useContext } from "react";
import fontSizeContext from "../Context/context";
const UseContextExample = () =&amp;gt; {
    const size = useContext(fontSizeContext);
    return &amp;lt;p style={{ fontSize: `${size}px` }}&amp;gt;font size now {size}px&amp;lt;/p&amp;gt;;
};
export default UseContextExample;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the above code, we use &lt;br&gt;
&lt;code&gt;const size = useContext(fontSizeContext);&lt;/code&gt; to get the value of font size. This component can &lt;strong&gt;easily access the data/value&lt;/strong&gt; of font size because it stays &lt;em&gt;inside the component tree&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;I have added &lt;strong&gt;github demo&lt;/strong&gt; &lt;a href="https://github.com/abdullahmubin/useContext" rel="noopener noreferrer"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's it for today. See yaaa.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>react useMemo, useCallback. Easier than we think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sat, 22 Jul 2023 19:54:27 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/react-usememo-usecallback-easier-than-we-think-13be</link>
      <guid>https://forem.com/abdullahmubin/react-usememo-usecallback-easier-than-we-think-13be</guid>
      <description>&lt;p&gt;As front-end developers, we always try to make our application performance better and better. Sometimes we need to execute large and critical calculation in our system. Those function/calculation take time to complete, so our application will be slow. &lt;/p&gt;

&lt;p&gt;Meanwhile, we try to &lt;strong&gt;improve performance&lt;/strong&gt; using the &lt;strong&gt;Memoization technique&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this lesson, we will learn about &lt;strong&gt;Memoization technique&lt;/strong&gt; using &lt;strong&gt;useMemo&lt;/strong&gt; and &lt;strong&gt;useCallback&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization:
&lt;/h2&gt;

&lt;p&gt;Memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls to pure functions and &lt;strong&gt;returning&lt;/strong&gt; the &lt;strong&gt;cached result&lt;/strong&gt; when the &lt;strong&gt;same inputs&lt;/strong&gt; occur again.&lt;/p&gt;

&lt;h2&gt;
  
  
  useMemo Hook
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;useMemo hook&lt;/strong&gt; is designed to memoize expensive computations. Memoization simply means caching. It caches the computation result with respect to the dependency values so that when the same values are passed, &lt;strong&gt;useMemo&lt;/strong&gt; will just spit out the already computed value &lt;strong&gt;without recomputing&lt;/strong&gt; it again. This can significantly &lt;strong&gt;improve performance&lt;/strong&gt; when done correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;useMemo hook&lt;/strong&gt; can be used as follows,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const memoizedResult = useMemo(() =&amp;gt; {&lt;br&gt;
  return criticalComputeFn(parameter1, parameter2);&lt;br&gt;
}, [parameter1, parameter2]);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, &lt;em&gt;criticalComputeFn&lt;/em&gt; represents the calculation function and &lt;em&gt;dependencies&lt;/em&gt; represent the dependency array. ([parameter1, parameter2]).&lt;/p&gt;
&lt;h2&gt;
  
  
  UseCallBack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;useCallback&lt;/strong&gt; does the same thing as &lt;strong&gt;useMemo&lt;/strong&gt; but it returns a &lt;strong&gt;memoized callback&lt;/strong&gt; &lt;em&gt;instead of&lt;/em&gt; &lt;strong&gt;memoized value&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Syntax:
&lt;/h2&gt;

&lt;p&gt;This hook can be used as follows,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const memoizedResult = useCallback(() =&amp;gt; {&lt;br&gt;
  return criticalComputeFn(parameter1, parameter2);&lt;br&gt;
}, [parameter1, parameter2]);&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember one thing, &lt;em&gt;useMemo&lt;/em&gt; and &lt;em&gt;useCallback&lt;/em&gt; are both used for same purpose, but &lt;strong&gt;useMemo return memoized value&lt;/strong&gt; but &lt;strong&gt;useCallback return memoized callback&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What is callback?&lt;/strong&gt;&lt;br&gt;
It is a function that is passed as an argument to another function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;During the &lt;em&gt;first&lt;/em&gt; rendering or &lt;em&gt;initial&lt;/em&gt; rendering useMemo and useCallback both invoke criticalComputeFn, then &lt;strong&gt;useMemo returns the result/value&lt;/strong&gt; but &lt;strong&gt;useCallback returns the callback&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If &lt;em&gt;dependencies change&lt;/em&gt; then useMemo and useCallback both invoke criticalComputeFn, then &lt;strong&gt;useMemo return the result/value&lt;/strong&gt; but &lt;strong&gt;useCallback return the callback&lt;/strong&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If dependencies &lt;em&gt;don't change&lt;/em&gt;, then both &lt;strong&gt;don't invoke&lt;/strong&gt; criticalComputeFn but &lt;strong&gt;useMemo return memoize result/value&lt;/strong&gt; and &lt;strong&gt;useCallback return memoize callback&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Simple Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useCallback, useMemo, useEffect } from 'react'

export default function App() {
  const a = 5
  const b = 7

  const memoResult = useMemo(() =&amp;gt; a + b, [a, b])

  const callbackResultFn = useCallback(() =&amp;gt; a + b, [a, b])

  useEffect(() =&amp;gt; {

  }, [])

  const callback = callbackResultFn()

  console.log(callbackResultFn) // Return function
  console.log(callback) // return value
  console.log(memoResult) // return value using useMemo



  return (
    &amp;lt;div&amp;gt;
      &amp;lt;&amp;gt;&amp;lt;h2&amp;gt;Test test&amp;lt;/h2&amp;gt;&amp;lt;/&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the above code we can see that &lt;em&gt;useMemo&lt;/em&gt; and &lt;em&gt;useCallback&lt;/em&gt; show the &lt;strong&gt;same result/value&lt;/strong&gt;. &lt;em&gt;useMemo&lt;/em&gt; directly return the calculation result/value but &lt;em&gt;useCallback&lt;/em&gt; return callback function then we need to &lt;em&gt;process the result&lt;/em&gt; to show it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Careful about:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;useMemo/useCallback&lt;/strong&gt; should be used only when it is necessary to optimize the computation. In other words, when &lt;strong&gt;recomputation&lt;/strong&gt; is &lt;strong&gt;expensive&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is advisable to first write the calculation without memoization and only memoize it if it is causing performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unnecessary and irrelevant use of the &lt;strong&gt;useMemo/useCallback&lt;/strong&gt; hook may even compound the performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes, too much memoization can also cause performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;RealTime example of useMemo:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";
import { useEffect, useMemo, useState } from "react";

export default function App() {
  const [employee, setEmployee] = useState({});
  const [employees, setEmployees] = useState([]);
  const [num, setNum] = useState(1);

  const endPoint =
    "https://my-json-server.typicode.com/ifeanyidike/jsondata/employees";

  useEffect(() =&amp;gt; {
    const getEmployee = async () =&amp;gt; {
      const { data } = await axios.get(`${endPoint}/${num}`);
      setEmployee(data);
    };
    getEmployee();

    return () =&amp;gt; {};
  }, [num]);

  useEffect(() =&amp;gt; {
    axios.get(endPoint).then(({ data }) =&amp;gt; setEmployees(data));
  }, [num]);

  const taxVariablesCompute = useMemo(() =&amp;gt; {
    const { income, noOfChildren, noOfDependentRelatives } = employee;

    const reliefAllowance1 = 0.01 * income &amp;gt;= 200000 ? 0.01 * income : 200000;
    const reliefAllowance2 = 0.2 * income;

    const numChildren = +noOfChildren &amp;lt;= 4 ? +noOfChildren : 4;
    const numRelatives =
      +noOfDependentRelatives &amp;lt;= 2 ? +noOfDependentRelatives : 2;

    const childrenRelief = numChildren * 2500;
    const relativesRelief = numRelatives * 2000;
    const pensionRelief = 0.075 * income;

    const reliefs =
      reliefAllowance1 +
      reliefAllowance2 +
      childrenRelief +
      relativesRelief +
      pensionRelief;

    return reliefs;
  }, [employee]);

  const taxCalculation = useMemo(() =&amp;gt; {
    const { income } = employee;
    let taxableIncome = income - taxVariablesCompute;
    let PAYE = 0;

    const taxEndPoints = [300000, 300000, 500000, 500000, 1600000, 3200000];

    for (let i = 0; i &amp;lt; taxEndPoints.length; i++) {
      if (i === 0) {
        if (taxableIncome &amp;gt;= 300000) {
          PAYE += 0.07 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.07 * taxableIncome;
          break;
        }
      } else if (i === 1) {
        if (taxableIncome &amp;gt;= 300000) {
          PAYE += 0.11 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.11 * taxableIncome;
          break;
        }
      } else if (i === 2 &amp;amp;&amp;amp; taxableIncome &amp;gt;= 500000) {
        if (taxableIncome &amp;gt;= 500000) {
          PAYE += 0.15 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.15 * taxableIncome;
          break;
        }
      } else if (i === 3) {
        if (taxableIncome &amp;gt;= 500000) {
          PAYE += 0.19 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.19 * taxableIncome;
          break;
        }
      } else if (i === 4) {
        if (taxableIncome &amp;gt;= 1600000) {
          PAYE += 0.21 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.21 * taxableIncome;
          break;
        }
      } else if (i === 5) {
        if (taxableIncome &amp;gt;= 3200000) {
          PAYE += 0.24 * taxEndPoints[i];
          taxableIncome -= taxEndPoints[i];
        } else {
          PAYE += 0.24 * taxableIncome;
          break;
        }
      }
    }

    const netIncome = income - PAYE;
    return { PAYE, netIncome };
  }, [employee, taxVariablesCompute]);

  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Name: {`${employee.firstName} ${employee.lastName}`}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Job: {employee.job}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Sex: {employee.sex}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Income: {employee.income}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;No. of children: {employee.noOfChildren}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;No. of dependents: {employee.noOfDependentRelatives}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;PAYE: ₦{taxCalculation.PAYE}&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Income after PAYE: ₦{taxCalculation.netIncome}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;button
          disabled={num === 1}
          onClick={() =&amp;gt;
            setNum((prevNum) =&amp;gt; (prevNum &amp;gt;= 1 ? prevNum - 1 : prevNum))
          }
        &amp;gt;
          &amp;amp;laquo;
        &amp;lt;/button&amp;gt;
        &amp;lt;button
          disabled={num === employees.length}
          onClick={() =&amp;gt;
            setNum((prevNum) =&amp;gt;
              prevNum &amp;lt; employees.length ? prevNum + 1 : prevNum
            )
          }
        &amp;gt;
          &amp;amp;raquo;
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, I have tried to &lt;em&gt;calculate tax&lt;/em&gt; information. I think it's an &lt;strong&gt;expensive calculation&lt;/strong&gt;. So I do it with &lt;strong&gt;useMemo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's it for today. See yaa. &lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>React useReducer. Easier than we think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Tue, 18 Jul 2023 10:02:30 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/react-usereducer-easier-than-we-think-447d</link>
      <guid>https://forem.com/abdullahmubin/react-usereducer-easier-than-we-think-447d</guid>
      <description>&lt;h2&gt;
  
  
  useReducer:
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;useReducer&lt;/strong&gt;&lt;/em&gt; is one of the most popular react hooks. &lt;em&gt;useReducer&lt;/em&gt; hook returns the current stage and a dispatch method. It is similar to the useState hook. If we want to make &lt;em&gt;complex logic&lt;/em&gt; then useReducer may be very useful.&lt;/p&gt;

&lt;p&gt;If you want to download the full demo project then click here &lt;a href="https://github.com/abdullahmubin/useReducer" rel="noopener noreferrer"&gt;Demo git&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax:
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useReducer(&amp;lt;reducer&amp;gt;, &amp;lt;initialState&amp;gt;)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;useReducer(&amp;lt;reducer&amp;gt;, &amp;lt;initialState&amp;gt;, &amp;lt;init&amp;gt;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, &lt;strong&gt;reducer&lt;/strong&gt; function contains custom state &lt;em&gt;logic&lt;/em&gt; and the &lt;strong&gt;initialState&lt;/strong&gt; can be a sample default state value. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;init&lt;/em&gt; is a function and it is used whenever we want to create the initial state lazily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosl4a8tixgq5xmsionpt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosl4a8tixgq5xmsionpt.png" alt=" " width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  reducer:
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;reducer&lt;/strong&gt; is a function that is able to process user &lt;em&gt;instruction/action&lt;/em&gt;. A reducer processes the &lt;em&gt;existing state&lt;/em&gt; with user action and returns the &lt;em&gt;new state&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;below we will try to make a simple application for better understanding. &lt;/p&gt;
&lt;h2&gt;
  
  
  Todo Application:
&lt;/h2&gt;

&lt;p&gt;The below image shows the UI of our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgijk66fw6o7yk4ap6gi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgijk66fw6o7yk4ap6gi.png" alt=" " width="350" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that it contains a submit button, if we save it then it will show on the list, we can complete and remove that todo item.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We will make our code as simple as we can.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;let try to make &lt;em&gt;action type&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here, we will make 3 types of action,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Todo&lt;/li&gt;
&lt;li&gt;Remove Todo&lt;/li&gt;
&lt;li&gt;Complete Todo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have created a new folder inside the &lt;strong&gt;src&lt;/strong&gt; directory and the folder name is &lt;strong&gt;action&lt;/strong&gt;. inside that folder, I have created an &lt;strong&gt;index.js&lt;/strong&gt; file and put the below code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/action/index.js

export const ADD_TODO = "ADD_TODO";
export const REMOVE_TODO = "REMOVE_TODO";
export const COMPLETE_TODO = "COMPLETE_TODO";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created three constants for user &lt;em&gt;action types&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;let try to make &lt;strong&gt;reducer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We already know that a &lt;strong&gt;reducer&lt;/strong&gt; basically is a function that contain complex logic. We need to pass value and instruction/action then it will change previous state to new state. Just like &lt;strong&gt;Redux&lt;/strong&gt; but we don't need to initialize our reducer here.&lt;/p&gt;

&lt;p&gt;I have created a new folder and named it reducer, inside that folder I have created an index.js file and put the below code,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ADD_TODO, REMOVE_TODO, COMPLETE_TODO } from './../action'

const reducer = (state, action) =&amp;gt; {
    switch (action.type) {
        case ADD_TODO:
            const newTodo = {
                id: action.id,
                text: action.text,
                completed: false
            };
            return [...state, newTodo];
        case REMOVE_TODO:
            return state.filter((todo) =&amp;gt; todo.id !== action.id);
        case COMPLETE_TODO:
            const completeTodo = state.map((todo) =&amp;gt; {
                if (todo.id === action.id) {
                    return {
                        ...todo,
                        completed: !todo.completed
                    };
                } else {
                    return todo;
                }
            });
            return completeTodo;
        default:
            return state;
    }
};
export default reducer;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;strong&gt;reducer&lt;/strong&gt; function, we used a &lt;em&gt;switch&lt;/em&gt; statement to check user action. If the user want to add &lt;em&gt;new todo&lt;/em&gt;, then the action type will be &lt;em&gt;ADD_TODO&lt;/em&gt; and based on switch statement, it will perform &lt;em&gt;ADD_TODO&lt;/em&gt; &lt;strong&gt;logic&lt;/strong&gt; in that block. Finally it will return &lt;em&gt;new state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;case ADD_TODO:&lt;br&gt;
            const newTodo = {&lt;br&gt;
                id: action.id,&lt;br&gt;
                text: action.text,&lt;br&gt;
                completed: false&lt;br&gt;
            };&lt;br&gt;
return [...state, newTodo];&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;Remove&lt;/strong&gt; a todo task, the action type will be &lt;em&gt;REMOVE_TODO&lt;/em&gt;, and based on the &lt;em&gt;switch _ statement, it will perform _REMOVE_TODO&lt;/em&gt; logic in that block. Finally, it will &lt;em&gt;return&lt;/em&gt; to the &lt;em&gt;new state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;case REMOVE_TODO:&lt;br&gt;
            return state.filter((todo) =&amp;gt; todo.id !== action.id);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;complete&lt;/strong&gt; a &lt;em&gt;todo&lt;/em&gt;, the action will be &lt;em&gt;COMPLETE_TODO&lt;/em&gt; and it will perform his logic and return new state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;case COMPLETE_TODO:&lt;br&gt;
            const completeTodo = state.map((todo) =&amp;gt; {&lt;br&gt;
                if (todo.id === action.id) {&lt;br&gt;
                    return {&lt;br&gt;
                        ...todo,&lt;br&gt;
                        completed: !todo.completed&lt;br&gt;
                    };&lt;br&gt;
                } else {&lt;br&gt;
                    return todo;&lt;br&gt;
                }&lt;br&gt;
            });&lt;br&gt;
 return completeTodo;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;it's a &lt;strong&gt;simple example&lt;/strong&gt; so I haven't divided &lt;em&gt;UI&lt;/em&gt; into separate containers. I put everything inside &lt;em&gt;app.js&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;let &lt;strong&gt;put useReducer&lt;/strong&gt; in app.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useReducer, useState } from "react";
import "./index.css";
import reducer from "./reducer";
import { ADD_TODO, REMOVE_TODO, COMPLETE_TODO } from './action'
export default function App() {
  const [id, setId] = useState(0);
  const [text, setText] = useState("");
  const initialState = [
    {
      id: id,
      text: "First todo Item",
      completed: false
    }
  ];

  //We could also pass an empty array as the initial state
  //const initialState = []

  const [state, dispatch] = useReducer(reducer, initialState);
  const addTodoItem = (e) =&amp;gt; {
    e.preventDefault();
    const newId = id + 1;
    setId(newId);
    dispatch({
      type: ADD_TODO,
      id: newId,
      text: text
    });
    setText("");
  };
  const removeTodo = (id) =&amp;gt; {
    dispatch({ type: REMOVE_TODO, id });
  };
  const completeTodo = (id) =&amp;gt; {
    dispatch({ type: COMPLETE_TODO, id });
  };
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;h2&amp;gt;Todo Example&amp;lt;/h2&amp;gt;
      &amp;lt;form className="input" onSubmit={addTodoItem}&amp;gt;
        &amp;lt;input value={text} onChange={(e) =&amp;gt; setText(e.target.value)} /&amp;gt;
        &amp;lt;button disabled={text.length === 0} type="submit"&amp;gt;+&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
      &amp;lt;div className="todos"&amp;gt;
        {state.map((todo) =&amp;gt; (
          &amp;lt;div key={todo.id} className="todoItem"&amp;gt;
            &amp;lt;p className=""&amp;gt;{todo.completed ? &amp;lt;del&amp;gt;{todo.text}&amp;lt;/del&amp;gt; : todo.text}&amp;lt;/p&amp;gt;
            &amp;lt;div className="actionType"&amp;gt;
              &amp;lt;span onClick={() =&amp;gt; removeTodo(todo.id)}&amp;gt;✕&amp;lt;/span&amp;gt;
              &amp;lt;span onClick={() =&amp;gt; completeTodo(todo.id)}&amp;gt;✓&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        ))}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we can see that &lt;strong&gt;useReducer&lt;/strong&gt; takes the &lt;em&gt;reducer function&lt;/em&gt; and &lt;em&gt;initialState&lt;/em&gt; as a &lt;em&gt;parameter&lt;/em&gt; then it returns &lt;em&gt;state&lt;/em&gt; and &lt;em&gt;dispatch&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When someone types some &lt;em&gt;text&lt;/em&gt; and clicks on &lt;strong&gt;+ sign&lt;/strong&gt;, then inside the &lt;em&gt;addTodoItem&lt;/em&gt; function &lt;em&gt;dispatch function&lt;/em&gt; will be called and it contains &lt;em&gt;3 parameters&lt;/em&gt; those are &lt;em&gt;type (ADD_TODO)&lt;/em&gt;, &lt;em&gt;id&lt;/em&gt; and &lt;em&gt;text&lt;/em&gt;. dispatch will trigger &lt;em&gt;reducer function&lt;/em&gt; and based on &lt;em&gt;type&lt;/em&gt; reducer function will add a new todo item and &lt;em&gt;return new state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dispatch({&lt;br&gt;
      type: ADD_TODO,&lt;br&gt;
      id: newId,&lt;br&gt;
      text: text&lt;br&gt;
    });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When someone &lt;em&gt;clicks&lt;/em&gt; on &lt;strong&gt;✕ the sign&lt;/strong&gt;, then another &lt;em&gt;dispatch function&lt;/em&gt; will be called, this time type will be &lt;em&gt;REMOVE_TODO&lt;/em&gt;, and based on &lt;em&gt;type&lt;/em&gt; and &lt;em&gt;id&lt;/em&gt;, the &lt;em&gt;reducer function&lt;/em&gt; &lt;em&gt;removes&lt;/em&gt; the specific item and will return &lt;em&gt;new state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dispatch({ type: REMOVE_TODO, id });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When someone &lt;strong&gt;clicks on ✓&lt;/strong&gt; then &lt;em&gt;dispatch function&lt;/em&gt; will trigger &lt;em&gt;reducer&lt;/em&gt; with action type &lt;em&gt;COMPLETE_TODO&lt;/em&gt;, then reducer will &lt;em&gt;update&lt;/em&gt; that object based on &lt;em&gt;id&lt;/em&gt; and return &lt;em&gt;new state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dispatch({ type: COMPLETE_TODO, id });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's put some &lt;em&gt;CSS&lt;/em&gt; in &lt;em&gt;index.css&lt;/em&gt; file,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

.App {
  width: 205px;
  margin: auto;
}

.todoItem {
  width: 100%;
  float: left;
  border-bottom: 1px solid;
}

.todoItem p {
  float: left;
}

.actionType {
  float: right;
  margin-top: 15px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to download the full demo project then click here &lt;a href="https://github.com/abdullahmubin/useReducer" rel="noopener noreferrer"&gt;Demo git&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's all for today, next, we will learn about react &lt;strong&gt;useContext&lt;/strong&gt; hook and how to use with &lt;strong&gt;useReducer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;See ya.  &lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Linked List Javascript. Easier than you think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sun, 09 Jul 2023 04:56:11 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/linked-list-javascript-easier-than-you-think-5gd3</link>
      <guid>https://forem.com/abdullahmubin/linked-list-javascript-easier-than-you-think-5gd3</guid>
      <description>&lt;p&gt;Thinking about data structure, let's take a closer look at Linked List. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linked list&lt;/strong&gt; is one of the most popular and efficient data structures. Basically, Linked List is a collection of "nodes", each node contain &lt;em&gt;data&lt;/em&gt;, &lt;em&gt;next&lt;/em&gt; and &lt;em&gt;previous&lt;/em&gt;, basically &lt;em&gt;next&lt;/em&gt; refers to next node and &lt;em&gt;previous&lt;/em&gt; refers to the previous node.&lt;/p&gt;

&lt;p&gt;We can say that, array and linked list is similar. but in array, elements are stored in a specific location or index.&lt;/p&gt;

&lt;p&gt;On the other hand, in Linked List everything works as a separate object. Each element (node) contain few things, data, link to the next node, link to the previous node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Types of Linked List:&lt;/strong&gt;&lt;br&gt;
There are three types of linked list,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Singly Linked List:&lt;/strong&gt; Each node contains data and a pointer to the next node. Basically its unidirectional. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjinw2ggf3bmmncp7qrq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjinw2ggf3bmmncp7qrq.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Analyzing the above image, it start with &lt;em&gt;Head&lt;/em&gt;, so &lt;em&gt;Head&lt;/em&gt; is the entry point. If a Linked list is empty then the &lt;em&gt;Head&lt;/em&gt; will be null. So &lt;em&gt;Head&lt;/em&gt; reference to the first node and &lt;em&gt;Last&lt;/em&gt; node points to the null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const linkedList = {
    head: {
        value: 5
        next: {
            value: 7                                             
            next: {
                value: 2
                next: {
                    value: 15
                    next: null  
                    }
                }
            }
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basic example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// class of node
class ListNode {
    constructor(data) {
        this.data = data
        this.next = null                
    }
}

/* LindedList class. remember, if the head node is not passed then head will be null */
class LinkedList {
    constructor(head = null) {
        this.head = head
    }
}

/* lets create some nodes */

let node1 = new ListNode(5) // data will be 5
let node2 = new ListNode(7) // data will be 7
let node3 = new ListNode(2) //  data will be 2
let node4 = new ListNode(15) // data will be 15

node1.next = node2 // points to the node2
node2.next = node3 // points to the node2
node3.next = node4

let list = new LinkedList(node1) // Linked List completed

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage and Uses of Singly Linked List&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Dynamic data structure:&lt;/strong&gt; Memory is dynamically allocated to the linked List. easily we can add or remove an element. We don't need to think about initial size.&lt;br&gt;
&lt;strong&gt;- Implementation:&lt;/strong&gt; Other data structure can be easily implemented here such as Queues and Stacks.&lt;br&gt;
&lt;strong&gt;- Versatility:&lt;/strong&gt; Lined list can be used to implement a wide range of data structures, such as stacks, queues, graphs, truees and has tables. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantage of Singly Linked List&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Memoray usage:&lt;/strong&gt; We need to store address of the next data, so it takes more memory.&lt;br&gt;
&lt;strong&gt;- Accessing an element:&lt;/strong&gt; Its impossible to access any element directly. If we need to find nth value, then we need to traverse until nth element found.&lt;br&gt;
&lt;strong&gt;- Reverse traversal:&lt;/strong&gt; It impossible for the Singly linked List. Because we don't have the memory address of the previous pointer. &lt;br&gt;
&lt;strong&gt;- More complex implementation:&lt;/strong&gt; Similar to Array, Its implementation is very complex. We need to understand dynamic memory location and pointer manipulation. &lt;br&gt;
&lt;strong&gt;- Lack of cache locality:&lt;/strong&gt; It may not take advantage of the caching mechanisms in modern processors. Its slower in performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Doubly Linked List:&lt;/strong&gt; Each node contains two pointers one for next node and one for previous node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglt2shao3auv8a7yu8bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglt2shao3auv8a7yu8bd.png" alt=" " width="662" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in the above image, we understand that,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prev: refers to the previous node&lt;/li&gt;
&lt;li&gt;data: data item&lt;/li&gt;
&lt;li&gt;next: address to the next node&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;below image shows us representation of doubly Linked list, Here each node contain &lt;em&gt;next _and _prev&lt;/em&gt; to point &lt;em&gt;next node&lt;/em&gt; and &lt;em&gt;prev node&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcc37m2zeaxb7ar4goaen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcc37m2zeaxb7ar4goaen.png" alt=" " width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ListNode  {
    constructor(value) {
        this.value = value;
        this.next = null;
        this.previous = null;
    }
}

class DoublyLinkedList {
    constructor(value) {
        this.head = {
            value: value,
            next: null,
            previous: null
        };
        this.length = 0;
        this.tail = this.head;
    }

    // Insert node at end of the list
    add(newNode) {
        this.tail.next = newNode;
        newNode.previous = this.tail;
        this.tail = newNode;
        this.length++;
    }

    printList() {
        let current = this.head;
        let result = [];
        while (current !== null) {
            result.push(current.value);
            current = current.next;
        }
        console.log(result.join(' '));
        return this;
    }
}

let numList = new DoublyLinkedList();
numList.add(new ListNode (12));
numList.add(new ListNode (13));
numList.add(new ListNode (14));
numList.add(new ListNode (15));
numList.add(new ListNode (16));
numList.add(new ListNode (17));
numList.printList();
console.log(numList)
console.log(numList.head)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage of Doubly Linked List:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Reversing:&lt;/strong&gt; Reversing the doubly linked list is very easy.&lt;br&gt;
&lt;strong&gt;-Traversal:&lt;/strong&gt; The traversal of this doubly linked list is bidirectional which is not possible in a singly linked list.&lt;br&gt;
&lt;strong&gt;-Deletion:&lt;/strong&gt; Deletion of nodes is easy as compared to a Singly Linked List.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantage of Doubly Linked List:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It uses extra memory when compared to the array and singly linked list.&lt;/li&gt;
&lt;li&gt;Traversing a doubly linked list can be slower than traversing a singly linked list&lt;/li&gt;
&lt;li&gt;Implementing and maintaining doubly linked lists can be more complex than singly linked lists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Uses of Doubly Linked List:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Navigation Systems:&lt;/strong&gt; It is used in the navigation systems where front and back navigation is required. &lt;br&gt;
&lt;strong&gt;- Undo and Redo:&lt;/strong&gt; It is also used by various applications to implement undo and redo functionality.&lt;br&gt;
&lt;strong&gt;- MRU/LRU:&lt;/strong&gt; Doubly Linked List is also used in constructing MRU/LRU (Most/least recently used) cache.&lt;br&gt;
&lt;strong&gt;- Thread Scheduler:&lt;/strong&gt; Also in many operating systems, the thread scheduler(the thing that chooses what process needs to run at which time) maintains a doubly-linked list of all processes running at that time.&lt;br&gt;
&lt;strong&gt;- Browser:&lt;/strong&gt; next and previous page.&lt;br&gt;
&lt;strong&gt;- Image viewer:&lt;/strong&gt; next and previous image&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementing **Graph **algorithms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Circular Linked Lists:&lt;/strong&gt; Its different than others, its last node points to the first nor or any other node before it.&lt;br&gt;
It has two types,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Circular Singly Linked List&lt;/li&gt;
&lt;li&gt;Circular Doubly Linked List&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will learn Circular Linked List in the next. that's it for today. See yaaa. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>datastructures</category>
      <category>node</category>
    </item>
  </channel>
</rss>
