<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Pavittar Singh]]></title><description><![CDATA[Pavittar Singh]]></description><link>https://blog.pavittarx.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1767635065072/fcbb7de6-8fb9-4f98-877e-c06937baf4b8.png</url><title>Pavittar Singh</title><link>https://blog.pavittarx.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 03:07:44 GMT</lastBuildDate><atom:link href="https://blog.pavittarx.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[HTTP/3: Faster Connections and Better Mobility]]></title><description><![CDATA[HTTP (Hypertext Transfer Protocol) is the backbone of the World Wide Web. It powers virtually every interaction we have online today. Since its public release in 1991, HTTP has evolved alongside the Web to meet the demands of modern software.
Under t...]]></description><link>https://blog.pavittarx.com/http3-faster-connections-and-better-mobility</link><guid isPermaLink="true">https://blog.pavittarx.com/http3-faster-connections-and-better-mobility</guid><category><![CDATA[http3]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 06 Jan 2026 16:35:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/weRQAu9TA-A/upload/ac9ef4f9d38fbf653b7b636ab7bb3e40.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>HTTP</strong> (Hypertext Transfer Protocol) is the backbone of the World Wide Web. It powers virtually every interaction we have online today. Since its public release in 1991, HTTP has evolved alongside the Web to meet the demands of modern software.</p>
<p>Under the hood, HTTP sits on top of three foundational protocols: <strong>TCP</strong>, <strong>IP</strong>, and <strong>UDP</strong>. While supporting actors like DNS and DHCP are essential, TCP, IP, and UDP are the pillars that hold up the Web.</p>
<p><strong>IP (Internet Protocol)</strong> is a protocol provides rules governing the format of data sent over the internet . It enables devices to communicate by assigning unique identifiers known as IP addresses.<br />An IP address is like a physical address that tells where the data is coming from, or needs to reach. An IP address looks like <code>192.168.1.1</code> for IPv4, and <code>2001:0db8:0000:0000:0000:8a2e:0370:7334</code> for IPv6.</p>
<h2 id="heading-transport-protocol-tcp-vs-udp"><strong>Transport Protocol: TCP vs. UDP</strong></h2>
<p>Once we have an address, we need a way to transport the data. This is where the two main "courier" protocols come in.</p>
<p><strong>TCP (Transmission Control Protocol)</strong> TCP defines how to establish and maintain a connection through which applications exchange information. It works alongside IP, often referred to together as <strong>TCP/IP</strong>. TCP is the strict, bureaucratic manager. It is perfectly accurate but can be slow. It checks every packet to ensure nothing is missing. We needed TCP for the web because a missing <code>&lt;/html&gt;</code> tag could break an entire page. We couldn't afford to lose data.</p>
<p><strong>UDP (User Datagram Protocol)</strong> UDP is the "sibling" protocol to TCP. It does the same job but in a fundamentally different way. UDP is fast and reckless. It fires data at the destination without checking if it arrived. It has zero latency but offers no guarantees. It doesn't "lose packets constantly" on purpose, but if a packet <em>does</em> get lost, UDP doesn't care and won't resend it.</p>
<h2 id="heading-the-evolution-of-http">The Evolution of HTTP</h2>
<h3 id="heading-http-11">HTTP 1.1</h3>
<p>We have used HTTP 1.1 since long time. It is text-based, human readable but has a major flaw that it processes requests sequentially.</p>
<p>If the browser needs a CSS file and a JS file, it sends a request for the CSS, waits for it to finish, and <em>then</em> asks for the JS. This creates a queue. If the first file gets stuck, everything behind it waits. This traffic jam is known as <strong>Head-of-Line Blocking.</strong></p>
<h3 id="heading-http-2">HTTP 2</h3>
<p><strong>HTTP/2</strong>, released in 2015, introduced <strong>Multiplexing</strong>. This allowed the browser to send requests for Image A, Image B, and Script C simultaneously over a single TCP connection.</p>
<p>It also introduced other critical upgrades:</p>
<ul>
<li><p><strong>Header Compression:</strong> This reduces the amount of repetitive data sent over the wire.</p>
</li>
<li><p><strong>Server Push:</strong> The server anticipates your needs. If you request <code>index.html</code>, it can push <code>style.css</code> and <code>script.js</code> over the same connection immediately—without waiting for you to ask.</p>
</li>
</ul>
<p>However, HTTP/2 had a hidden flaw. While it seemed perfect, it could not solve <strong>Head-of-Line (HOL) Blocking</strong> at the <em>TCP</em> level. Because all files share a single TCP connection, you run the risk of <strong>everything</strong> getting blocked if a single packet is lost due to spotty Wi-Fi or mobile data.</p>
<h2 id="heading-http3">🔒 HTTP/3</h2>
<p><strong>HTTP/3 is a revolution.</strong> It discards TCP entirely in favor of UDP (via <strong>QUIC</strong> – Quick UDP Internet Connections).</p>
<p>TCP is simply too rigid. The "Head-of-Line Blocking" problem inherent to TCP could not be solved without updating every operating system in the world. We needed a blank slate to build a better protocol, and UDP provided exactly that. QUIC essentially builds a new, smarter transport layer on top of UDP.</p>
<p>In <strong>HTTP/2</strong>, a single lost packet blocks the complete transmission. In <strong>HTTP/3</strong>, every file (or stream) has its own lane. If a packet for a single image is lost, only the stream for that specific image pauses. All other resources—CSS, scripts, text—keep downloading without interruption.</p>
<p>HTTP/3 also solves the <strong>mobility problem</strong>. Have you ever had a download fail when you walked out of your house and switched from Wi-Fi to 4G? That is a TCP problem (because your IP address changed). HTTP/3 solves this by using a <strong>Connection ID</strong> instead of an IP address. Even if you change networks, the server recognizes your ID, and the download resumes seamlessly.</p>
<p>Finally, in HTTP/3, <strong>security is baked in</strong>. It uses TLS 1.3 by default. You literally cannot have an unencrypted HTTP/3 connection. There is no <code>http://</code> 🔓, only <code>https://</code> 🔒.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767717235128/814de00e-96b5-4495-9147-ed258f879da0.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-quic-lifecycle">The QUIC Lifecycle</h2>
<p>In TCP, you shake hands to connect, <em>then</em> shake hands to encrypt. In QUIC, you do both at once.</p>
<p><strong>A. Handshake (0-RTT Magic)</strong> During the first visit, the client sends both encryption keys and connection parameters immediately. The server acknowledges them and opens the connection. For every repeat visit, there is <strong>Zero Round Trip Time (0-RTT)</strong>. Since the client has talked to the server before, it uses a saved "resumption ticket" to send encrypted data in the very first packet.  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767717100885/473392ce-0f5c-4f9a-af5e-d4486fc38260.webp" alt class="image--center mx-auto" /></p>
<p><strong>B. Data Transmission (Frames &amp; Streams)</strong> Once connected, HTTP/3 doesn't send a single blob of data. It organizes data into a hierarchy:</p>
<ol>
<li><p>Every file is assigned its own <strong>Stream ID</strong>. These streams are multiplexed but remain logically independent.</p>
</li>
<li><p>Data is chopped into <strong>Frames</strong> inside a stream.</p>
</li>
<li><p>Frames are wrapped inside <strong>QUIC Packets</strong>.</p>
</li>
<li><p>QUIC packets are wrapped inside <strong>UDP Datagrams</strong>.</p>
</li>
</ol>
<p><em>The key difference:</em> In HTTP/2, the browser knew the streams were separate, but TCP didn’t. In HTTP/3, QUIC knows they are different, so it handles packet loss per stream.</p>
<p><strong>C. Header Compression (QPACK)</strong> HTTP/2 used <strong>HPACK</strong>, which relied on packets arriving in perfect order. Since QUIC allows packets to arrive out of order, HPACK breaks. Therefore, HTTP/3 introduces <strong>QPACK</strong> to handle compression without blocking.</p>
<h3 id="heading-the-architectural-shift"><strong>The Architectural Shift</strong></h3>
<p>In HTTP/2, responsibilities were segmented into distinct protocols. HTTP/3 consolidates transport and security responsibilities into a new protocol that runs in User Space (the application).</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>HTTP/2 Architecture</strong></td><td><strong>HTTP/3 Architecture</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Application Layer</strong></td><td>Handles requests and multiplexing logic.</td><td>Handles only request methods (GET/POST).</td></tr>
<tr>
<td><strong>Security Layer</strong></td><td><strong>TLS</strong> handles encryption via a separate handshake over TCP.</td><td><strong>QUIC</strong> handles encryption (TLS 1.3) intrinsically during the handshake.</td></tr>
<tr>
<td><strong>Transport Layer</strong></td><td><strong>TCP</strong> handles reliability, ordering, and congestion control in the OS Kernel.</td><td><strong>QUIC</strong> handles streams, reliability, and congestion control in the Application (Browser).<strong>UDP</strong> is used strictly as an envelope to traverse firewalls. It provides no reliability guarantees.</td></tr>
<tr>
<td><strong>Network Carrier</strong></td><td><strong>IP</strong> handles routing.</td><td>IP handles routing.</td></tr>
</tbody>
</table>
</div><p>QUIC treats UDP like a blank piece of paper. It writes its own reliability rules, encryption rules, and connection IDs onto that paper. To the outside world (the router), it looks like a simple UDP packet. But inside, it is a sophisticated, reliable QUIC packet.</p>
<p>By moving reliability logic from the <strong>OS Kernel (TCP)</strong> to the <strong>Application Layer (QUIC)</strong>, HTTP/3 finally eliminates Head-of-Line Blocking and modernizes the web</p>
]]></content:encoded></item><item><title><![CDATA[Don’t Block, Just Queue: The Art of Asynchronous Traffic Control.]]></title><description><![CDATA[Modern systems handle traffic at a staggering scale. Google processes approximately ~190k searches per second, based on an estimated 16.4 billion searches per day. IoT devices generate data ranging from a few kilobytes to 1GB per second. A single Boe...]]></description><link>https://blog.pavittarx.com/dont-block-just-queue-the-art-of-asynchronous-traffic-control</link><guid isPermaLink="true">https://blog.pavittarx.com/dont-block-just-queue-the-art-of-asynchronous-traffic-control</guid><category><![CDATA[message queue]]></category><category><![CDATA[kafka]]></category><category><![CDATA[event streaming]]></category><category><![CDATA[scale]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 30 Dec 2025 15:43:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/qZ6if8WXl7E/upload/1587378189caf40d8eb18e810ed976e0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Modern systems handle traffic at a staggering scale. Google processes approximately <strong>~190k searches per second</strong>, based on an estimated 16.4 billion searches per day. IoT devices generate data ranging from a few kilobytes to <strong>1GB per second</strong>. A single Boeing 787 aircraft produces <strong>~5GB of data per second</strong> while in flight.</p>
<p>But these numbers only tell half the story. This is just the data arriving at the "front door."</p>
<p>Once that data enters the system, the volume explodes. A single request often triggers multiple downstream actions—database writes, analytics logging, notifications, and third-party API calls. <strong>5GB of external traffic can easily turn into 50GB of internal traffic.</strong></p>
<p>How do we manage this load without the servers catching fire? <strong>Message Queues.</strong></p>
<p>Message Queues do not magically reduce the size of the data. Instead, they manage <em>how</em> and <em>when</em> we process it. When that Boeing 787 dumps 5GB of data, a traditional system tries to process it all immediately. The database locks up, the CPU spikes to 100%, and the system crashes. This is a <strong>synchronous failure</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767085059370/f7497709-b12a-417f-8c14-33af69a31141.webp" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Message Queues <strong>decouple</strong> the components of the system, so they can be updated independently.</p>
</li>
<li><p>It smoothens the traffic flow, during traffic spikes the system does not crash it just takes longer to process the messages. It continues processing at its steady rate.</p>
</li>
<li><p>Instead of single service trying to do all the work, the work is distributed among different components. The Ingestion Service does not wait for Analytics Service to finish, it keeps processing its batch even if the Analytics Service fails.</p>
</li>
<li><p>Message Queues also increase the availability and performance of the system.</p>
</li>
</ol>
<p>Event Streaming platforms are more advanced counterparts of Messaging Queues which are heavily used in modern Systems. <strong>Amazon SQS, ZeroMQ, RabbitMQ, Apache RocketMQ, Apache ActiveMQ,</strong> are some prominent Messaging Queues. Meanwhile, <strong>Apache Kafka, Apache Pulsar</strong> are some of the popular event streaming platforms.</p>
<h2 id="heading-the-anatomy-how-it-works">The Anatomy: How it Works?</h2>
<p>In order to understand this further, we need to define the 4 organs of the system —</p>
<ul>
<li><p><strong>The Producer:</strong> The service creating the data (e.g., The User Interface or an IoT sensor).</p>
</li>
<li><p><strong>The Message:</strong> The data packet itself (containing the Payload + Headers).</p>
</li>
<li><p><strong>The Broker (The Post Office):</strong> The physical server that receives, routes, and stores the message.</p>
</li>
<li><p><strong>The Consumer:</strong> The service that takes the message off the queue and processes it.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767108395414/504a1615-a5a3-4ce8-9969-7a5cfc8a7137.webp" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h2 id="heading-queues-vs-event-streams">Queues v/s Event Streams</h2>
<p>While they look similar on the surface (data in, data out), technically they operate very differently. We can divide them into the <strong>Queue Model</strong> (Traditional) and the <strong>Stream Model</strong> (Modern).</p>
<ol>
<li><strong>The Queue Model (RabbitMQ, SQS)</strong></li>
</ol>
<p>Think of this like a task list: once a task is done, it is crossed off the list. The focus is on <strong>delivery</strong>. The goal is to get the message to a consumer and delete it as fast as possible.</p>
<ul>
<li><p><strong>Producer:</strong> Sends the message.</p>
</li>
<li><p><strong>The Exchange (Router):</strong> <em>Specific to advanced queues like RabbitMQ.</em> The producer sends data here first. Based on configured rules, the exchange decides which specific queue receives the message.</p>
</li>
<li><p><strong>The Queue (Buffer):</strong> A transient storage area that holds messages until they are consumed.</p>
</li>
<li><p><strong>The Consumer:</strong> The worker that processes the message.</p>
</li>
<li><p><strong>ACK (The Delete Command):</strong> Once the consumer finishes, it sends an acknowledgment (ACK). The queue then deletes the message immediately.</p>
</li>
</ul>
<ol start="2">
<li><strong>The Event Streaming Model (Kafka/Pulsar)</strong></li>
</ol>
<p>This model focuses on <strong>storage and history</strong>. The goal is to record what happened, in order, and let different workers consume the history at their own pace.</p>
<ul>
<li><p><strong>Producer:</strong> Emits "events" (facts that happened, e.g., "User Clicked").</p>
</li>
<li><p><strong>The Topic:</strong> The category of events (e.g., 'Clicks', 'Invoices').</p>
</li>
<li><p><strong>The Partition (Scalability Engine):</strong> A topic can be too massive for one server, so it is split into partitions. Messages are appended to the end of a partition log file. <em>Note: Order is guaranteed only within a partition.</em></p>
</li>
<li><p><strong>Offset (The Bookmark):</strong> Unlike queues, messages stay in the stream. The offset is just a number tracking where a consumer is. Different consumers can be at different offsets.</p>
</li>
<li><p><strong>Consumer Group:</strong> If a topic has 4 partitions and you have a Consumer Group with 4 consumers, the system assigns one consumer to each partition for parallel processing.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767108403003/ad357058-8eb8-4517-a111-bca2c2d78d85.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-designing-the-rails-key-architecture-decisions">Designing the Rails — Key Architecture Decisions</h2>
<p>Once you are ready to scale, you cannot just "pick a queue." You need to match the tool to your traffic shape. Here are the seven critical decisions you must make.</p>
<ol>
<li><p><strong>Format &amp; Size of Messages</strong></p>
<p> Are you sending <strong>small JSON notifications or massive video logs</strong>? Most messaging tools (like Kafka and SQS) are optimized for small payloads (typically under 1MB). If you push large files directly into the queue, performance will degrade instantly. <strong>The Fix:</strong> Use the <strong>Claim Check Pattern</strong>. Upload the large file to object storage (like S3) first, then pass only the reference URL in the message payload.</p>
</li>
<li><p><strong>Topology: Point-to-Point vs. Pub/Sub</strong></p>
<p> This defines the relationship between the sender and the receiver.</p>
<ul>
<li><p><strong>Point-to-Point (Work Queues):</strong> This is about <strong>competition</strong>. Even if 50 consumers are listening, a specific message is handled by <em>only one</em> of them. Use this for heavy background tasks (e.g., resizing an image) where you want to distribute the workload without duplicating effort.</p>
</li>
<li><p><strong>Publish/Subscribe (Pub/Sub):</strong> This is about <strong>broadcasting</strong>. The sender sends a message to a topic, and <em>every</em> active service subscribed to that topic gets its own copy. Use this for event notifications (e.g., a "User Signup" event triggers a Welcome Email, a Database Entry, and an Analytics Log simultaneously).</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767108511838/7455ee1d-0ba9-4852-ad18-035c4988bc3c.webp" alt class="image--center mx-auto" /></p>
<ol start="3">
<li><p><strong>Delivery Semantics (Reliability)</strong></p>
<p> How catastrophic is it if a message is lost? You typically choose between three tiers:</p>
<ul>
<li><p><strong>At-Most-Once (Fire &amp; Forget):</strong> High performance, but if the server crashes, the data is gone. Best for IoT sensor data where missing one temperature reading is acceptable.</p>
</li>
<li><p><strong>At-Least-Once (The Standard):</strong> The message is guaranteed to arrive, but it might arrive twice. Your consumer must be <strong>idempotent</strong> (able to handle duplicates without errors).</p>
</li>
<li><p><strong>Exactly-Once:</strong> The holy grail. It guarantees a single delivery but is expensive in terms of latency and complexity. Best reserved for financial transactions.</p>
</li>
</ul>
</li>
<li><p><strong>Order of Delivery</strong></p>
<p> Does Message A <em>have</em> to be processed before Message B? Strict ordering is the enemy of scale because it forces you to use a single consumer. To get around this, we use <strong>Partitioned Ordering</strong>. You guarantee order only within a specific group (e.g., "All events for User ID 101 are ordered"), but different groups are processed in parallel.</p>
</li>
<li><p><strong>Delivery Mechanism: Push vs. Pull</strong></p>
<p> This defines who controls the flow of data.</p>
<ul>
<li><p><strong>Push (e.g., RabbitMQ):</strong> The <strong>Broker</strong> forces messages onto the consumer. This offers the lowest latency but risks overwhelming the consumer during traffic spikes.</p>
</li>
<li><p><strong>Pull (e.g., Kafka, SQS):</strong> The <strong>Consumer</strong> requests messages when it is ready. This provides excellent flow control (the consumer is never overwhelmed) but introduces a slight latency delay due to polling.</p>
</li>
</ul>
</li>
<li><p><strong>Data Retention: Queue vs. Log</strong></p>
<p> Do you want to delete the message or keep it?</p>
<ul>
<li><p><strong>Traditional Queues (RabbitMQ/SQS):</strong> These are <strong>ephemeral</strong>. The goal is to delete the message as soon as it is processed.</p>
</li>
<li><p><strong>Event Streams (Kafka/Pulsar):</strong> These are <strong>durable</strong>. The message is stored like a log entry for a set time (e.g., 7 days) even after it is read. This allows you to "replay" history if a bug corrupts your database.</p>
</li>
</ul>
</li>
<li><p><strong>Throughput vs. Latency</strong></p>
<p> You generally cannot maximize both.</p>
<ul>
<li><p><strong>Low Latency:</strong> You process messages immediately as they arrive. This limits your total throughput.</p>
</li>
<li><p><strong>High Throughput:</strong> You move massive amounts of data (e.g., 10GB/sec) by <strong>batching</strong> messages together. This increases latency because the system must wait to fill the batch before sending it.</p>
</li>
</ul>
</li>
</ol>
<p>Message Queues are the unsung heroes of modern architecture. They allow our systems to breathe, to buffer, and to survive the inevitable chaos of the real world. Whether you are building a simple email notifier or a global streaming platform, the principle remains the same: <strong>Don't block. Just queue.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Design Choices for Location Based Services III]]></title><description><![CDATA[Let’s jump back in where we left off with Quad Trees. You remember those, right? Or you are experiencing memory leaks just like me?
Need a refresher? didn’t you read the blog I sent you? I know you didn’t. Ah! no worries, we’ll figure it out.
Google ...]]></description><link>https://blog.pavittarx.com/design-choices-for-location-based-services-iii</link><guid isPermaLink="true">https://blog.pavittarx.com/design-choices-for-location-based-services-iii</guid><category><![CDATA[s2]]></category><category><![CDATA[uber h3]]></category><category><![CDATA[h3]]></category><category><![CDATA[google s2]]></category><category><![CDATA[#LocationServices ]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Mon, 15 Dec 2025 19:30:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/oCMkiLOSz44/upload/2666dea0557b9195e9d569f0a9de4a18.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let’s jump back in where we left off with Quad Trees. You remember those, right? Or <strong>you are</strong> experiencing memory leaks just like me?</p>
<p>Need a refresher? didn’t you read the blog I sent you? I know you didn’t. Ah! no worries, we’ll figure it out.</p>
<h1 id="heading-google-s2-geometry">Google S2 Geometry</h1>
<p>S2 (aka S2 Geometry Library) is <strong>a</strong> <strong>spherical geometry library</strong> and <strong>spatial indexing system</strong>. It is an open-source C++ library developed and used extensively by Google.</p>
<p>It <strong>works directly on a sphere</strong> instead of projecting the world onto a flat 2D plane. This makes it robust for global applications, avoiding the distortions or seams—like <strong>those at the</strong> Poles or the International Date Line—that plague flat maps.</p>
<p>Internally, S2 is a set of math functions mapping 2D (latitude, longitude) points into S2 cell IDs. <strong>This simplifies</strong> 2D coordinates (double, double) into <strong>highly cacheable,</strong> 1D 64-bit integer lookups.</p>
<p>The S2 library solves a fundamental problem in global mapping: <strong>how to represent and query locations (like points, lines, and polygons)</strong> anywhere on Earth without the distortion, discontinuities, and singularities that occur when using traditional planar map projections (like the Mercator projection).</p>
<h2 id="heading-s2-architecture">S2 Architecture</h2>
<p>S2 performs a 3-step transformation:</p>
<ol>
<li><p><strong>Sphere to Cube:</strong> It projects the Earth onto the six square faces of a cube. This avoids the singularities at the poles and reduces the distortion found in traditional map projections.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765823538764/d9e5d2c0-7d0c-4d0f-afe2-3531dc155c88.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Hierarchical Decomposition:</strong> Each face is divided into a <strong>quadtree</strong>. This subdivision can go as deep as <strong>Level 30</strong>, where a single leaf node represents roughly <strong>0.74 cm² to 1 cm²</strong> of the Earth's surface.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765823554077/03aa247a-f25a-409e-abbe-7b7bace3dc59.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Linearization:</strong> Finally, S2 uses a <strong>Hilbert Space-Filling Curve</strong> to traverse and number the cells. This converts 2D positions into a 1D index (the Cell ID).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765823605307/38c1aa71-aa1c-48f1-9e3d-1850a15c68af.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-google-s2-visual-demo-httpss2vizpavittarxcomhttpss2vizpavittarxcom"><strong>Google S2 Visual Demo</strong> - <a target="_blank" href="https://s2viz.pavittarx.com/">https://s2viz.pavittarx.com/</a></h3>
<h3 id="heading-what-is-hilbert-curve"><strong>What is Hilbert Curve?</strong></h3>
<p>The <strong>Hilbert Curve</strong> is the secret sauce of the S2 Library. It is used to map the sphere onto a <strong>1D index</strong>.</p>
<p>The Hilbert Curve has a crucial property: two points that are close on the curve will also be close on the map. Hence, the Hilbert Curve <strong>preserves spatial locality</strong>.</p>
<p>Google S2 powers a variety of applications and systems. It is employed by <strong>Google Maps</strong> and <strong>MongoDB</strong> (for its geospatial indexing). It is famously used by <strong>Pokémon Go</strong> for the placement and distribution of in-game assets.</p>
<h1 id="heading-uber-h3">Uber H3</h1>
<p>Uber’s H3 (Hexagonal Hierarchical Spatial Index) is designed for smoothing, movement, and analytics, whereas S2 is tailored more towards storage and containment. H3 utilizes a hexagonal system for geospatial indexing, a departure from the traditional square-based approach used in previous algorithms.</p>
<p><strong>Uber H3 (Hexagonal Index)</strong> is built for <strong>analyzing movement—like tracking rides or visualizing traffic</strong>. S2, on the other hand, <strong>is better for just storing location data.</strong></p>
<p>Quadtrees use squares, which have <strong>8 neighbors (4 distinct edges and 4 corners)</strong>. Consequently, moving <strong>diagonally covers more distance</strong> than moving horizontally, causing <strong>heatmaps to look blocky</strong>—much like Minecraft. Hexagons, conversely, create smooth and balanced grids. A <strong>hexagon has 6 neighbors</strong>, each <strong>equidistant from the center,</strong> meaning neighbor traversal uses the same math in every direction. This results in uniform movement and heatmaps that look smooth and natural.</p>
<h2 id="heading-h3-architecture">H3 Architecture</h2>
<p>Standard maps often use cylindrical projections (like Mercator) which distort size near the poles. H3 takes a completely different approach to minimize this distortion.</p>
<ol>
<li><p><strong>Sphere to Icosahedron (20 sided die)</strong></p>
<p> It projects the Earth's spherical surface onto these 20 flat triangular faces. Because an icosahedron approximates a sphere much better than a cylinder or a cube does, the distortion of landmasses is significantly lower.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765827475704/b4af2434-009a-4659-a214-23a73d52f194.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<ol start="2">
<li><p><strong>Hexagons replace triangles</strong></p>
<p> H3 fills these faces of Icosahedron with hexagons. A single triangle on a grid actually only has 3 edge neighbors, but the <em>vertices</em> of the icosahedron meet in complex ways (<strong>5 triangles meet at a point)</strong> this results in <strong>(12) neighbors</strong> which makes it <strong>harder to calculate movement</strong>. Additionally, <strong>hexagons are equidistant. distance from center of one hexagon is equal to another.</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765827455967/5a0d9eb4-7a85-4cab-bc82-c71785058a0d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Aperture-7 System</strong><br /> H3 has 16 levels of resolution, and each child splits into 7 child hexagons. H3 uses fuzzy containment, as 7 hexagons <strong>do not</strong> fit perfectly inside a larger hexagon. They spill over the edges slightly. You cannot say a child is 100% inside parent. It is excellent for gradients which naturally blur data, exactly what is needed for heatmaps or pricing. you want them to transition smoothly not cut sharply.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765827443779/237232c2-61b4-4860-9c20-90f144f91c67.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>Pentagon is here.. Well, the mathematical one, not the military.</p>
<p>In order to make the math work, H3 hides 12 pentagons (5 sided polygon) at specific points on Earth (mostly at oceans) to close the sphere. Why you ask? You cannot tile a sphere <em>perfectly</em> with only hexagons (mathematically impossible; it's Euler's formula).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765827422180/9085978f-3a72-41e8-b491-33f707ca5c15.png" alt class="image--center mx-auto" /></p>
<p>If a cell has high demand, Uber smoothens out the surge to neighboring cells, so you do not need sharp increase in price just walking 10 meters.</p>
<h2 id="heading-h3-visualizer-httpsh3vizpavittarxcomhttpsh3vizpavittarxcom">H3 Visualizer - <a target="_blank" href="https://h3viz.pavittarx.com/">https://h3viz.pavittarx.com/</a></h2>
<p><strong>Related Links ...</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=eTYsIePy5zg">Why every world map is wrong - Kayla Wolf</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=lPNrtjboISg">How the World Map Looks Wildly Different Than You Think</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=3s7h2MHQtxc">Hilbert Curve</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Design Choices for Location Based Services / Part II]]></title><description><![CDATA[As we've seen, calculating locations in 2D space using latitude and longitude can be compute-intensive and time-consuming. However, queries and lookups in 1D are significantly faster. Therefore, we are exploring methods to map 2D coordinates (lat, lo...]]></description><link>https://blog.pavittarx.com/design-choices-for-location-based-services-part-ii</link><guid isPermaLink="true">https://blog.pavittarx.com/design-choices-for-location-based-services-part-ii</guid><category><![CDATA[designing-location-based-services-ii]]></category><category><![CDATA[#LocationServices ]]></category><category><![CDATA[Location Intelligence Market]]></category><category><![CDATA[gps]]></category><category><![CDATA[quadtree]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 09 Dec 2025 16:58:22 GMT</pubDate><content:encoded><![CDATA[<p>As we've seen, calculating locations in 2D space using <strong>latitude and longitude</strong> can be <strong>compute-intensive</strong> and <strong>time-consuming</strong>. However, queries and lookups in <strong>1D</strong> are significantly faster. Therefore, we are exploring methods to map 2D coordinates (lat, long) to 1D space.</p>
<p>This can be achieved in two main ways: <strong>hash-based</strong> and <strong>tree-based</strong> methods. We've already examined hash-based approaches, namely <strong>Even Grid</strong> and <strong>GeoHash</strong>. In this blog post, we will be discussing <strong>Quad Tree</strong>.</p>
<h2 id="heading-quad-tree">Quad Tree</h2>
<p>A <strong>Quadtree</strong> is a tree data structure used to efficiently <strong>organize and partition a two-dimensional space</strong>. It recursively divides a region into <strong>four quadrants</strong> (<strong>quads</strong>) until the content of a quadrant meets a certain condition (e.g., a maximum number of points). It is an effective method for <strong>spatial indexing</strong>, allowing for fast lookups and queries on data points (like latitude and longitude) that are clustered in a 2D plane.</p>
<p>A Quadtree is an <strong>in-memory data structure</strong>, not a database solution. It typically runs on a <strong>Location-Based Service (LBS) Server</strong> and is built during the server's startup time. The following steps detail the construction process:</p>
<ol>
<li><p>The process begins with a single node (the <strong>root</strong>) that represents the entire 2D space being indexed (e.g., a city map).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765295833458/ba03a3db-e0c0-416e-b58c-79b2b99501a6.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>A node is split into four child regions if it contains more data points or objects than a predefined <strong>maximum capacity (threshold)</strong>.</p>
</li>
<li><p>The four child regions are typically designated as <strong>North-West, North-East, South-East, and South-West</strong>.</p>
</li>
<li><p>The points within the parent node are then redistributed into the new child quadrants based on their coordinates.</p>
</li>
<li><p>This same splitting rule is <strong>applied recursively</strong> to each of the four child nodes.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765295862955/9ffb19b6-ad62-49d0-8621-5b433d96e5e3.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>The process stops when a node (<strong>a leaf</strong>) satisfies the stopping condition—usually containing less than the maximum capacity of points or reaching a maximum defined depth.</p>
</li>
</ol>
<p>The Quadtree follows <strong>adaptive precision</strong>, meaning the structure automatically adjusts to the data density. It saves computational resources by not over-dividing empty regions. It is due to this property that it is used for <strong>collision detection</strong> in games and <strong>Level of Detail (LOD) rendering</strong> in graphics.</p>
<p>While Quadtrees are excellent for spatial analysis, it is useful to compare them to alternative methods. For instance, <strong>Geohash</strong> is typically preferred for <strong>high-volume writes</strong> (like tracking moving objects) and simplicity, while Quadtrees excel for complex spatial analysis and non-uniform data distribution.</p>
<p>Additionally, as the server builds the Quadtree at startup, indexing <strong>millions of records</strong> can result in the Location-Based Service (LBS) taking <strong>a few minutes to become operational</strong>. This creates a period of <strong>service unavailability</strong> during the startup process. To mitigate this downtime, a deployment strategy of <strong>incremental rollout</strong> (or canary deployment) can be used, updating only a small subset of servers at a time while maintaining the availability of the others.</p>
<p>This deployment method, however, may result in some servers serving <strong>stale data</strong> for a short period. An alternative is to update the Quadtree <strong>as changes occur</strong> (on-the-fly). While this ensures data freshness, it significantly <strong>complicates the design</strong> because it necessitates implementing <strong>locking mechanisms</strong> within the Quadtree structure to ensure <strong>thread safety</strong> in a multi-threaded environment.</p>
<p><strong>Additional Reads &amp; Watch</strong></p>
<ul>
<li><p>Quadtree - <a target="_blank" href="https://www.youtube.com/watch?v=jxbDYxm-pXg">https://www.youtube.com/watch?v=jxbDYxm-pXg</a></p>
</li>
<li><p>Booking.com uses Quadtree - <a target="_blank" href="https://medium.com/booking-com-development/how-to-search-point-of-interest-poi-markers-on-a-map-efficiently-b5f3f37a914a">https://medium.com/booking-com-development/how-to-search-point-of-interest-poi-markers-on-a-map-efficiently-b5f3f37a914a</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Design choices for building Location Based Services / Part I]]></title><description><![CDATA[Location-based services (LBS) have become an inherent part of our daily lives. From shopping orders, booking taxis, and finding nearby stores to building travel plans—everything is built upon location-based services.
Going down this rabbit hole, your...]]></description><link>https://blog.pavittarx.com/design-choices-for-building-location-based-services-part-i</link><guid isPermaLink="true">https://blog.pavittarx.com/design-choices-for-building-location-based-services-part-i</guid><category><![CDATA[location services]]></category><category><![CDATA[location ]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 25 Nov 2025 18:10:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_jFZFtCVdbc/upload/da224f93895e53ad6e278b18bb449267.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Location-based services (LBS) have become an inherent part of our daily lives. From shopping orders, booking taxis, and finding nearby stores to building travel plans—everything is built upon location-based services.</p>
<p>Going down this rabbit hole, your design choices will depend on the type of location service you are building. Is it a <strong>static location</strong> (a shop or business that doesn't move) or a <strong>dynamic location</strong> (nearby friends, a food order being delivered, a moving taxi)?</p>
<p>Let’s start with mapping static locations. The first intuitive idea is to draw a circle of a certain radius (say, 5km) and search for any businesses within that circle. This translates to querying by latitude and longitude in a SQL database. However, this requires searching 2D data; you must query for longitudes and latitudes separately and then calculate intersections to find the locations of interest.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764121078969/5c40a7eb-8e6a-4f47-85d7-5cd2821c4c02.png" alt class="image--center mx-auto" /></p>
<p><strong>The Problem:</strong> As the dataset grows, this becomes both slow and compute-intensive. While applying database indexes can improve performance, we are still left with a massive number of data points to intersect, which doesn't solve the scalability issue.</p>
<p>The earlier approach shows us that 2D search is inefficient. The solution? Converting that 2D data into a 1D string. This is exactly what specialized databases do (e.g., Geo operations in Redis, PostGIS extension for Postgres).</p>
<p><strong>What is a Geohash?</strong> It is an indexing method for geographical data. Generally, there are two types of spatial indexing:</p>
<ul>
<li><p><strong>Hash-Based:</strong> Even Grid, Geohash, Cartesian Tiers, etc.</p>
</li>
<li><p><strong>Tree-Based:</strong> Quadtree, Google S2, R-Tree, etc.</p>
</li>
</ul>
<p>Broadly speaking, these methods divide the map into smaller areas and build indexes for faster searching. Geohash, Quadtree, and Google S2 are the most popular.</p>
<h2 id="heading-even-grid">Even Grid</h2>
<p>This method works by dividing the map into a grid of multiple smaller, evenly divided areas (buckets). An area can contain multiple businesses, but a specific business belongs to only one grid cell.</p>
<p>Each object (user, restaurant, taxi) is assigned to a cell based on GPS coordinates. To find a taxi, we simply look for taxis in the cell you are currently in. This makes the search extremely fast.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764089814467/10aa7bce-7de3-4c4e-8bde-51c3804cdfa7.png" alt class="image--center mx-auto" /></p>
<p><strong>The Drawback:</strong> While the grids are of even size, the <em>data</em> is not evenly distributed. A grid in Delhi might hold 10,000 items, while a grid in rural area might hold zero. This creates "hot spots" and empty memory. Additionally, if a user is on the edge of a grid, finding the nearest items requires checking neighboring cells, which adds complexity to the logic.</p>
<h2 id="heading-geohash">GeoHash</h2>
<p>Geohash is generally superior to the simple Even Grid approach. It reduces 2D latitude/longitude data into a 1D string of letters and digits.</p>
<p>It works by recursively dividing areas into smaller and smaller grids with each additional character. Geohash is like a digital map that lets you zoom in. It supports 12 precision levels, though levels 4-6 are sufficient for most LBS applications.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Level (Char Length)</strong></td><td><strong>Cell Size (Approx)</strong></td><td><strong>Use Case</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>1</strong></td><td>5,000km x 5,000km</td><td>Continent / Large Region</td></tr>
<tr>
<td><strong>2</strong></td><td>1,250km x 625km</td><td>Large State / Country</td></tr>
<tr>
<td><strong>3</strong></td><td>156km x 156km</td><td>Cluster of Cities</td></tr>
<tr>
<td><strong>4</strong></td><td>39km x 19km</td><td>A City</td></tr>
<tr>
<td><strong>5</strong></td><td>4.9km x 4.9km</td><td>A District / Neighborhood</td></tr>
<tr>
<td><strong>6</strong></td><td><strong>1.2km x 0.6km</strong></td><td><strong>A few city blocks (Common for LBS)</strong></td></tr>
<tr>
<td><strong>7</strong></td><td>150m x 150m</td><td>A large building footprint</td></tr>
<tr>
<td><strong>8</strong></td><td>38m x 19m</td><td>A house property</td></tr>
<tr>
<td><strong>9</strong></td><td>4.8m x 4.8m</td><td>A specific room / parking spot</td></tr>
</tbody>
</table>
</div><p>We start by dividing the world into 4 quadrants, based on bits (0 or 1) -</p>
<ul>
<li><p>Go Left: Longitude range [-180, 0] is represented by 0</p>
</li>
<li><p>Go Right: Longitude range [0, 180] is represented by 1</p>
</li>
<li><p>Go Down: Latitude range [-90, 0] is represented by 0</p>
</li>
<li><p>Go Up: Latitude range [0, 90] is represented by 1</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764091061160/37f004c8-45ea-4973-873f-b970f4a06ef6.png" alt class="image--center mx-auto" /></p>
<p>We continue dividing these quadrants recursively until we reach the required granularity. These bits are then grouped (5 bits at a time) to form characters using <strong>Base32 encoding</strong>. The alphabet used is <code>0-9</code> and <code>b-z</code> (letters like a, i, l, and o are missing to avoid confusion).</p>
<ul>
<li><p><strong>Level 1:</strong> The world is divided into 32 rectangles (e.g., <code>d</code>, <code>e</code>, <code>f</code>).</p>
</li>
<li><p><strong>Level 2:</strong> Each rectangle is further divided into 32 smaller ones (e.g., <code>da</code>, <code>db</code>).</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764091692724/9344274e-eccd-458d-b91d-921ca005e03c.png" alt class="image--center mx-auto" /></p>
<p>This is a global standard. For example:</p>
<ul>
<li><p><code>d</code>: Covers the Eastern US and the Atlantic.</p>
</li>
<li><p><code>e</code>: Covers Europe and West Africa.</p>
</li>
<li><p><code>f</code>: Covers Eastern Canada and Greenland.</p>
</li>
</ul>
<p><strong>The Advantage:</strong> This allows for <strong>Prefix Searching</strong>. If User A is at <code>tdr12</code> and User B is at <code>tdr15</code>, you know they are close because they share the prefix <code>tdr1</code>.</p>
<p><strong>The Edge Case (Boundary Issues):</strong> Geohash works best most of the time, but like physical countries, it has boundary issues. Geohash guarantees that if two hashes share a long prefix, they are close. However, <strong>the opposite is not true</strong>: if there is no shared prefix, it does <em>not</em> mean the places are far apart.</p>
<p>For example, take two people standing in Greenwich Park (the Prime Meridian):</p>
<ul>
<li><p><strong>Person Left:</strong> Geohash <code>gcpvj...</code></p>
</li>
<li><p><strong>Person Right:</strong> Geohash <code>u10hb...</code></p>
</li>
</ul>
<p>A query <code>SELECT * WHERE geohash LIKE 'gcpv%'</code> will miss the person standing one meter away because their hash starts with <code>u</code>.</p>
<p>To solve this, we cannot rely on the prefix alone. The standard solution is to fetch businesses not just from the current cell, but also from the <strong>8 neighboring cells</strong>. This ensures complete coverage and can be done in constant time.</p>
<h2 id="heading-up-next">Up Next …</h2>
<ul>
<li><p><strong>Quad Tree</strong></p>
</li>
<li><p><strong>Google S2</strong></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Unique IDs... Which is the best?]]></title><description><![CDATA[When thinking of generating unique IDs, the very first approach that comes to mind is using auto-incrementing integer IDs in traditional databases. This works well for small systems or systems with a single database. However, you cannot use this meth...]]></description><link>https://blog.pavittarx.com/unique-ids-which-is-the-best</link><guid isPermaLink="true">https://blog.pavittarx.com/unique-ids-which-is-the-best</guid><category><![CDATA[distributed system]]></category><category><![CDATA[unique identifier]]></category><category><![CDATA[scaling]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 11 Nov 2025 05:44:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Oaqk7qqNh_c/upload/5ae2d12a7abe215c0818131ff23079c4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When thinking of generating unique <strong>IDs</strong>, the very first approach that comes to mind is using auto-incrementing integer IDs in traditional databases. This works well for small systems or systems with a single database. However, you cannot use this method when building large-scale distributed applications.</p>
<p>The reason is that there is no way for different systems to coordinate what the next sequence number should be. Consequently, all nodes will generate their own sequences (e.g., 1, 2, 3), resulting in the same ID pointing to different records across the system.</p>
<h2 id="heading-multi-master-replication"><strong>Multi-Master Replication</strong></h2>
<p>We can implement a variation of the auto-increment feature where, instead of increasing the next ID by 1, we increase it by <strong>k</strong>, where <strong>k</strong> is the total number of nodes in the distributed system.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762581332992/1b7a60f4-2885-4888-985c-be4b2f2df854.png" alt class="image--center mx-auto" /></p>
<p>The next ID generated on a single system has a difference of <strong>k</strong> from its last ID, so the IDs generated on two different nodes will never collide. This solves the scalability issue of the basic auto-increment approach. However, this method still has several issues:</p>
<ul>
<li><p>It does not scale well when a server is added or removed (as <strong>k</strong> would need to change).</p>
</li>
<li><p>IDs do not increase chronologically across the entire system.</p>
</li>
<li><p>It is hard to scale across multiple data centers.</p>
</li>
</ul>
<h2 id="heading-ticket-server">Ticket Server</h2>
<p>A Ticket Server is another way of generating unique IDs. This approach, used by services like Flickr and Etsy, uses a centralized, dedicated server to generate globally unique primary keys.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762591230573/96a6bb66-f65e-4cb7-b36c-e12d01a86f4c.png" alt class="image--center mx-auto" /></p>
<p>It is relatively easy to implement and scales from small- to medium-scale systems. However, since it is centralized, it creates a <strong>single point of failure (SPOF)</strong>. Any issue with the ticket server can halt or bring down the whole system. While you could introduce distributed ticket servers, that brings its own challenges, such as data synchronization.</p>
<h2 id="heading-uuid-universally-unique-identifier-v4">UUID (Universally Unique Identifier) v4</h2>
<p>A UUID is a 128-bit number used to identify information in computer systems. UUIDs have a very low probability of <strong>collision</strong>. An example is <code>1e653ffd-5b98-4648-8571-5848edb0b7fe</code>.</p>
<p>It consists of a 128-bit (16-byte) block of data, where 6 bits are reserved for version and variant flags, and the remaining 122 bits are for random data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762619620332/72aaf885-e477-415a-a56f-72e078727e34.png" alt class="image--center mx-auto" /></p>
<p>Since UUID v4 is random, it can be generated without coordination between server nodes, thus avoiding synchronization issues. This makes it highly scalable, as each node can generate IDs independently. However, this approach still has a few issues:</p>
<ul>
<li><p>They are non-numeric, which can be inefficient for storage compared to a 64-bit integer.</p>
</li>
<li><p>UUID v4 is purely random, meaning the IDs do not increase chronologically and are therefore not sortable.</p>
</li>
<li><p>Their 128-bit size is larger than a 64-bit integer, which can impact storage and index size.</p>
</li>
</ul>
<p>UUID v4 provides good random data distribution. (Other random ID formats include Nano ID and CUID2.) By "random data distribution," we mean that if many UUID v4 IDs are generated and inserted, they will be scattered randomly throughout the database's index. This is good for distributed <strong>(hash-based)</strong> databases but can lead to <strong>index fragmentation</strong> and increased disk I/O in traditional single-database (B-Tree) systems.</p>
<h2 id="heading-twitter-snowflake-id">❄️ Twitter Snowflake ID</h2>
<p>Twitter Snowflake is a time-based unique ID generation algorithm developed by X (formerly Twitter). It was designed to address the problem of generating unique IDs for distributed systems at scale.</p>
<p>Snowflake was designed to overcome the shortcomings of other methods. For example, Multi-Master Replication is hard to scale, and Ticket Servers create a single point of failure. While UUID v4 avoids these issues, its random nature means it isn't time-sortable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762619646213/11fe3113-7377-4c6d-a8bd-de254eff1bba.png" alt class="image--center mx-auto" /></p>
<p>The Snowflake ID is a 64-bit ID designed for high-throughput, distributed systems. It consists of:</p>
<ul>
<li><p><strong>Sign Bit (1 bit):</strong> It will always be 0, reserved for future use.</p>
</li>
<li><p><strong>Timestamp (41 bits):</strong> Milliseconds since a custom epoch. Twitter's default epoch is <code>1288834974657</code> (Nov 04, 2010). This is the most important part, as the timestamp ensures that IDs are sortable by time. 41 bits provide for ~69 years of IDs.</p>
</li>
<li><p><strong>Datacenter ID (5 bits):</strong> Allows for 2^5 = 32 datacenters.</p>
</li>
<li><p><strong>Machine ID (5 bits):</strong> Allows for 2^5 = 32 machines per datacenter.</p>
</li>
<li><p><strong>Sequence number (12 bits):</strong> A counter for IDs generated within the same millisecond on the same machine. It is reset to 0 every millisecond and allows for 2^12 = 4096 IDs per millisecond, per machine.</p>
</li>
</ul>
<p>Datacenter and machine IDs are typically chosen at startup and fixed. Any accidental change in these values can lead to ID conflicts.</p>
<h2 id="heading-ulid-universally-unique-lexographically-sortable-identifier">ULID (Universally Unique Lexographically Sortable Identifier)</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762622043900/c10edaa8-3286-409a-9903-23c4680adfca.png" alt class="image--center mx-auto" /></p>
<p>ULID is also a 128-bit (16-byte) ID that is similar to Twitter Snowflake, and UUID v7.</p>
<ul>
<li><p>It uses a 48-bit timestamp (Unix epoch in <strong>milliseconds</strong>).</p>
</li>
<li><p>It is <strong>lexicographically</strong> sortable and has time-based locality.</p>
</li>
<li><p>It is not <em>natively</em> compatible with UUID, so migration can be difficult.</p>
</li>
<li><p>It can be generated offline without coordination.</p>
</li>
</ul>
<p>If you want a time-sortable ID that <strong>is</strong> a native, specification-compliant, you should use <strong>UUID v7</strong>.</p>
<h2 id="heading-uuid-universally-unique-identifier-v7">UUID (Universally Unique Identifier) v7</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762620517402/51b5ab60-2a16-4d84-be97-51864b06b897.png" alt class="image--center mx-auto" /></p>
<p>UUID v7 uses a 48-bit timestamp, 74 bits for randomness, and 6 bits for version and variant. The timestamp is based on the Unix epoch in <strong>milliseconds</strong> (not seconds). It is designed for high-load databases and distributed systems.</p>
<p>UUID v7 is best for systems that require records to be stored in the order they were created, such as logs, database indexes, and audit trails. UUIDs are supported as a native type by many databases; alternatively, a <code>Binary(16)</code> data type can be used to store them.</p>
<h2 id="heading-which-id-is-the-best">Which ID is the best?</h2>
<p>Ultimately, we are left with two kinds of IDs: random and time-based sortable. The best choice depends on the kind of database you are using.</p>
<ul>
<li><p><strong>B-Tree based Databases (MySQL, PostgreSQL, etc.):</strong> <strong>Time-based IDs are best.</strong> These databases sort keys in an index. Random IDs are bad here, as they cause index fragmentation, making <code>INSERT</code> operations very slow. Sequential IDs are fast because they are simply appended to the end of the index.</p>
</li>
<li><p><strong>Hash-Based Distributed Databases (DynamoDB, Cassandra, etc.):</strong> <strong>Random IDs (UUID v4) are best.</strong> Time-based IDs are <strong>bad</strong> here because they cause <strong>write hotspots</strong>, making one server do all the work. These databases "distribute" data by hashing the ID to decide which server (node) to store it on. If you use a time-based ID, all new IDs will have a similar prefix (the timestamp) and will be hashed to the same server, creating a bottleneck. Random IDs distribute the load perfectly.</p>
</li>
</ul>
<p>Ultimately, the quest for the "perfect" unique ID reveals a core principle of system design: there is no single best solution, only the right one for the job. As we've seen, the choice between a random or a time-sortable ID is a critical decision that depends entirely on your database architecture. Choosing a random ID for a B-Tree database can lead to crippling fragmentation, while using a sequential ID on a hash-based system can create debilitating hotspots. The best ID, therefore, is the one that aligns with how your data is stored and distributed.</p>
]]></content:encoded></item><item><title><![CDATA[How Consistent Hashing Scales Distributed Systems]]></title><description><![CDATA[Scaling is the process of increasing the system’s capacity to handle growing amount work. It's about designing your application or infrastructure so it can manage more users, data, or requests without failing or becoming slow.
There were two major wa...]]></description><link>https://blog.pavittarx.com/how-consistent-hashing-scales-distributed-systems</link><guid isPermaLink="true">https://blog.pavittarx.com/how-consistent-hashing-scales-distributed-systems</guid><category><![CDATA[consistent hashing]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[scalability]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 28 Oct 2025 17:53:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/OwqLxCvoVxI/upload/37143ab2549a0ac14268b41580ad296f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Scaling is the process of increasing the system’s capacity to handle growing amount work.</strong> It's about designing your application or infrastructure so it can manage more users, data, or requests without failing or becoming slow.</p>
<p>There were two major ways of scaling systems —</p>
<ol>
<li><p><strong>Vertical Scaling (Scaling Up)</strong></p>
<p> You might add more power to your system (<strong>more cores, more RAM, more storage, faster SSDs</strong>). In this case, the ability of the system to handle load is increased. This is also the easiest since it does not require changes to application or its architecture. However, on the flip side, it expensive — as high-end hardware costs more, it is limited — you will soon hit machine’s max capacity. Additionally, upgrades require downtime, and single failure can bring down entire application.</p>
</li>
<li><p><strong>Horizontal Scaling (Scaling Out)</strong><br /> This involves <strong>adding more servers to distribute the system load.</strong> This could be distributing your database, application or (or its parts) onto separate/multiple machines.<br /> It is more fault tolerant solution, brings the near unlimited scalability, cheap — you could use multiple standard systems rather than one high-end one, zero downtime during upgrades. However, it is much more complex, as it requires changes to architecture as well as application level code. You need shared state for application to be in sync, load balancers to manage the traffic, etc.</p>
</li>
</ol>
<p>There is also database level scaling (caching, read replicas, and sharding), and application level scaling (asynchronous processing, microservices), which is also used alongside above two techniques.</p>
<p>One of the major problems in horizontal scaling is how to distribute the traffic/load on multiple servers efficiently.</p>
<h2 id="heading-the-rehashing-problem"><strong>The Rehashing Problem</strong></h2>
<p>The simplest way to distribute the load among N servers is using the formula, <code>serverIndex = hash(key) % N</code> .</p>
<p>For example, with 4 servers, we use the modular operation <code>hash(key) % 4</code> to find the server where a key is stored. This works reasonably well for a <strong>fixed number</strong> of <strong>servers</strong> if the data distribution is even, but that is seldom the case in real-world distributed <strong>systems</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761625461732/77694c77-6795-4c3c-a8f4-c8ced93a3a98.png" alt class="image--center mx-auto" /></p>
<p>Now, if a server crashes (say, we go from 4 servers to 3), the formula becomes <code>hash(key) % 3</code>. This change causes a catastrophic remapping. Here is what happens,</p>
<ol>
<li><p>The result of <code>hash(key) % 3</code> will be different from <code>hash(key) % 4</code> for majority of keys — <strong>all keys will needed to be remapped,</strong> not just the keys on Server 3.</p>
</li>
<li><p>Your cache is suddenly empty. Since, keys map to a different server and application cannot find the expected data.</p>
</li>
<li><p>All cache misses directly hit your database, overloading it, and likely bringing it to a halt. This is often called, <strong>thundering herd</strong> problem.</p>
</li>
<li><p>You will need to <strong>remap</strong> almost all <strong>K</strong> keys in the system, which is an $O(K)$ operation that can grind the system to a halt.</p>
</li>
</ol>
<p>Consistent hashing solves this.</p>
<h2 id="heading-consistent-hashing">Consistent Hashing</h2>
<p>The primary benefit of consistent hashing is that when a server (or slot) is added or removed, only <code>k/n</code> <strong>keys</strong> need to be remapped on average, where <code>k</code> is the total number of keys and <code>n</code> is the number of servers.</p>
<p>It works by placing servers on a conceptual ring. It then maps a key to the first server it "sees" by moving clockwise around the ring from the key's position. When a server is added or removed, only the keys in its specific arc are affected. The vast majority of keys stay exactly where they are.</p>
<p><strong>Hash Ring</strong></p>
<p>The hash ring represents output space of the hash function in use. For example, If we use SHA-1 as hash function, it’s hash space goes from <code>0</code> to <code>2^160 -1</code> , lets say <code>x0</code> … <code>xN</code>.</p>
<p>The hash ring represents the <em>entire</em> output space of the hash function being used. For example, if we use SHA-1 as the hash function, its hash space goes from 0 to 2^160 - 1. In this case <code>x0</code> will be 0, and <code>xN</code> will be 2^160 - 1.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761660351113/48e61af6-a9a0-4275-81e0-6eec57cf766a.png" alt class="image--center mx-auto" /></p>
<p><strong>Hash Servers</strong> - We map servers onto the ring using IP or server name, using the same hash function. The hash function used in here is different as there is no modulo operation.</p>
<p>In consistent hashing, we place both the keys and the servers onto this same ring. To determine which server a key is stored on, we travel clockwise from the key's location until a server is found.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761662741195/40926d87-f2d4-4b76-a354-61e6c4b744b2.png" alt class="image--center mx-auto" /></p>
<p>For example, in above if we need to find the server for <code>k0</code>, we will go clockwise from <code>k0</code>, until we reach <code>s1</code>. Hence, key <code>k0</code> is stored on server <code>s1</code> . Similarly, key <code>k4</code> and <code>k5</code> are stored on server <code>s3</code>.</p>
<p>Now, say if we</p>
<ol>
<li><p>add a server <code>s5</code> between, <code>k0</code> and <code>k1</code>. Key <code>k0</code> will now be found on server <code>s5</code>, while <code>k1</code> and <code>k2</code> will be found on server <code>s1</code>. So, only one key was needed to be remapped.</p>
</li>
<li><p>If we remove server <code>s3</code> then only keys <code>k4</code> and <code>k5</code> will be needed to be remapped on server <code>s4</code>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761663088996/608dff15-a29e-4079-b4c9-7ad39bdb5e8a.png" alt class="image--center mx-auto" /></p>
<p>So far it would have become obvious that this issues creates two further problems —</p>
<ol>
<li><p>It is possible for servers to be clustered unevenly on the ring, creating large gaps. See how, <code>s4</code>, <code>s5</code>, and <code>s1</code> , <code>s2</code> only cover half of the ring.</p>
</li>
<li><p>It is possible keys are unevenly distributed, where almost all the keys (hotspots) are only assigned to a few servers.</p>
</li>
</ol>
<h2 id="heading-virtual-nodes">Virtual Nodes</h2>
<p><strong>Virtual nodes</strong> are used to solve the problem of uneven key distribution in consistent hashing. Instead of mapping a physical server to one point, the server is represented by many <strong>virtual nodes</strong> at multiple places on the ring. In a real-world system, this number is typically large, which reduces the probability of an uneven distribution of keys. This way, a single server is responsible for many small partitions of the ring.</p>
<p>This large number of virtual nodes helps balance the distribution of keys among the <strong>servers</strong> on the ring. The standard deviation of the key distribution will be smaller when we increase the number of virtual nodes. However, more space is needed to store the metadata mapping these virtual nodes to their physical servers. This is a tradeoff, and we can tune the number of virtual nodes to fit our system's requirements.</p>
<h2 id="heading-applications">Applications</h2>
<ul>
<li><p>Discord Chat Application</p>
</li>
<li><p>Akamai Content Delivery Network</p>
</li>
<li><p>Partitioning Component of Amazon’s Dynamo Database.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Deciphering CAP: The Fundamental Trade-off in Distributed Systems]]></title><description><![CDATA[CAP Theorem is measure that can help you assess the tradeoffs when designing distributed systems. The trade-off is between Consistency, Availability and Partition Tolerance.
All of these three are inter-related, with subtle difference, and all of the...]]></description><link>https://blog.pavittarx.com/deciphering-cap-the-fundamental-trade-off-in-distributed-systems</link><guid isPermaLink="true">https://blog.pavittarx.com/deciphering-cap-the-fundamental-trade-off-in-distributed-systems</guid><category><![CDATA[CAP-Theorem]]></category><category><![CDATA[Developer]]></category><category><![CDATA[System Design]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[consistency]]></category><category><![CDATA[distributed systems]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Tue, 21 Oct 2025 18:24:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cqH4_fBvVPg/upload/31b3c89e94a8b8fd8f00b2a088570fba.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>CAP Theorem is measure that can help you assess the tradeoffs when designing distributed systems. The trade-off is between <strong>Consistency, Availability and Partition Tolerance</strong>.</p>
<p>All of these three are inter-related, with subtle difference, and all of them these cannot be guaranteed at the same time. Before we dive any further into CAP theorem, lets deep dive these three —</p>
<ol>
<li><p><strong>Consistency</strong> — is about whether the data client sees is up to data or not. All nodes in a system with strong consistency shows most recent data or throws errors. There is no in-between.<br /> You must note that, Consistency here is different from consistency guarantee in databases with ACID transactions.</p>
</li>
<li><p><strong>Availability</strong> — focuses more on making data available rather than data being most up to data. You might be seeing some stale data while the data is being updated. In highly available system, You are supposed to get a response, unless the node is failing.</p>
</li>
<li><p><strong>Partition Tolerance</strong> - is ability of a distributed system to continue to operate despite an arbitrary number of messages being lost, delayed, or dropped by the network between nodes.<br /> A partition (network partition) is a communication failure that divides the nodes of a distributed system into two or more separate groups (partition), where nodes within groups can communicate but nodes between groups cannot.</p>
</li>
</ol>
<p><strong><em>CAP theorem states it is impossible for a distributed system to simultaneously provide more than two of these three guarantees: consistency, availability, and partition tolerance.</em></strong></p>
<ul>
<li><p><strong>C</strong>onsistency: Every read receives the most recent write or an error.</p>
</li>
<li><p><strong>A</strong>vailability: Every request receives a (non-error) response, without guarantee that it contains the most recent write.</p>
</li>
<li><p><strong>P</strong>artition Tolerance: The system continues to operate despite network failures (partitions) that isolate some nodes.</p>
</li>
</ul>
<p>There leads to three theoretical system configurations —</p>
<ol>
<li><p><strong>CP</strong> (Consistency &amp; Partition Tolerance) System - sacrifices availability to support consistency &amp; partition tolerance.</p>
</li>
<li><p><strong>AP</strong> (Availability &amp; Partition Tolerance) System - sacrifices consistency to support availability and partition tolerance.</p>
</li>
<li><p><strong>CA</strong> (Consistency &amp; Availability) System - sacrifices partition tolerance, to support consistency &amp; availability.</p>
</li>
</ol>
<p>Now ideally, if network partition never occurs, and data from node <code>n0</code> is automatically replicated to all other nodes, we could thus create a <strong>CA System,</strong> as both consistency and availability are achieved. However, in real-world distributed systems, network partition is unavoidable, and thus we are forced choose between consistency and availability.</p>
<p>If we choose Consistency, we get a CP System, on the other hand if we choose Availability we get AP system. Consistency and Availability are also interrelated, as if we reduce consistency of a system, it becomes more available, as stale data can be used, and if we choose more of availability the data client sees is not up to date.</p>
<p>Now when we are left with Consistency and Availablity, it is hard to say one system is better than the other as it completely depends on type of application you are building. A banking/financial app would require strong consistency since it's better to make the customer wait, than to show incorrect balance. Similarly, for a social media feed, it makes much more sense to show something even if it not the latest, rather than throwing errors at all the places.</p>
]]></content:encoded></item><item><title><![CDATA[Does your code have debt?]]></title><description><![CDATA[Good code is an asset, while Bad code is a liability. The liability also has a technical name as Tech/Code Debt.
Code debt arises when the delivered code is not very optimal requires refactoring. This debt can be due to faster delivery timelines, mis...]]></description><link>https://blog.pavittarx.com/does-your-code-have-debt</link><guid isPermaLink="true">https://blog.pavittarx.com/does-your-code-have-debt</guid><category><![CDATA[code]]></category><category><![CDATA[debugging]]></category><category><![CDATA[refactoring]]></category><category><![CDATA[code smell ]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Sat, 13 Nov 2021 19:35:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1636832006904/0pvuu-yVE.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Good code is an asset, while Bad code is a liability. The liability also has a technical name as Tech/Code Debt.</p>
<p>Code debt arises when the delivered code is not very optimal requires refactoring. This debt can be due to faster delivery timelines, missing documentation, legacy/redundant code delivery without appropriating testing.</p>
<p>Code debt is similar to taking a loan. Businesses borrow money to fulfill ambitions that are not possible with the resources they currently have. Similarly, when the short-term gain is prioritized over long-term stability, you accumulate code debt.</p>
<p>Just as with monetary debt, you must be wise with code debt. Rushing out a feature to gain market edge and build upon the experience you may gain is purely rational. However, not putting in enough time and effort for refactoring will lead to unmaintained code, unknown issues, and stretched timelines. Finally, the code will be a mess. </p>
<p>Finally, Code debt should not be mistaken to be a mess. A mess is a mess. Code debt is a result of rational decisions. A code mess results from non-maintenance, following bad practices, and not putting appropriate resources for the needful. </p>
<p>#code #refactoring #debt #code-debt #cleancode #development</p>
]]></content:encoded></item><item><title><![CDATA[Using multiple Github accounts with SSH]]></title><description><![CDATA[When I started using Github, I used Github Desktop for sometime because that felt easy. Down the line, I learnt using git via CLI. And, I haven't touched the electron tool back ever. But, I was still using Github via HTTP vs SSH. 
I fell in love with...]]></description><link>https://blog.pavittarx.com/using-multiple-github-accounts-with-ssh</link><guid isPermaLink="true">https://blog.pavittarx.com/using-multiple-github-accounts-with-ssh</guid><category><![CDATA[GitHub]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Wed, 06 Oct 2021 13:30:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633526968710/hRWfqRdWG.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I started using Github, I used Github Desktop for sometime because that felt easy. Down the line, I learnt using <code>git</code> via CLI. And, I haven't touched the electron tool back ever. But, I was still using Github via <code>HTTP</code> vs <code>SSH</code>. </p>
<p>I fell in love with <code>ssh</code> when I first discovered it. Once setup you can use ssh to work with multiple repositories under same account. The only downside is the initial setup that might feel complicated if you are using it for the very first time. However, it saves you from the pain of password/token based authentication (...painful).</p>
<p>If you haven't used <code>ssh</code> before, these two articles would help you set up pretty quick. </p>
<ol>
<li><a target="_blank" href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent">Generating a new SSH Key</a></li>
<li><a target="_blank" href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account">Adding the Generated Key to your Github Account</a></li>
</ol>
<p>So far so good, this works good for a single account. What if you have to use multiple accounts? Personal and Work? </p>
<ol>
<li>Use <code>ssh-keygen</code> to start creating your new ssh key. Note, this email should be same as the one you use with your Github account. <pre><code class="lang-bash">     ssh-keygen -t rsa -C <span class="hljs-string">"youremail@domain.com"</span>
</code></pre>
</li>
<li><p>Give this ssh-key a different name, so that it does not conflict/overwrite existing keys. All existing <code>ssh</code> keys can be found under <code>~/.ssh</code> folder. I named my own as "pavittarxnoauth".</p>
<pre><code class="lang-bash">   Enter file <span class="hljs-keyword">in</span> <span class="hljs-built_in">which</span> to save the key (/home/pavittarx/.ssh/id_rsa): pavittarxnoauth
</code></pre>
</li>
<li><p>In the next steps, provide a password or simply hit enter if you do not want to add any passwords while authentication.</p>
</li>
<li><p>Check if the key has been successfully created. If you cannot find the key in .ssh folder. Repeat steps 1-3.</p>
<pre><code class="lang-bash">   ls ~/.ssh
</code></pre>
</li>
<li><p>Start your ssh-agent if you have not already. </p>
<pre><code class="lang-bash">   <span class="hljs-built_in">eval</span> `ssh-agent -s`
</code></pre>
</li>
<li><p>Add the key to your ssh agent. </p>
<pre><code class="lang-bash">   ssh-add ~/.ssh/pavittarxnoauth
</code></pre>
</li>
<li><p>Navigate to <code>~/.ssh</code> directory.</p>
<pre><code>   <span class="hljs-built_in">cd</span> ~/.ssh
</code></pre></li>
<li><p>Add following entry to the <code>config</code> file. You can also create one if it doesn't exist. Replace, pavittarxnoauth with your key-file name. Also, replace <code>github-noauth</code> to anything as per your preference. </p>
<pre><code class="lang-vim">Host github-noauth
 HostName github.com
 User git
 IdentityFile ~/.ssh/pavittarxnoauth
</code></pre>
</li>
<li><p>Add the <code>~/.ssh/&lt;yourkeyfilename.pub&gt;</code> to your Github account as stated <a target="_blank" href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account">here</a>.</p>
</li>
<li><p>Clone your repo with ssh, or change the <code>git remote</code> and <code>git config</code> for the repository. </p>
<pre><code class="lang-bash">    git <span class="hljs-built_in">clone</span> git@github-noauth:&lt;your-github-username&gt;/&lt;your-git-repo&gt;
</code></pre>
<p>For existing repository, that has been cloned already.</p>
<ol>
<li>Change <code>git remote origin</code></li>
</ol>
<pre><code class="lang-bash">  git remote remove origin
  git remote add origin git@github-noauth:&lt;github-username&gt;/&lt;git-repo&gt;
</code></pre>
<ol>
<li>Change <code>git config</code></li>
</ol>
<pre><code class="lang-bash">  git config --<span class="hljs-built_in">local</span> user.email <span class="hljs-string">"your-github-email@domain.com"</span>
  git config --<span class="hljs-built_in">local</span> user.name <span class="hljs-string">"github-username"</span>
</code></pre>
</li>
</ol>
<p>You can use same process to add multiple keys, with same or different accounts to Github. Also, the same is reproducable for other git providers such as Bitbucket/ Gitlab.</p>
]]></content:encoded></item><item><title><![CDATA[How code execution works in Javascript?]]></title><description><![CDATA[Javascript is asynchronous, that simply means that it does not wait. Well, it does but not very often. And, unless you ask it to await.
Javascript is like the language of Web. So, if you planning to learn Web Development. Javascript is one of the thi...]]></description><link>https://blog.pavittarx.com/how-code-execution-works-in-javascript</link><guid isPermaLink="true">https://blog.pavittarx.com/how-code-execution-works-in-javascript</guid><category><![CDATA[js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[vanilla-js]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Sat, 14 Aug 2021 14:29:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633527498407/C30bYOPiG.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Javascript is asynchronous, that simply means that it does not wait. Well, it does but not very often. And, unless you ask it to <code>await</code>.</p>
<p>Javascript is like the language of Web. So, if you planning to learn Web Development. Javascript is one of the things that you must consider learning. Although, you will be able to get multiple tutorials online that would teach you the semantics, syntax and programming in Javascript. But, most of them would skip over the fact that "Javascipt is single-threaded and asynchronous". </p>
<h2 id="single-threaded-model">Single threaded model</h2>
<p>Javascript being single-threaded,which means it has one memory heap and one call stack. So, that comes down to that you can only run a single task at a given time, and unti
l then your program is stuck. </p>
<p>Consider the following code snippet: </p>
<pre><code class="lang-js">  <span class="hljs-number">1.</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"One"</span>);
  <span class="hljs-number">2.</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Two"</span>);
  <span class="hljs-number">3.</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Three"</span>);

<span class="hljs-comment">/* 
  Result: 

    One
    Two 
    Three
*/</span>
</code></pre>
<p>Here, Line 1 should finish executing before Line 2, and Line 2 should finish excuting before Line 3. </p>
<p>However, you must know that even though Javascript runs on a single thread. There are certain cases where Javascript behaves asynchronously. For example, see the below code snippet: </p>
<pre><code class="lang-js">
  <span class="hljs-number">1.</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"One"</span>);
  <span class="hljs-number">2.</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Two"</span>), <span class="hljs-number">2000</span>);
  <span class="hljs-number">3.</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Three"</span>);

  <span class="hljs-comment">/* 
   Result: 

    One
    Three
    Two
  */</span>
</code></pre>
<p>Here, this bit of code skips over Line 2, and executes Line 3 before Line 2 finishes. Now, that is asynchronous behaviour for you.  </p>
<p>However for this to make sense to you. You must understand <strong>Javascript is an interpreted language and not a compiled language like Java, C or C++.</strong> There is no compilation step for Javascript, instead the code is interpreted line by line run by the interpreter. Modern intepretors in some enviornments use  <a target="_blank" href="https://stackoverflow.com/questions/59807938/the-confusion-with-jit-compilation-in-v8">JIT (Just-in-Time)</a>  compilation, which convert Javscript code to executable code just when it is about to run. </p>
<p> <a target="_blank" href="https://v8.dev/">V8 Engine</a>  written in C++ is  used in Chrome and NodeJs enviornments to run Javascript. Firefox uses  <a target="_blank" href="https://spidermonkey.dev/">SpiderMonkey</a> , which was introduced in 2017. IE and Edge had its own Chakra Engine. The newer Edge and all other chromium based browsers use V8 Engine under the hood. </p>
<p>These engine offers extra API features, which run the tasks in background while the Javascript keeps executing. In browser these external features are often referred to as Web APIs. In the example above, <code>setTimeout()</code> is an external API. So, whenever the browser encounters code using <code>setTimeout</code> it starts executing this snippet in background. And, when the task finishes it transfers the control back to Javascript. </p>
<p>For a deeper understanding of how this happens.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=8aGhZQkoFbQ">https://www.youtube.com/watch?v=8aGhZQkoFbQ</a></div>
<p> </p>
<p>Event Loop in action: http://latentflip.com/loupe</p>
<p>List of available Web APIs: https://developer.mozilla.org/en-US/docs/Web/API</p>
]]></content:encoded></item><item><title><![CDATA[Why you should avoid using CMS for your projects?]]></title><description><![CDATA[I will start with Strapi, and If you do not know it already. Strapi is a headless CMS, written on top of Nodejs. So, you can use it to create APIs, while the content can be managed by the CMS. It uses Koa (not express) under the hood for configuring ...]]></description><link>https://blog.pavittarx.com/why-you-should-avoid-using-cms-for-your-projects</link><guid isPermaLink="true">https://blog.pavittarx.com/why-you-should-avoid-using-cms-for-your-projects</guid><category><![CDATA[cms]]></category><category><![CDATA[headless cms]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Sat, 14 Aug 2021 10:54:05 GMT</pubDate><content:encoded><![CDATA[<p>I will start with Strapi, and If you do not know it already. Strapi is a headless CMS, written on top of Nodejs. So, you can use it to create APIs, while the content can be managed by the CMS. It uses Koa (not express) under the hood for configuring your server. </p>
<p>It comes preconfigured with middlewares, authentication and role-based access for you. So, you don't have to go around and configure a good part of it. So, if your use-case is easy enough. You can be running in minutes in Strapi. Now that it has all the features for you that would allow you to build complex apps. However, in cases where your use case becomes complex you do be feel better off to have done it with express instead. Strapi is more UI-friendly rather than code-friendly. Afterall, its a CMS.  </p>
<p>Strapi uses a Content-Manager plugin that allows you to create collections as per your requirements. The default quickstart template comes preconfigured with <code>sqlite3</code> but you can always configure your own database as well. I have been using MongoDb, and the sad bit it, all the collection information, as well as roles and permission information is kept in database rather than the app. And there is quite a time you might spend juggling around the backend (node-project) and the Strapi's own admin UI. </p>
<p>The interesting bit however is that, Strapi creates basic CRUD operations for you. The APIs support sorting and filtering by default, but the syntax can be a bit confusing at times. The documentation on the website is not very descriptive either. Yet, it can be all that you may need. But, then again if you want something different than basic CRUD, you have to end up writing your own custome APIs. </p>
<p>So, good so far, but here are the extremely bad bits -</p>
<ul>
<li>Strapi has its own system of recognizing enviornment variables. But, that doesn't work as you expect. </li>
<li>The project overall is heavy, since a lot of stuff is already configured for you.</li>
<li>The scope of configuring error response messages is very low. You can do that for some use cases or at places when you are writing your own APIs.</li>
<li>From security perspective, the APIs are not very secure. Even though you have role based access, you can make PUT requests to all the collections, if you belong to that particular role. </li>
<li>For MongoDb, strapi has a wrapper around <code>mongoose</code>, which in itself is a wrapper around MongoDb's native Node APIs. </li>
<li>Even for custom APIs, strapi does not support transactions. I was able to write transaction but that did always end in failure no matter what. </li>
<li>The reload time on the development enviroment is very high. It is a known problem and the solutions provided in forums do not work. </li>
<li>You will not be able to build projects on AWS's <code>t2.nano</code> &amp; <code>t2.micro</code> instances. <code>t2.small</code> is needed at the very least or else the project would error out at the build step. </li>
</ul>
<p>Now, that was Strapi so far. But you can see similar issues in other CMS's as well. </p>
<ul>
<li><p>If you are concerned about security of your project. Then, using a CMS is certainly should be "NO". Why? just because CMS's vuerabilities are your project's vunerabilities. </p>
</li>
<li><p>The glitter and shine in the front are problems in the dark. No project advertises its vunerabilities, same goes for every CMS. You only come to know when you work with them. The simplicity in the start end up making simple tasks complex as your project evolves. </p>
</li>
<li><p>Your control over the project is not so good. Since, for everything you do must be done in a way CMS allows you to. Also, you options are limited in terms of approaches you may go to implement a particular feature in your project. </p>
</li>
<li><p>CMS add unnecessary bloat to your projects, which can also result in performance issues. </p>
</li>
<li><p>CMS do follow monolith architecture, so scaling can be an issue unless you CMS support it. </p>
</li>
</ul>
<p>I hope you got the gist of it until now... rest for later.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the Client-Server model of application development]]></title><description><![CDATA[For someone starting out their web development journey, he must first understand how web apps work. 
The Client-Server model act as the core of every web app. Be it a social networking app as Facebook, Instagram or Whatsapp; an online MMORPG game you...]]></description><link>https://blog.pavittarx.com/understanding-the-client-server-model-of-application-development</link><guid isPermaLink="true">https://blog.pavittarx.com/understanding-the-client-server-model-of-application-development</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Applications]]></category><category><![CDATA[web application]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Pavittar Singh]]></dc:creator><pubDate>Sun, 25 Apr 2021 15:14:23 GMT</pubDate><content:encoded><![CDATA[<p>For someone starting out their web development journey, he must first understand how web apps work. </p>
<p>The Client-Server model act as the core of every web app. Be it a social networking app as Facebook, Instagram or Whatsapp; an online MMORPG game you love to play;  apps such as Zoom, Google Meet or anything else that has got something to do with the internet. But, what is this Client-Server model?</p>
<p>The client-server model tells us how the server and the client interact with each other. In order to understand this, you must understand what a client is? </p>
<p>A client is a device that makes requests for data or information. This data can be a file, image, webpage or anything else. Say for example, when you make a Google Search from your phone. Your phone is the client here,  It made the request for information you are searching for. </p>
<p>A server resides on the other end of this equation. The server is the one who provides this information. The reason for this is simple enough. It is if some information has to be provided to you, it must exist somewhere and you must have access to it. Now taking the earlier example, when you make a Google Search the information you are asking for is at Google's server. The server sends it to you through the internet. </p>
<p>Hence, a client is one that makes requests. And, the server on the other end is one that responds to those requests. A client can be a  smartphone, a laptop, a desktop, an IOT device, etc. Now, have a look at the picture below for a visual representation of the model. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619363535150/A1aCKTiR2.jpeg" alt="Frame 1.jpg" /></p>
<p>Thank you for the read. More heartly stuff coming soon. Do subscribe for quick updates. Also, do let me know what other stuff should I cover for you? I'll be happy to consider.</p>
<h2 id="follow-me">Follow Me:</h2>
<p>Github - https://github.com/pavittarx
Find me on Linkedin - https://linkedin.com/in/pavittarx</p>
]]></content:encoded></item></channel></rss>