<?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>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>
    <item>
      <title>CSS animation, Easier than we think.</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sun, 18 Jun 2023 16:47:23 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/css-animation-easier-than-you-think-2155</link>
      <guid>https://forem.com/abdullahmubin/css-animation-easier-than-you-think-2155</guid>
      <description>&lt;p&gt;Sometimes we want to make animation for a better user experience. There are a lot of tools, packages used to make animation. sometimes we need to understand JavaScript or Flash or other third-party packages to make animation.&lt;/p&gt;

&lt;p&gt;meanwhile, CSS provides us an easy way to make awesome animation. Here we will try to learn about it.&lt;/p&gt;

&lt;p&gt;So basically, we will animate HTML elements without using JavaScript or other third-party library.&lt;/p&gt;

&lt;p&gt;Using CSS animation, we can animate an element gradually changing from one style to another, we can change CSS property as many times as we want.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;@keyframes &lt;/li&gt;
&lt;li&gt;animation-name&lt;/li&gt;
&lt;li&gt;animation-duration&lt;/li&gt;
&lt;li&gt;animation-delay&lt;/li&gt;
&lt;li&gt;animation-iteration-count&lt;/li&gt;
&lt;li&gt;animation-direction&lt;/li&gt;
&lt;li&gt;animation-timing-function&lt;/li&gt;
&lt;li&gt;animation-fill-mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;@keyframes&lt;/strong&gt;&lt;br&gt;
By putting CSS style inside @keyframes, we can define our animation, and that will gradually change from present style to a new style at a certain times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
@keyframes example {
  from {background-color: green;}
  to {background-color: red;}
}

.circle {
  width: 50px;
  height: 50px;
  background-color: red;
  animation-name: example;
  animation-duration: 4s;
  margin-bottom: 10px;
  border-radius: 50%
}


&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code shows us, how @keyframes works with our styles. put the above code in your editor or online editor such as &lt;a href="https://jsfiddle.net/" rel="noopener noreferrer"&gt;Jsfiddle&lt;/a&gt; and see the changes. &lt;/p&gt;

&lt;p&gt;at first, the "circle" class will be "green" color, then it will change to "red" color.&lt;/p&gt;

&lt;p&gt;inside @keyframes, we already provided "from" and "to" property. We can replace them with percent. Such as, "0%", "25%", "50%", "75", and "100%".&lt;/p&gt;

&lt;p&gt;try below code to see the changes, I'm using &lt;a href="https://jsfiddle.net/" rel="noopener noreferrer"&gt;Jsfiddle&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
@keyframes example {
  0%   {background-color: green;}
  25%  {background-color: yellow;}
  50%  {background-color: blue;}
  100% {background-color: red;}
}

.circle {
  width: 50px;
  height: 50px;
  background-color: red;
  animation-name: example;
  animation-duration: 4s;
  margin-bottom: 10px;
  border-radius: 50%
}


&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we can see that color of the circle will be changed to green, yellow, blue, and red. Duration will be 4s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;animation-name:&lt;/strong&gt;&lt;br&gt;
This property used to indicates the &lt;a class="mentioned-user" href="https://dev.to/keyframe"&gt;@keyframe&lt;/a&gt; name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@keyframes example { /* name "example" */
}

.circle {
  animation-name: example; /* indicates @keyframes name */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;animation-duration:&lt;/strong&gt;&lt;br&gt;
It is a mandatory property. It defines how long it takes to complete the animation. Its default value is 0s so without defines, no animation will occur. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;animation-delay:&lt;/strong&gt;&lt;br&gt;
This property will make sure, that your animation will be delayed to start. &lt;/p&gt;

&lt;p&gt;update the "circle" class with below code to see the changes,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.circle {
  width: 50px;
  height: 50px;
  background-color: red;
  animation-name: example;
  animation-duration: 4s;
  animation-delay: 2s; /* animation will be deloayed for 2 seconds */
  margin-bottom: 10px;
  border-radius: 50%
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Negative values are also allowed, if we use "-2" then it will start as if it had been playing for 2 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.circle {
  width: 50px;
  height: 50px;
  background-color: red;
  animation-name: example;
  animation-duration: 4s;
  animation-delay: -2s;
  margin-bottom: 10px;
  border-radius: 50%
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can add multiple style property for each period of time inside of a @keyframes. below code will change color alongside of position of each circle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
.circle{
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example;
  animation-duration: 4s;
  animation-delay: 2s;
  border-radius: 50%
}

@keyframes example {
  0%   {background-color:red; left:0px; top:0px;}
  25%  {background-color:yellow; left:200px; top:0px;}
  50%  {background-color:blue; left:200px; top:200px;}
  75%  {background-color:green; left:0px; top:200px;}
  100% {background-color:red; left:0px; top:0px;}
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;



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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;animation-iteration-count:&lt;/strong&gt;&lt;br&gt;
It will define the number of times an animation should run.&lt;br&gt;
below code shows us it will run the animation 3 times before it stops.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
.circle{
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example;
  animation-duration: 4s;
  animation-iteration-count: 3;
  border-radius: 50%
}

@keyframes example {
  0%   {background-color:red; left:0px; top:0px;}
  25%  {background-color:yellow; left:200px; top:0px;}
  50%  {background-color:blue; left:200px; top:200px;}
  75%  {background-color:green; left:0px; top:200px;}
  100% {background-color:red; left:0px; top:0px;}
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;



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

&lt;/div&gt;



&lt;p&gt;if we want that animation will stay forever then we need to use "infinite".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.circle {
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  border-radius: 50%
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;animation-direction:&lt;/strong&gt;&lt;br&gt;
it will define that animation would play backward or forwards. below are the values of animation-direction&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- normal&lt;/strong&gt; - played as normal (forwards). This is default.&lt;br&gt;
&lt;strong&gt;- reverse&lt;/strong&gt; - played in reverse direction (backwards)&lt;br&gt;
&lt;strong&gt;- alternate&lt;/strong&gt; - played forwards first, then backwards&lt;br&gt;
&lt;strong&gt;- alternate-reverse&lt;/strong&gt; - played backwards first, then forwards&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.circle {
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example;
  animation-duration: 4s;
  animation-direction: reverse; 
  border-radius: 50%;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;animation-timing-function&lt;/strong&gt;&lt;br&gt;
It specifies the speed curve of animation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ease - Specifies an animation with a slow start, then fast, then end slowly (this is default)&lt;/li&gt;
&lt;li&gt;linear - Specifies an animation with the same speed from start to end&lt;/li&gt;
&lt;li&gt;ease-in - Specifies an animation with a slow start&lt;/li&gt;
&lt;li&gt;ease-out - Specifies an animation with a slow end&lt;/li&gt;
&lt;li&gt;ease-in-out - Specifies an animation with a slow start and end
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
div {
  width: 100px;
  height: 50px;
  background-color: red;
  font-weight: bold;
  position: relative;
  animation: mymove 5s infinite;
}

.circle-1 {animation-timing-function: linear;}
.circle-2 {animation-timing-function: ease;}
.circle-3 {animation-timing-function: ease-in;}
.circle-4 {animation-timing-function: ease-out;}
.circle-5 {animation-timing-function: ease-in-out;}

@keyframes mymove {
  from {left: 0px;}
  to {left: 300px;}
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle-1"&amp;gt;linear&amp;lt;/div&amp;gt;
&amp;lt;div class="circle-2"&amp;gt;ease&amp;lt;/div&amp;gt;
&amp;lt;div class="circle-3"&amp;gt;ease-in&amp;lt;/div&amp;gt;
&amp;lt;div class="circle-4"&amp;gt;ease-out&amp;lt;/div&amp;gt;
&amp;lt;div class="circle-5"&amp;gt;ease-in-out&amp;lt;/div&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;



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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;animation-fill-mode:&lt;/strong&gt;&lt;br&gt;
It specifies a style for the target element when the animation is not playing. Values of animation-fill-mode are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;none - Default value. Animation will not apply any styles to the element before or after it is executing&lt;/li&gt;
&lt;li&gt;forwards - The element will retain the style values that is set by the last keyframe (depends on animation-direction and animation-iteration-count)&lt;/li&gt;
&lt;li&gt;backwards - The element will get the style values that is set by the first keyframe (depends on animation-direction), and retain this during the animation-delay period&lt;/li&gt;
&lt;li&gt;both - The animation will follow the rules for both forwards and backwards, extending the animation properties in both directions
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt; 
div {
  width: 100px;
  height: 100px;
  background: red;
  position: relative;
  animation-name: example;
  animation-duration: 3s;  
  animation-fill-mode: forwards;
  border-radius: 50%
}

@keyframes example {
  from {top: 0px;}
  to {top: 200px; background-color: blue;}
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div class="circle-1"&amp;gt;&amp;lt;/div&amp;gt;


&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;



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

&lt;/div&gt;



&lt;p&gt;That's it. Seee ya. &lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>animation</category>
      <category>design</category>
    </item>
    <item>
      <title>Node js file system, Easier than we think(1).</title>
      <dc:creator>Abdullah al Mubin</dc:creator>
      <pubDate>Sun, 11 Jun 2023 14:52:57 +0000</pubDate>
      <link>https://forem.com/abdullahmubin/node-js-file-system-easier-than-you-think1-5ck7</link>
      <guid>https://forem.com/abdullahmubin/node-js-file-system-easier-than-you-think1-5ck7</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is Node js?&lt;/strong&gt;&lt;br&gt;
If we want to run javascript without a browser, we must use an environment to execute js code. Using Node js we can create that runtime environment to execute js code.&lt;/p&gt;

&lt;p&gt;It's built upon Chrome's v8 engine using C++.&lt;/p&gt;

&lt;p&gt;We need to install Node js &lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node js&lt;/a&gt; in our system. We also need the editor to write codes. I'm going to use &lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;Visual studio&lt;/a&gt; to write and execute javascript code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is File system?&lt;/strong&gt;&lt;br&gt;
The file system module allows us to work with files in our system. Using the file system we can perform various tasks just like,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Need to know&lt;/strong&gt;&lt;br&gt;
The basic idea is to run a node js file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create File&lt;/strong&gt;&lt;br&gt;
There are three different methods to create new files,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;fs.writeFile()&lt;/li&gt;
&lt;li&gt;fs.open()&lt;/li&gt;
&lt;li&gt;fs.appendFile()&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;here 'fs' represent &lt;code&gt;var fs =require('fs')&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;fs.writeFile()&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;fs.writeFile&lt;/code&gt; method helps us to create and write something on a file if that file does not exist. If that file already exists then it will replace with new content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fs.writeFile( file, data, options, callback )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above line, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file: represent, string, buffer, url or file path&lt;/li&gt;
&lt;li&gt;data: represent specific content.&lt;/li&gt;
&lt;li&gt;options: encoding, mode, flag&lt;/li&gt;
&lt;li&gt;callback: we can set a function that will be called after that (fs.writeFile) function executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br&gt;
write the below code to create a file with its content. Now execute &lt;code&gt;node index.js&lt;/code&gt;(file name) command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fs = require('fs');

//create a file named firstFile.txt:
fs.writeFile('firstFile.txt', 'Hello world!', function (err) {
    if (err) throw err;
    console.log('Saved!');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fzzvks53obaxu2qaasrpn.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%2Fzzvks53obaxu2qaasrpn.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;above code will create a text file named 'firstFile.txt' and its content will be 'Hello world!'&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%2Fqd0retbi0d8xwvrh94nl.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%2Fqd0retbi0d8xwvrh94nl.png" alt=" " width="662" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if you change its content 'Hello world!' to something else, then the will be replaced with the new content. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example with encoding, mode and flag,&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fs.writeFile('firstFile.txt', 'Hello world!',
  {
    encoding: "utf8",
    flag: "w",
    mode: 0o666
  },
  function (err) {
    if (err) throw err;
    console.log('Saved!');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;fs.open()&lt;/strong&gt;&lt;br&gt;
This method works differently than others, it takes the second parameter as a "flag", and if the second parameter is "w" for "writing", then the file is opened for writing. if the file does not exist then it will create an empty file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fs = require('fs');

fs.open('firstFile.txt', 'w', function (err, file) {
  if (err) throw err;
  console.log('Saved!');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;execute node index.js(filename) to see the changes.&lt;/p&gt;

&lt;p&gt;types of flags are described below,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- w:&lt;/strong&gt; Open file for writing. A file is created if it doesn’t exist.&lt;br&gt;
&lt;strong&gt;- w+:&lt;/strong&gt; Open the file to read and write. A file is created if it doesn’t exist.&lt;br&gt;
&lt;strong&gt;- wx:&lt;/strong&gt; It is the same as ‘w’ but fails if the path exists.&lt;br&gt;
&lt;strong&gt;- wx+:&lt;/strong&gt; Open the file to read and write. A file is created if it doesn’t exist.&lt;br&gt;
&lt;strong&gt;- r:&lt;/strong&gt; To open the file to read and throws an exception if the file doesn’t exist.&lt;br&gt;
&lt;strong&gt;- r+:&lt;/strong&gt; Open the file to read and write. Throws an exception if the file doesn’t exist.&lt;br&gt;
&lt;strong&gt;- rs+:&lt;/strong&gt; Open files in synchronous mode to read and write.&lt;br&gt;
&lt;strong&gt;- a:&lt;/strong&gt; Open the file to append. A file is created if it doesn’t exist.&lt;br&gt;
&lt;strong&gt;- ax:&lt;/strong&gt; It is the same as a but fails if the path exists.&lt;br&gt;
&lt;strong&gt;- a+:&lt;/strong&gt; Open the file for reading and appending. A file is created if it doesn’t exist.&lt;br&gt;
&lt;strong&gt;- ax+:&lt;/strong&gt; It is the same as ‘a+’ but fails if the path exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fs.appendFile()&lt;/strong&gt;&lt;br&gt;
It is used to asynchronously append the given data to a file. If the file does not exist, the file will be created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fs.appendFile( path, data[, options], callback )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above line,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;path: It can be string, buffer, url&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;data: It can be string, buffer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;options: encoding, mode, flag&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;callback: we can set a function that will be called after that (fs.appendFile) function executed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;below code helps us to understand more clearly, here, 'utf8' is refers to "encoding"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fs = require('fs');

var data = "appendFileTest";

// Append data to file
fs.appendFile('appendFile.txt', data, 'utf8',
    // Callback function
    function () {
        console.log("Nicely done.")
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run the code with &lt;br&gt;
&lt;code&gt;node index.js // index.js is file name.&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%2Fu1zgzbjwtm723zfw7elm.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%2Fu1zgzbjwtm723zfw7elm.png" alt=" " width="676" height="340"&gt;&lt;/a&gt;&lt;br&gt;
below image shows we created a file and its name "appendFile.txt"&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%2Fh3h7vf1p2sj5lk0nnqdr.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%2Fh3h7vf1p2sj5lk0nnqdr.png" alt=" " width="668" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;that's for today, see yaa.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>react</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
