<?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[Developer Talks: Simplifying Complexity in Tech - Programming, Cloud, Microservices, Database, and More]]></title><description><![CDATA[Exploring a range of tech topics: programming, cloud computing, microservices, database performance, and more. Stay informed and inspired.]]></description><link>https://priyankpatel.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1660978814468/Q362W72Tl.gif</url><title>Developer Talks: Simplifying Complexity in Tech - Programming, Cloud, Microservices, Database, and More</title><link>https://priyankpatel.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 02:07:41 GMT</lastBuildDate><atom:link href="https://priyankpatel.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Art of Crawl Budget Management: Keeping Googlebot Happy and Your Pages Crawled!]]></title><description><![CDATA[Welcome to the Crawl Budget Circus! 🎪
Step right up, ladies and gentlemen! Today, we’re diving into the thrilling world of crawl budgets—the magical limit that determines how much time Googlebot spends crawling your website. Think of it as a circus ...]]></description><link>https://priyankpatel.dev/the-art-of-crawl-budget-management-keeping-googlebot-happy-and-your-pages-crawled</link><guid isPermaLink="true">https://priyankpatel.dev/the-art-of-crawl-budget-management-keeping-googlebot-happy-and-your-pages-crawled</guid><category><![CDATA[Crawl Capacity Limit]]></category><category><![CDATA[SEO]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[websites]]></category><category><![CDATA[Developer]]></category><category><![CDATA[website crawling]]></category><category><![CDATA[SEO Strategy]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sun, 19 Jan 2025 05:17:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737189809406/c298ac24-6d2a-41ff-aeac-fedd895b18df.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-welcome-to-the-crawl-budget-circus">Welcome to the Crawl Budget Circus! 🎪</h2>
<p>Step right up, ladies and gentlemen! Today, we’re diving into the thrilling world of <strong>crawl budgets</strong>—the magical limit that determines how much time Googlebot spends crawling your website. Think of it as a circus act where Googlebot is the star performer, and your site is the stage. If you want to keep the show running smoothly, you need to manage that crawl budget like a pro!</p>
<hr />
<h2 id="heading-what-is-a-crawl-budget">What Is a Crawl Budget?</h2>
<p>Picture this: Googlebot rolls up to your digital doorstep, ready to explore. But wait! It only has a limited amount of time and resources to check out your pages. That’s your crawl budget in action!</p>
<p>In simple terms, <strong>crawl budget</strong> refers to the number of pages Googlebot can crawl on your site within a given timeframe. This budget fluctuates based on several factors, including:</p>
<ul>
<li><p><strong>Site Size</strong>: Bigger sites have more pages to crawl, which can stretch that budget thin.</p>
</li>
<li><p><strong>Site Health</strong>: If your site has errors or slow loading times, Googlebot might decide it’s not worth its time.</p>
</li>
<li><p><strong>Content Freshness</strong>: Regular updates signal to Google that your site is worth revisiting.</p>
</li>
</ul>
<p>If you have a large site (think millions of pages), managing this budget becomes crucial. Otherwise, important content could get lost in the digital shuffle!</p>
<hr />
<h2 id="heading-why-should-you-care-about-crawl-budget">Why Should You Care About Crawl Budget?</h2>
<p>Imagine throwing a party where half your guests can’t find the bathroom because it’s hidden behind a mountain of clutter. That’s what happens when Googlebot can’t efficiently crawl your site! A poor crawl budget means:</p>
<ul>
<li><p><strong>Lower Search Rankings</strong>: If Google can't find your pages, they won't show up in search results.</p>
</li>
<li><p><strong>Reduced Visibility</strong>: Your content might as well be hiding under a rock.</p>
</li>
<li><p><strong>Fewer Leads and Sales</strong>: If potential customers can’t find you online, you’re missing out!</p>
</li>
</ul>
<p>So, let’s roll up our sleeves and optimize that crawl budget!</p>
<hr />
<h2 id="heading-how-does-googlebot-decide-what-to-crawl">How Does Googlebot Decide What to Crawl?</h2>
<p>Googlebot isn’t just wandering around aimlessly; it’s got a plan! Here’s how it decides what gets crawled:</p>
<ol>
<li><p><strong>Crawl Demand</strong>: This is how much Google wants to crawl your site based on popularity and content changes. If you’ve got hot topics or trending content, expect more visits!</p>
</li>
<li><p><strong>Crawl Capacity Limit</strong>: This is the maximum number of simultaneous connections Googlebot can use while crawling your site. Think of it as the number of rides at a theme park—too many visitors at once can lead to chaos!</p>
</li>
<li><p><strong>Sitemap Signals</strong>: Keeping an updated sitemap is like giving Googlebot a map of your amusement park. It shows them where all the fun stuff (your important pages) is located.</p>
</li>
</ol>
<hr />
<h2 id="heading-tips-for-optimizing-your-crawl-budget">Tips for Optimizing Your Crawl Budget</h2>
<p>Now that we’ve established why crawl budgets matter, let’s get into the nitty-gritty of optimization. Here are some tips that will make Googlebot feel like royalty at your digital soirée:</p>
<h3 id="heading-1-prioritize-important-pages">1. Prioritize Important Pages</h3>
<p>Decide which pages are must-sees for Googlebot and which can take a backseat. Use analytics tools to identify high-traffic pages and ensure they’re easily accessible.</p>
<h3 id="heading-2-clean-up-duplicate-content">2. Clean Up Duplicate Content</h3>
<p>Duplicate content is like serving the same dish at every meal—boring! Consolidate similar pages to enhance user experience and make it easier for Googlebot to navigate.</p>
<h3 id="heading-3-maintain-a-clear-site-structure">3. Maintain a Clear Site Structure</h3>
<p>A logical site architecture helps Googlebot find its way around without getting lost. Use clear categories and internal links to guide them through your content.</p>
<h3 id="heading-4-keep-your-sitemaps-updated">4. Keep Your Sitemaps Updated</h3>
<p>An outdated sitemap is like giving someone an old map—it leads them nowhere! Regularly update your sitemap with new URLs and remove any outdated ones.</p>
<h3 id="heading-5-monitor-server-performance">5. Monitor Server Performance</h3>
<p>Ensure your server can handle traffic without breaking down like an overworked clown car. Slow loading times or errors can deter Googlebot from crawling effectively.</p>
<hr />
<h2 id="heading-advanced-strategies-for-large-sites">Advanced Strategies for Large Sites</h2>
<p>For those managing massive websites (we're talking millions of pages), here are some advanced strategies:</p>
<ul>
<li><p><strong>Mobile Link Consistency</strong>: With mobile-first indexing taking center stage, ensure that both mobile and desktop versions of your site have consistent links. Inconsistencies confuse Googlebot and waste precious crawl budget!</p>
</li>
<li><p><strong>Utilize URL Parameters Wisely</strong>: If you have dynamic URLs with parameters (like tracking codes), manage them carefully to avoid creating unnecessary duplicate content.</p>
</li>
<li><p><strong>Regularly Check Crawl Stats</strong>: Use tools like Google Search Console to monitor how many pages are being crawled daily versus how many you have overall. If you notice a disparity, it’s time for some optimization magic!</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion-keep-the-show-going">Conclusion: Keep the Show Going! 🎭</h2>
<p>Managing your crawl budget doesn’t have to be daunting; think of it as keeping the circus running smoothly! By prioritizing important content, maintaining a clean site structure, and regularly updating sitemaps, you’ll ensure that Googlebot has a fantastic experience on your site.</p>
<p>Remember, if you treat Googlebot like the VIP guest it is, you'll reap the rewards in search visibility and traffic. So roll up those sleeves, put on your best party hat, and let’s keep that crawl budget in check! Happy crawling!</p>
]]></content:encoded></item><item><title><![CDATA[The Magic Number 6174 That Never Goes Away]]></title><description><![CDATA[Last night while checking out a YouTube video, the algorithm suggested a video about the 6174 magic number—also known as Kaprekar's constant. Since the word "magic" always catches my attention, I gave it a watch. And wow, this number really is magic!...]]></description><link>https://priyankpatel.dev/the-magic-number-6174-that-never-goes-away</link><guid isPermaLink="true">https://priyankpatel.dev/the-magic-number-6174-that-never-goes-away</guid><category><![CDATA[Mathematical Tricks]]></category><category><![CDATA[Kaprekar's Constant]]></category><category><![CDATA[Mathematics]]></category><category><![CDATA[numbers]]></category><category><![CDATA[Information]]></category><category><![CDATA[Indian Mathematics]]></category><category><![CDATA[Math puzzles]]></category><category><![CDATA[Number theory]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sun, 29 Sep 2024 04:28:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727583442842/a058d061-eaf2-4ffc-864f-db6a800bf034.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last night while checking out a YouTube video, the algorithm suggested a video about the <strong>6174 magic number</strong>—also known as Kaprekar's constant. Since the word "magic" always catches my attention, I gave it a watch. And wow, this number really is magic! It’s so simple and fun that you can play around with it with your friends, kids, or anyone, really.</p>
<p>Let’s dive straight into the details.</p>
<hr />
<h1 id="heading-what-is-the-magic-of-6174">What is the Magic of 6174?</h1>
<p>The number <strong>6174</strong> is known as <strong>Kaprekar’s constant</strong>, and it has a special trick. If you take almost any 4-digit number, follow a few simple steps, and repeat them, you will always end up with <strong>6174</strong>. No matter what!</p>
<p>Here’s how it works:</p>
<ol>
<li><p><strong>Pick a 4-digit number</strong> (it can’t have all the digits the same, like 1111 or 2222).</p>
</li>
<li><p>Rearrange the digits to make the <strong>biggest</strong> number possible and the <strong>smallest</strong> number possible.</p>
</li>
<li><p>Subtract the smallest number from the biggest number.</p>
</li>
</ol>
<p>Repeat the process with the new number you get, and after a few rounds, you’ll reach <strong>6174</strong>.</p>
<hr />
<h3 id="heading-how-to-do-it-so-easy-a-5-year-old-can-understand">How to Do It (So Easy a 5-Year-Old Can Understand)</h3>
<p>Let’s break it down super simply. Imagine you have a 4-digit number like <strong>3524</strong>. Here’s what you do:</p>
<ol>
<li><p>First, rearrange the digits so you get the largest and smallest numbers.</p>
<ul>
<li><p>Largest: <strong>5432</strong></p>
</li>
<li><p>Smallest: <strong>2345</strong></p>
</li>
</ul>
</li>
<li><p>Now subtract the smallest from the largest:<br /> 5432 - 2345 = <strong>3087</strong></p>
</li>
<li><p>Now do the same thing with the new number, <strong>3087</strong>.</p>
<ul>
<li><p>Largest: <strong>8730</strong></p>
</li>
<li><p>Smallest: <strong>0378</strong> (which is just 378)</p>
</li>
</ul>
</li>
<li><p>Subtract them:<br /> 8730 - 378 = <strong>8352</strong></p>
</li>
<li><p>Now take <strong>8352</strong> and repeat the process:</p>
<ul>
<li><p>Largest: <strong>8532</strong></p>
</li>
<li><p>Smallest: <strong>2358</strong></p>
</li>
</ul>
</li>
<li><p>Subtract:<br /> 8532 - 2358 = <strong>6174</strong></p>
</li>
</ol>
<p>And that’s it! You’ve reached the magic number <strong>6174</strong>. If you keep going, you’ll always get 6174 no matter how many times you repeat the steps.</p>
<p>Try it out for yourself, you can check out this CodePen and play around with Kaprekar's constant right in your browser.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/priyankatgit/full/OJwyEGr">https://codepen.io/priyankatgit/full/OJwyEGr</a></div>
<p> </p>
<hr />
<h2 id="heading-who-discovered-this-and-why-is-it-special">Who Discovered This and Why Is It Special?</h2>
<p>The magic of 6174 was discovered by an Indian mathematician named <a target="_blank" href="https://en.wikipedia.org/wiki/D._R._Kaprekar"><strong>D. R. Kaprekar</strong></a> in 1949. He loved finding interesting patterns in numbers, and this one is his most famous discovery. It’s a fun trick that shows how math can surprise us in unexpected ways.</p>
<p>India has contributed a lot to mathematics, from the invention of the number zero to the brilliant work of mathematicians like Srinivasa Ramanujan. Kaprekar’s constant is another reminder that math can be playful and full of cool discoveries, even when it seems simple.</p>
]]></content:encoded></item><item><title><![CDATA[Turbocharge Your Workflow with ToDo + VSCode by Fabio Spampinato]]></title><description><![CDATA[Why ToDo+?
Like countless developers, I found solace in managing my priorities through a straightforward text file. The simplicity of having a to-do file right in your workspace, ready to be opened and updated at any moment, is unmatched. It's a quic...]]></description><link>https://priyankpatel.dev/turbocharge-your-workflow-with-todo-vscode-by-fabio-spampinato</link><guid isPermaLink="true">https://priyankpatel.dev/turbocharge-your-workflow-with-todo-vscode-by-fabio-spampinato</guid><category><![CDATA[Productivity]]></category><category><![CDATA[todoapp]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[vscode extensions]]></category><category><![CDATA[management]]></category><category><![CDATA[development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sun, 31 Dec 2023 08:37:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1704131201972/ba52df90-3be2-40d4-8e09-d057caccdff4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-why-todo"><strong>Why ToDo+?</strong></h1>
<p>Like countless developers, I found solace in managing my priorities through a straightforward text file. The simplicity of having a to-do file right in your workspace, ready to be opened and updated at any moment, is unmatched. It's a quick and efficient way to keep track of tasks while staying focused on the coding process.</p>
<p>However, when juggling multiple tasks in parallel, a basic to-do list might fall short. ToDo+ steps in to bridge that gap, enhancing the traditional to-do list with features that go beyond the ordinary.</p>
<p>Enter <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=fabiospampinato.vscode-todo-plus">Fabio Spampinato's ToDo+ VSCode extension</a> – a game-changer for developers seeking a balance between simplicity and advanced task management.</p>
<h2 id="heading-demo">Demo:</h2>
<pre><code class="lang-markdown">
Projects:
  ☐ Anything with a colon at the end of the line is a project
  ☐ Projects will show some statistics next to them @1h
<span class="hljs-code">    ✔ By default those statistics are the number of pending todos and the sum of their time estimates @30m
  Nested:
    ☐ You can nest projects inside each other and fold them
</span>
Todos:
  You can write plain text notes/descriptions wherever you want
  New:
<span class="hljs-code">    ☐ Press Cmd/Ctrl+Enter to add a new todo
  Done:
    ✔ Press Alt+D to mark a todo as done
    ✔ Press it again to undo the action
  Cancelled:
    ✘ Press Alt+C to mark a todo as cancelled
    ✘ Press it again to undo the action
  Tagging:
    ☐ You can add tags using the @ symbol, like this @tag
    ☐ There are some special, customizable tags: @critical @high @low @today
  Timekeeping:
    ✔ Completed todos can show a timestamp @done(17-11-03 10:42)
    ☐ Press Alt+S to mark a todo as started @started(17-11-03 10:42)
      ✔ Now it will show the elapsed time @started(17-11-03 10:42) @done(17-11-03 20:11) @lasted(9h29m)
    ☐ You can provide time estimates for your todos @1h30m
      ☐ We are even doing some natural language processing @est(1 day and 20 minutes)
</span>
Formatting:
  You can format text in a markdown-like fashion
  Bold:
<span class="hljs-code">    ☐ Use asterisks for *bold*
  Italic:
    ☐ Use underscores for _italic_
  Strikethrough:
    ☐ Use tildes for ~strikethrough~
  Code:
    ☐ Use backticks for `code`
</span>
Archive:
  ✔ You can archive finished todos here
  ✔ Congratulations, you are now a Todo+ master!
</code></pre>
<h3 id="heading-feature-highlights"><strong>Feature Highlights</strong></h3>
<p>Here's a glimpse of what ToDo+ brings to the table:</p>
<ol>
<li><p><strong>Portable:</strong></p>
<ul>
<li>Utilizes a plain text format, ensuring compatibility with any text editor.</li>
</ul>
</li>
<li><p><strong>Custom Symbols:</strong></p>
<ul>
<li><p>Choose from a variety of symbols to represent tasks.</p>
</li>
<li><p>Symbols include boxes, done indicators, and cancellation markers.</p>
<ul>
<li><p><strong>Box Symbols:</strong> <code>-</code> ❍ ❑ ■ ⬜ □ ☐ ▪ ▫ – — ≡ → › [] [ ]</p>
</li>
<li><p><strong>Done Symbols:</strong> ✔ ✓ ☑ + [x] [X] [+]</p>
</li>
<li><p><strong>Cancelled Symbols:</strong> ✘ x X [-]</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Custom Colors:</strong></p>
<ul>
<li>Personalize your to-do list with customized colors for a visually appealing experience.</li>
</ul>
</li>
<li><p><strong>Custom Special Tags:</strong></p>
<ul>
<li><p>Assign special tags to tasks for priorities, individuals, or any other categorization.</p>
</li>
<li><p>Tailor the color scheme for these special tags to suit your preferences.</p>
</li>
</ul>
</li>
<li><p><strong>Archive Functionality:</strong> Move completed tasks to a designated "Archive" section effortlessly.</p>
</li>
<li><p><strong>Formatting Options:</strong> Apply formatting similar to Markdown, including bold, italic, strikethrough, and code.</p>
</li>
<li><p><strong>Timekeeping and Timer:</strong></p>
<ul>
<li><p>Track elapsed time for tasks.</p>
</li>
<li><p>Display a timer in the status bar for ongoing tasks.</p>
</li>
</ul>
</li>
<li><p><strong>Time Estimates:</strong> Estimate the time needed for tasks using tags like @est(3 hours) or @2h30m.</p>
</li>
<li><p><strong>Statistics:</strong> Gain insights into your overall progress with file and project-level statistics.</p>
</li>
<li><p><strong>Embedded Todos:</strong> Identify //TODO or //FIXME comments in your code effortlessly.</p>
</li>
<li><p><strong>Activity Bar Views:</strong> Access your to-do file and embedded todos directly from a custom activity bar section.</p>
</li>
</ol>
<h3 id="heading-configure-your-workflow"><strong>Configure Your Workflow</strong></h3>
<p>Explore detailed configurations and unleash the full potential of ToDo+ at <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=fabiospampinato.vscode-todo-plus">VSCode Marketplace</a>.</p>
<p>In conclusion, ToDo+ by Fabio Spampinato transforms the way developers manage their tasks. It strikes the perfect balance between simplicity and advanced functionality, making it a must-have extension for anyone seeking to supercharge their productivity within the VSCode environment. Give it a try and experience a new level of efficiency in your coding journey!</p>
]]></content:encoded></item><item><title><![CDATA[Tim Berners-Lee: Architect of the Web's Genesis]]></title><description><![CDATA[In the vast realm of the internet, where countless websites and platforms seamlessly connect us, have you ever wondered about the origins of the World Wide Web (WWW)? Let's embark on a fascinating journey back to 1989 when a British scientist named T...]]></description><link>https://priyankpatel.dev/tim-berners-lee-architect-of-the-webs-genesis</link><guid isPermaLink="true">https://priyankpatel.dev/tim-berners-lee-architect-of-the-webs-genesis</guid><category><![CDATA[#InternetPioneers]]></category><category><![CDATA[#WebGenesis]]></category><category><![CDATA[#htmlhistory]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[innovation]]></category><category><![CDATA[technology]]></category><category><![CDATA[history]]></category><category><![CDATA[internet]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sat, 02 Dec 2023 08:02:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701503034675/be1fe5af-bb74-4f46-9c14-e71ce06f2e6b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the vast realm of the internet, where countless websites and platforms seamlessly connect us, have you ever wondered about the origins of the World Wide Web (WWW)? Let's embark on a fascinating journey back to 1989 when a British scientist named Tim Berners-Lee, working at CERN, laid the foundation for the interconnected web we know today.</p>
<h2 id="heading-the-birth-of-an-idea-tim-berners-lees-proposal"><strong>The Birth of an Idea: Tim Berners-Lee's Proposal</strong></h2>
<p>The WWW wasn't a stroke of luck but a well-thought-out concept proposed by Tim Berners-Lee. In 1989, he introduced the idea of linking documents using hypertext, a concept that had been in the minds of researchers. This visionary proposal paved the way for a revolution in information sharing and collaboration.</p>
<h3 id="heading-the-document-that-started-it-all-tim-berners-lees-proposal-for-the-world-wide-web-march-1989">📜 <strong>The Document that Started it All: Tim Berners-Lee's Proposal</strong> for the World Wide Web <strong>(March 1989)</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701503240537/f7ad08b3-6e86-45e1-a927-184a4b983e21.jpeg" alt class="image--center mx-auto" /></p>
<p>Fast forward to the execution phase. Tim Berners-Lee went beyond the proposal stage and set out to bring his vision to life. He not only conceptualized but also implemented the first web server, browser, and webpage.</p>
<h2 id="heading-the-next-frontier-the-computer-behind-the-web-revolution">🖥️ <strong>The NeXT Frontier: The Computer Behind the Web Revolution</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701503432234/77a0f209-294c-4ae3-a2a7-33ce2ac34b4e.png" alt class="image--center mx-auto" /></p>
<p>The hardware that powered this groundbreaking venture was no ordinary machine. Tim Berners-Lee utilized a NeXT computer at CERN, demonstrating the fusion of cutting-edge technology with innovative ideas.</p>
<h2 id="heading-exploring-the-first-webpage">🌐 <strong>Exploring the First Webpage:</strong></h2>
<p>The inaugural webpage, hosted on the NeXT computer, can still be visited today. Take a digital stroll through history by visiting the link: <a target="_blank" href="http://info.cern.ch/hypertext/WWW/TheProject.html">http://info.cern.ch/hypertext/WWW/TheProject.html</a>. It provides a glimpse into the simplicity of the early web and the ambitious project Tim Berners-Lee set in motion.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701503533961/914039e2-d370-4256-a48b-dcb94c3f2e3b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-tim-berners-lees-next-world-wide-web-browser">💻 Tim Berners-Lee's NeXT World Wide Web browser</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701503658259/36721495-3141-4c56-9c3f-f2acdac286f9.png" alt class="image--center mx-auto" /></p>
<p>HTML, or Hypertext Markup Language, was the language that glued these early web pages together. It allowed for the formatting of text and images and the creation of links to other pages. <strong>Tim Berners-Lee's NeXT World Wide Web browser was instrumental in bringing this language to life.</strong></p>
<hr />
<h2 id="heading-evolution-of-html-from-simple-to-dynamic">🚀 <strong>Evolution of HTML: From Simple to Dynamic</strong></h2>
<p>HTML started with humble capabilities, but it rapidly evolved. Versions like HTML 2 introduced tables, forms, and image maps. HTML 3 embraced fonts, colors, and multimedia. HTML 4 brought style sheets and scripting into the mix. Finally, HTML 5 introduced a new era with features like video, audio, canvas, and semantic elements.</p>
<h2 id="heading-celebrating-the-web-pioneers">🎉 <strong>Celebrating the Web Pioneers</strong></h2>
<p>As we navigate the vast expanse of the internet today, let's take a moment to celebrate the pioneers like Tim Berners-Lee. His visionary ideas and relentless efforts have shaped the digital landscape we know and love.</p>
<p>🌐 <strong>#WebOrigins #TimBernersLee #HTMLEvolution #WWWHistory #TechInnovation</strong></p>
<p>In conclusion, the journey from a simple proposal to the dynamic web we experience today is awe-inspiring. Let's express gratitude to the trailblazers who, like Tim Berners-Lee, set the stage for the interconnected world we live in. 🚀✨</p>
<p><strong>Credits:</strong></p>
<p>Cover photo: <a target="_blank" href="https://cds.cern.ch/images/CERN-GE-9407011-31">Tim Berners-Lee, World Wide Web inventor (cern.ch)</a></p>
<p><a target="_blank" href="https://cds.cern.ch/images/OPEN-PHO-CCC-2019-001-1">An image of the first page of Tim Berners-Lee's proposal for the World Wide Web in March 1989 (cern.ch)</a></p>
<p><a target="_blank" href="https://cds.cern.ch/images/CERN-IT-9001001-01">A screenshot showing the NeXT world wide web browser created by Tim Berners-Lee (cern.ch)</a></p>
]]></content:encoded></item><item><title><![CDATA[Uncharted Territory: Exploring Lesser-Known JavaScript Functions]]></title><description><![CDATA[Using + to Convert Strings to Numbers:
const numericValue = +"42"; // Converts the string to a number
console.log(numericValue); // Output: 42 

const numericValue = +"abc";
console.log(numericValue); // Output: Nan

The + symbol is placed before the...]]></description><link>https://priyankpatel.dev/uncharted-territory-exploring-lesser-known-javascript-functions</link><guid isPermaLink="true">https://priyankpatel.dev/uncharted-territory-exploring-lesser-known-javascript-functions</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Fri, 01 Dec 2023 16:30:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Iqi0Rm6gBkQ/upload/ebf90175a03d68240c00a47f7dddc7b7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-using-to-convert-strings-to-numbers"><strong>Using</strong> <code>+</code> to Convert Strings to Numbers:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> numericValue = +<span class="hljs-string">"42"</span>; <span class="hljs-comment">// Converts the string to a number</span>
<span class="hljs-built_in">console</span>.log(numericValue); <span class="hljs-comment">// Output: 42 </span>

<span class="hljs-keyword">const</span> numericValue = +<span class="hljs-string">"abc"</span>;
<span class="hljs-built_in">console</span>.log(numericValue); <span class="hljs-comment">// Output: Nan</span>
</code></pre>
<p>The <code>+</code> symbol is placed before the <code>stringNumber</code>, and it effectively coerces the string into a numeric value. It's important to note that if the string cannot be converted to a valid number, the result will be <code>NaN</code></p>
<h3 id="heading-double-bitwise-not-for-mathfloor"><strong>Double Bitwise NOT for Math.floor:</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// Instead of</span>
<span class="hljs-keyword">const</span> rounded1 = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-number">4.9</span>);
<span class="hljs-built_in">console</span>.log(rounded1); <span class="hljs-comment">// Output: 4</span>
<span class="hljs-comment">// Use</span>
<span class="hljs-keyword">const</span> rounded2 = ~~<span class="hljs-number">4.9</span>;
<span class="hljs-built_in">console</span>.log(rounded2); <span class="hljs-comment">// Output: 4</span>
</code></pre>
<h3 id="heading-swapping-values">Swapping Values:</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// Use destructuring</span>
<span class="hljs-keyword">let</span> a = <span class="hljs-number">5</span>, b = <span class="hljs-number">10</span>;
[a, b] = [b, a];
</code></pre>
<p>Destructuring assignment can be used to exchange the values of two variables in a concise manner, as shown in the example: <code>[a, b] = [b, a];</code>. This eliminates the need for a temporary variable and simplifies the swapping process.</p>
<h3 id="heading-simplify-multiple-criteria-checks-with-arrayincludes">Simplify Multiple Criteria Checks with Array.includes</h3>
<p><strong>Without Array.includes:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> userRole = <span class="hljs-string">"admin"</span>;

<span class="hljs-comment">// Check if the user role is one of the specified roles</span>
<span class="hljs-keyword">if</span> (userRole === <span class="hljs-string">"admin"</span> || userRole === <span class="hljs-string">"editor"</span> || userRole === <span class="hljs-string">"viewer"</span>) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User has a valid role!"</span>);
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Invalid user role."</span>);
}
</code></pre>
<p><strong>With Array.includes:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> validRoles = [<span class="hljs-string">"admin"</span>, <span class="hljs-string">"editor"</span>, <span class="hljs-string">"viewer"</span>];
<span class="hljs-keyword">const</span> userRole = <span class="hljs-string">"admin"</span>;

<span class="hljs-comment">// Check if the user role is in the array of valid roles</span>
<span class="hljs-keyword">if</span> (validRoles.includes(userRole)) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User has a valid role!"</span>);
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Invalid user role."</span>);
}
</code></pre>
<h2 id="heading-objectfreeze-and-immutability"><code>Object.freeze</code> and Immutability:</h2>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a mutable object</span>
<span class="hljs-keyword">const</span> mutableObject = {
  <span class="hljs-attr">property1</span>: <span class="hljs-string">'value1'</span>,
  <span class="hljs-attr">property2</span>: <span class="hljs-string">'value2'</span>
};
<span class="hljs-comment">// Freeze the object to make it immutable</span>
<span class="hljs-keyword">const</span> immutableObject = <span class="hljs-built_in">Object</span>.freeze(mutableObject);
<span class="hljs-comment">// Attempt to modify a property - this will not throw an error, but it won't have any effect</span>
immutableObject.property1 = <span class="hljs-string">'new value'</span>;
<span class="hljs-comment">// Attempt to add a new property - this will not throw an error, but it won't have any effect</span>
immutableObject.property3 = <span class="hljs-string">'value3'</span>;
<span class="hljs-comment">// Attempt to delete a property - this will not throw an error, but it won't have any effect</span>
<span class="hljs-keyword">delete</span> immutableObject.property2;
<span class="hljs-comment">// The original object remains unchanged</span>
<span class="hljs-built_in">console</span>.log(mutableObject); <span class="hljs-comment">// { property1: 'new value', property2: 'value2' }</span>
<span class="hljs-comment">// The frozen object remains unchanged</span>
<span class="hljs-built_in">console</span>.log(immutableObject); <span class="hljs-comment">// { property1: 'value1', property2: 'value2' }</span>
</code></pre>
<p><code>Object.freeze</code> makes an object immutable, preventing changes to its properties.</p>
<p>Although <code>Object.freeze</code> is handy for preventing changes to an object's properties, it's important to keep in mind that it doesn't ensure deep immutability. If your object has nested objects, those nested parts might still be mutable. If you need full deep immutability, you might want to consider taking extra steps or using libraries like <a target="_blank" href="https://immutable-js.com/"><strong>Immutable.js</strong></a>, which specifically support immutable data structures.</p>
<h3 id="heading-logical-and-for-short-circuit-evaluation"><strong>Logical AND for Short-Circuit Evaluation:</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// Instead of if-else</span>
<span class="hljs-keyword">let</span> result;
<span class="hljs-keyword">if</span> (condition) {
  result = <span class="hljs-string">'True'</span>;
} <span class="hljs-keyword">else</span> {
  result = <span class="hljs-string">'False'</span>;
}

<span class="hljs-comment">// Use logical AND</span>
<span class="hljs-keyword">let</span> result = condition &amp;&amp; <span class="hljs-string">'True'</span> || <span class="hljs-string">'False'</span>;
</code></pre>
<h3 id="heading-early-returns-amp-less-nesting">Early Returns &amp; Less Nesting</h3>
<h4 id="heading-less-desirable-example"><strong>Less Desirable Example:</strong></h4>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculatePrice</span>(<span class="hljs-params">quantity, price</span>) </span>{
  <span class="hljs-keyword">if</span> (quantity &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">if</span> (price &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">let</span> totalPrice = quantity * price;

      <span class="hljs-keyword">if</span> (quantity &gt;= <span class="hljs-number">10</span>) {
        totalPrice *= <span class="hljs-number">0.9</span>; <span class="hljs-comment">// 10% discount for quantities of 10 or more</span>
      }

      <span class="hljs-keyword">return</span> totalPrice;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Invalid input: Price must be a positive value."</span>);
    }
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Invalid input: Quantity must be a positive value."</span>);
  }
}
<span class="hljs-keyword">const</span> finalPrice = calculatePrice(<span class="hljs-number">15</span>, <span class="hljs-number">5</span>);
</code></pre>
<h4 id="heading-good-example"><strong>Good Example:</strong></h4>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculatePrice</span>(<span class="hljs-params">quantity, price</span>) </span>{
  <span class="hljs-comment">// Validate input parameters</span>
  <span class="hljs-keyword">if</span> (quantity &lt;= <span class="hljs-number">0</span> || price &lt;= <span class="hljs-number">0</span>) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Invalid input: Quantity and price must be positive values."</span>);
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-comment">// Calculate total price</span>
  <span class="hljs-keyword">const</span> totalPrice = quantity * price;

  <span class="hljs-comment">// Apply discount for bulk purchases</span>
  <span class="hljs-keyword">if</span> (quantity &gt;= <span class="hljs-number">10</span>) {
    <span class="hljs-keyword">return</span> totalPrice * <span class="hljs-number">0.9</span>; <span class="hljs-comment">// 10% discount for quantities of 10 or more</span>
  }

  <span class="hljs-keyword">return</span> totalPrice;
}
<span class="hljs-keyword">const</span> finalPrice = calculatePrice(<span class="hljs-number">15</span>, <span class="hljs-number">5</span>);
</code></pre>
<p>The "Less Nesting, Return Early" coding style provides benefits such as improved readability, better error handling, and easier debugging. It simplifies code structure and makes it more straightforward to understand and maintain.</p>
<h3 id="heading-nullish-coalescing-operator"><strong>Nullish Coalescing Operator (</strong><code>??</code>):</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// Instead of logical OR</span>
<span class="hljs-keyword">const</span> value = (someVariable !== <span class="hljs-literal">null</span> &amp;&amp; someVariable !== <span class="hljs-literal">undefined</span>) ? someVariable : <span class="hljs-string">'default'</span>;
<span class="hljs-comment">// Use nullish coalescing operator</span>
<span class="hljs-keyword">const</span> value = someVariable ?? <span class="hljs-string">'default'</span>;
</code></pre>
<p>The Nullish Coalescing Operator (<code>??</code>) efficiently provides default values for variables, ensuring the right-hand operand is used only when the left-hand operand is <code>null</code> or <code>undefined</code>.</p>
<h3 id="heading-often-underutilized-array-methods-in-javascript">Often underutilized Array methods in JavaScript:</h3>
<ol>
<li><p><strong><mark>flat</mark></strong> and <strong><mark>flatMap</mark></strong>:</p>
<ul>
<li><p><code>flat</code>: Flattens nested arrays.</p>
</li>
<li><p><code>flatMap</code>: Maps each element using a mapping function and then flattens the result.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-javascript">    <span class="hljs-keyword">let</span> nestedArray = [<span class="hljs-number">1</span>, [<span class="hljs-number">2</span>, [<span class="hljs-number">3</span>]]];
    <span class="hljs-keyword">let</span> flatArray = nestedArray.flat(); <span class="hljs-comment">// [1, 2, [3]]</span>
    <span class="hljs-keyword">let</span> mappedFlatArray = nestedArray.flatMap(<span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> [value * <span class="hljs-number">2</span>]); <span class="hljs-comment">// [2, 4, 6]</span>
</code></pre>
<ol>
<li><p><strong><mark>from</mark></strong> with a Mapping Function:</p>
<ul>
<li>Creates a new array with the results of calling a provided function on every element in the array.</li>
</ul>
</li>
</ol>
<pre><code class="lang-javascript">    <span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
    <span class="hljs-keyword">let</span> squaredArray = <span class="hljs-built_in">Array</span>.from(array, <span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> x * x); <span class="hljs-comment">// [1, 4, 9]</span>
</code></pre>
<ol>
<li><p><strong><mark>Reverses</mark></strong> the elements of an array in place.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];
 array.reverse(); <span class="hljs-comment">// [5, 4, 3, 2, 1]</span>
</code></pre>
</li>
<li><p><strong><mark>Array.some: </mark></strong> Checks if at least one element in the array satisfies a provided condition.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> hasPositiveNumber = [<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>].some(<span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num &gt; <span class="hljs-number">0</span>); <span class="hljs-comment">// true</span>
</code></pre>
</li>
<li><p><strong><mark>Array.every</mark>:</strong> Checks if all elements in the array satisfy a provided condition.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> allPositiveNumbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>].every(<span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num &gt; <span class="hljs-number">0</span>); <span class="hljs-comment">// true</span>
</code></pre>
</li>
<li><p><strong><mark>Array.reduceRight</mark>:</strong> Applies a function against an accumulator and each element in the array (from right to left) to reduce it to a single value.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> reversedString = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>].reduceRight(<span class="hljs-function">(<span class="hljs-params">acc, char</span>) =&gt;</span> acc + char, <span class="hljs-string">''</span>); <span class="hljs-comment">// 'cba'</span>
</code></pre>
</li>
</ol>
<h3 id="heading-lesser-known-examples-of-using-tolocalestring-for-various-scenarios">Lesser-known examples of using <code>toLocaleString</code> for various scenarios:</h3>
<ol>
<li><p><strong>Basic Number Formatting:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> number = <span class="hljs-number">1234567.89</span>;
 <span class="hljs-keyword">let</span> formattedNumber = number.toLocaleString(); <span class="hljs-comment">// "1,234,567.89"</span>
</code></pre>
</li>
<li><p><strong>Currency Formatting:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> price = <span class="hljs-number">12345.67</span>;
 <span class="hljs-keyword">let</span> formattedPrice = price.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">style</span>: <span class="hljs-string">'currency'</span>, <span class="hljs-attr">currency</span>: <span class="hljs-string">'USD'</span> }); <span class="hljs-comment">// "$12,345.67"</span>
</code></pre>
</li>
<li><p><strong>Date Formatting:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-string">'2023-01-01T12:34:56'</span>);
 <span class="hljs-keyword">let</span> formattedDate = date.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">dateStyle</span>: <span class="hljs-string">'full'</span>, <span class="hljs-attr">timeStyle</span>: <span class="hljs-string">'short'</span> });
 <span class="hljs-comment">// "Sunday, January 1, 2023 at 12:34 PM"</span>
</code></pre>
</li>
<li><p><strong>Percentage Formatting:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> percentage = <span class="hljs-number">0.456</span>;
 <span class="hljs-keyword">let</span> formattedPercentage = percentage.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">style</span>: <span class="hljs-string">'percent'</span> }); <span class="hljs-comment">// "45.6%"</span>
</code></pre>
</li>
<li><p><strong>Grouping Options:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> largeNumber = <span class="hljs-number">9876543210</span>;
 <span class="hljs-keyword">let</span> formattedLargeNumber = largeNumber.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">useGrouping</span>: <span class="hljs-literal">false</span> }); <span class="hljs-comment">// "9876543210"</span>
</code></pre>
</li>
<li><p><strong>Compact Display for Large Numbers:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> largeNumber = <span class="hljs-number">12345678901234567890</span>;
 <span class="hljs-keyword">let</span> formattedLargeNumber = largeNumber.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">notation</span>: <span class="hljs-string">'compact'</span> }); <span class="hljs-comment">// "12.3Q"</span>
</code></pre>
</li>
<li><p><strong>Customizing Decimal and Thousand Separators:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> customFormattedNumber = <span class="hljs-number">9876543.21</span>.toLocaleString(<span class="hljs-string">'en-US'</span>, { <span class="hljs-attr">minimumFractionDigits</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">maximumFractionDigits</span>: <span class="hljs-number">4</span> });
 <span class="hljs-comment">// "9,876,543.2100"</span>
</code></pre>
</li>
<li><p><strong>Using Locales for Different Regions:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> number = <span class="hljs-number">12345.67</span>;
 <span class="hljs-keyword">let</span> formattedNumberFrench = number.toLocaleString(<span class="hljs-string">'fr-FR'</span>); <span class="hljs-comment">// "12 345,67"</span>
 <span class="hljs-keyword">let</span> formattedNumberGerman = number.toLocaleString(<span class="hljs-string">'de-DE'</span>); <span class="hljs-comment">// "12.345,67"</span>
</code></pre>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Demystifying JavaScript Promises: A Tale of Promise.race and Promise.allSettled]]></title><description><![CDATA[Let's talk about two cool JavaScript tools: Promise.race and Promise.allSettled. Think of them as your trusty superheroes for dealing with multiple promises.
Meet Promise.race: The Fast and the First
Imagine you're in a race with a bunch of tasks, ea...]]></description><link>https://priyankpatel.dev/demystifying-javascript-promises-a-tale-of-promiserace-and-promiseallsettled</link><guid isPermaLink="true">https://priyankpatel.dev/demystifying-javascript-promises-a-tale-of-promiserace-and-promiseallsettled</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[promises]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Wed, 22 Nov 2023 05:30:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700892762520/437cfcd1-904e-4205-8676-b2548534b444.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's talk about two cool JavaScript tools: <code>Promise.race</code> and <code>Promise.allSettled</code>. Think of them as your trusty superheroes for dealing with multiple promises.</p>
<h2 id="heading-meet-promiserace-the-fast-and-the-first">Meet <code>Promise.race</code>: The Fast and the First</h2>
<p>Imagine you're in a race with a bunch of tasks, each taking a different amount of time to finish. Some are sprinters, while others are marathon runners. Now, enter <code>Promise.race</code> - the race coordinator of JavaScript promises!</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> task1 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-string">'Task 1 completed'</span>), <span class="hljs-number">2000</span>));
<span class="hljs-keyword">const</span> task2 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-string">'Task 2 completed'</span>), <span class="hljs-number">1500</span>));
<span class="hljs-keyword">const</span> task3 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-string">'Task 3 completed'</span>), <span class="hljs-number">1000</span>));

<span class="hljs-keyword">const</span> winnerTask = <span class="hljs-built_in">Promise</span>.race([task1, task2, task3]);

winnerTask.then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(result));
<span class="hljs-comment">// Output: "Task 3 completed" (Task 3 finishes first)</span>
</code></pre>
<p>In this scenario, <code>Promise.race</code> is like the referee, and it shouts out the winner as soon as the first task crosses the finish line. It's a great way to handle tasks when you're only interested in the fastest result.</p>
<h2 id="heading-enter-promiseallsettled-handling-lifes-curveballs">Enter <code>Promise.allSettled</code>: Handling Life's Curveballs</h2>
<p>Now, picture this: you're juggling multiple promises, perhaps making requests to different corners of the internet. Some requests may succeed, while others hit roadblocks. That's where <code>Promise.allSettled</code> comes to the rescue!</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> userIds = [<span class="hljs-number">101</span>, <span class="hljs-number">102</span>, <span class="hljs-number">103</span>];
<span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">'https://api.example.com/users/'</span>;

<span class="hljs-keyword">const</span> fetchUser = <span class="hljs-function">(<span class="hljs-params">userId</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> url = <span class="hljs-string">`<span class="hljs-subst">${apiUrl}</span><span class="hljs-subst">${userId}</span>`</span>;
  <span class="hljs-keyword">return</span> fetch(url)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
    .then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> ({ <span class="hljs-attr">status</span>: <span class="hljs-string">'fulfilled'</span>, <span class="hljs-attr">value</span>: user }))
    .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> ({ <span class="hljs-attr">status</span>: <span class="hljs-string">'rejected'</span>, <span class="hljs-attr">reason</span>: error }));
};

<span class="hljs-keyword">const</span> fetchUserPromises = userIds.map(fetchUser);

<span class="hljs-keyword">const</span> handleUserResults = <span class="hljs-function">(<span class="hljs-params">results</span>) =&gt;</span> {
  results.forEach(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (result.status === <span class="hljs-string">'fulfilled'</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User Data:'</span>, result.value);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching user:'</span>, result.reason.message);
    }
  });
};

<span class="hljs-keyword">const</span> allUserPromises = <span class="hljs-built_in">Promise</span>.allSettled(fetchUserPromises);

allUserPromises.then(handleUserResults);
</code></pre>
<p>Think of <code>Promise.allSettled</code> as your reliable friend who collects reports on each promise, whether they succeed or face challenges. It's perfect for scenarios where you want to know the outcome of every promise, no matter what life throws at them.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>And that's a quick peek into the worlds of <code>Promise.race</code> and <code>Promise.allSettled</code>. These superheroes might not have capes, but they're your go-to allies when dealing with multiple promises in JavaScript.</p>
<p>Happy coding, and may your promises always resolve! 🚀✨</p>
]]></content:encoded></item><item><title><![CDATA[🔥Nailing Your First Job Interview: A Fresh Perspective]]></title><description><![CDATA[Introduction:
Entering the professional realm can be both exciting and nerve-wracking for freshers. One crucial step in this journey is the job interview, where first impressions can make or break your chances. In this blog post, we'll explore common...]]></description><link>https://priyankpatel.dev/nailing-your-first-job-interview-a-fresh-perspective</link><guid isPermaLink="true">https://priyankpatel.dev/nailing-your-first-job-interview-a-fresh-perspective</guid><category><![CDATA[interview]]></category><category><![CDATA[newbie]]></category><category><![CDATA[jobs]]></category><category><![CDATA[tips]]></category><category><![CDATA[guide]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sat, 18 Nov 2023 07:16:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/3gMqeoCM3Io/upload/114e7bb7f3127c1aba3e69bb14be28f8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction:</h1>
<p>Entering the professional realm can be both exciting and nerve-wracking for freshers. One crucial step in this journey is the job interview, where first impressions can make or break your chances. In this blog post, we'll explore common mistakes that freshers often make during job interviews and provide valuable tips to help you shine in this crucial stage of your career.</p>
<h3 id="heading-git-more-than-just-jargon">🌱<strong>Git: More Than Just Jargon</strong></h3>
<p>Know the basics of Git. Understand that <strong><mark>Git and GitHub are different animals</mark></strong>, just like JavaScript and Java. Stay in the loop and let your knowledge shine. If you've collaborated on coding projects or used version control in the past, share those experiences. It's not just about knowing the terms; it's about demonstrating practical understanding.</p>
<h2 id="heading-tech-prep-tools-and-environments">🔊Tech Prep: Tools and Environments:</h2>
<p>Install those interview tools early—Microsoft Teams, Zoom, you name it. <strong><mark>Test your audio, output, and camera with some trial calls</mark></strong>. Being tech-ready saves you from those last-minute panics, especially during practical tests. Familiarize yourself with the platforms not just for the interview but for future collaboration.</p>
<h3 id="heading-resume-reality-check">📝 <strong>Resume Reality Check:</strong></h3>
<p>When it comes to your resume, honesty is the best policy. While the length is not crucial, the accuracy of the information is. <strong><mark>Avoid exaggerating your skills</mark></strong>, especially core competencies. Use online tools to generate a clean and simple resume, <strong>steering clear of any spelling mistakes</strong>. And, of course, <strong><mark>refrain from adding a photo</mark></strong>—let your skills and experience speak for themselves.</p>
<h2 id="heading-ditch-the-phone-for-your-phone-interviews">📱Ditch the Phone for Your Phone Interviews:</h2>
<p><strong><mark>Avoid starting phone interviews from your phone.</mark></strong> Practical challenges and technical glitches on a small screen can trip you up, risking a smooth interview and that vital 80% of your first impression. Opt for a stable connection for a seamless experience, showcasing both your skills and professionalism.</p>
<h2 id="heading-backup-internet-life">🌐<strong>Backup Internet Life</strong></h2>
<p>Let's be real—<strong><mark>losing internet when you need it most is the worst</mark></strong>. The fix? A secret weapon: a backup internet plan. Whether it's a trusty <strong><mark>mobile hotspot or an extra connection</mark></strong>, having a Plan B is your escape route from those cringe-worthy "lost connection" moments. Stay connected effortlessly and keep your cool.</p>
<h2 id="heading-location-matters">🏠Location Matters:</h2>
<p><strong><mark>Select a 🔇 quiet setting for your interview.</mark></strong> If background noise is unavoidable, consider noise cancellation tools. A calm environment contributes to clearer communication and reflects positively on your professionalism.</p>
<h2 id="heading-communication-is-key">👽️Communication Is Key:</h2>
<p>Communication goes beyond just verbal interaction. If unexpected circumstances arise and you need to reschedule, <strong><mark>communicate promptly with the HR representative. Leaving them in the dark is unprofessional</mark></strong> and can leave a lasting negative impression.</p>
<h2 id="heading-time-management">🕙Time Management:</h2>
<p>Time is of the essence during interviews. <strong><mark>Be available 15 minutes in advance to demonstrate punctuality.</mark></strong> If, for any reason, you are running late, inform the HR contact immediately. Respecting others' time is a crucial aspect of professionalism.</p>
<h3 id="heading-its-okay-not-to-know-everything"><strong>❌ It's Okay Not to Know Everything</strong></h3>
<p><strong><mark>No need to be a know-it-all.</mark></strong> Embrace the power of "I don't know." Honesty goes a long way, and employers appreciate your willingness to learn.</p>
<h2 id="heading-prepare-for-practical-tests">💯Prepare for Practical Tests:</h2>
<p>Many interviews, especially in technical fields, involve practical tests. <mark>Practice basic code challenges beforehand </mark> <strong>to familiarize yourself with the process</strong>. This preparation will boost your confidence and performance during the actual interview.</p>
<h2 id="heading-believe-in-yourself">💥Believe in Yourself:</h2>
<p>Lastly, instill confidence in yourself. Confidence is key when facing an interview. <strong><mark>Speak with a clear and audible tone</mark></strong> to ensure the interviewer can understand you well. Remember, it's okay not to know everything. <strong><mark>If you're unsure about a question, it's better to admit it than to provide inaccurate information.</mark></strong></p>
<h3 id="heading-conclusion">🚩Conclusion:</h3>
<p>Job interviews can be intimidating, but with the right preparation and mindset, you can navigate them successfully. Avoiding these common mistakes and following these tips will help you make a positive impression and increase your chances of landing that coveted job. <strong><mark>Remember, confidence, honesty, and professionalism are your allies in the interview process. Good luck!</mark></strong></p>
]]></content:encoded></item><item><title><![CDATA[𝐅𝐫𝐨𝐦 𝐩𝐚𝐠𝐞 𝐫𝐞𝐟𝐫𝐞𝐬𝐡𝐢𝐧𝐠 𝐭𝐨 𝐩𝐚𝐠𝐞 𝐢𝐦𝐩𝐫𝐞𝐬𝐬𝐢𝐧𝐠: 𝐭𝐡𝐞 𝐞𝐯𝐨𝐥𝐮𝐭𝐢𝐨𝐧 𝐨𝐟 𝐀𝐉𝐀𝐗.]]></title><description><![CDATA[Today, we're going to embark on a journey through time to explore the evolution of AJAX, a crucial technology that has transformed the way we interact with web pages. From its humble beginnings with the XMLHttpRequest (XHR) object to the modern marve...]]></description><link>https://priyankpatel.dev/8j2qhfcdkkvwnzco8j2qpidwnzcp8j2qmvcdkkdwnzceipcdkkvwnzce8j2qncdkkvwnzce8j2qrpcdkkhwnzci8j2qpcdkkag8j2qrfcdkkgg8j2qqfcdkjrwnzcg8j2qnidwnzci8j2qpvcdkknwnzcr8j2qnvcdkkzwnzcs8j2qovcdkkfwnzcgoidwnzct8j2qofcdkj4g8j2qnvcdkkwnzco8j2qpfcdkk7wnzct8j2qovcdkkjwnzcnipcdkkjwnzcfipcdkidwnzcj8j2qgpcdkjcu</link><guid isPermaLink="true">https://priyankpatel.dev/8j2qhfcdkkvwnzco8j2qpidwnzcp8j2qmvcdkkdwnzceipcdkkvwnzce8j2qncdkkvwnzce8j2qrpcdkkhwnzci8j2qpcdkkag8j2qrfcdkkgg8j2qqfcdkjrwnzcg8j2qnidwnzci8j2qpvcdkknwnzcr8j2qnvcdkkzwnzcs8j2qovcdkkfwnzcgoidwnzct8j2qofcdkj4g8j2qnvcdkkwnzco8j2qpfcdkk7wnzct8j2qovcdkkjwnzcnipcdkkjwnzcfipcdkidwnzcj8j2qgpcdkjcu</guid><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[user experience]]></category><category><![CDATA[modernization]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Tue, 12 Sep 2023 18:30:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694330205211/7faa3c8a-f337-4e3e-bfbd-b5704d840cf8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, we're going to embark on a journey through time to explore the evolution of AJAX, a crucial technology that has transformed the way we interact with web pages. From its humble beginnings with the XMLHttpRequest (XHR) object to the modern marvel that is the Fetch API, AJAX has come a long way, and its impact on web development cannot be overstated.</p>
<h2 id="heading-xhr-the-precursor"><strong>XHR: The Precursor</strong></h2>
<p>Our story begins in the late 1990s when Microsoft introduced the XMLHttpRequest (XHR) object as part of Internet Explorer 5. Initially, this technology was exclusive to Internet Explorer, making it a limited tool for developers. It allowed for asynchronous data retrieval from a server without having to refresh the entire web page. However, its adoption was slow due to its lack of cross-browser compatibility.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694328733145/088cb84d-ad22-4bbb-960b-0fbfbd069072.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-enter-ajax"><strong>Enter AJAX</strong></h2>
<p>Fast forward to 2004, when Jesse James Garrett coined the term "AJAX" (Asynchronous JavaScript and XML) and wrote an influential article titled "Ajax: A New Approach to Web Applications." Garrett's work was a game-changer. It shed light on the potential of asynchronous web requests to create seamless, dynamic user experiences. AJAX was no longer just an obscure technology; it was a revolutionary concept.</p>
<p>Around the same time, jQuery AJAX came onto the scene in 2006. This library simplified asynchronous requests, making it accessible to developers of all skill levels. With jQuery AJAX, a few lines of code could replace complex XHR implementations, and it quickly gained popularity. Developers could now send and receive data from the server without the need for page reloads, drastically improving the user experience.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694328753090/775dcd03-993b-4bdb-aeea-791f0dca8a17.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-rise-of-fetch-api"><strong>The Rise of Fetch API</strong></h2>
<p>As the web continued to evolve, so did the need for more modern and standardized techniques for handling asynchronous requests. Enter the Fetch API in 2015, introduced with the release of ECMAScript 2015. This API brought a breath of fresh air to web development.</p>
<p>The Fetch API utilizes promises, a powerful concept that simplifies asynchronous operations. Promises make code more readable and maintainable by providing a structured way to handle asynchronous tasks. With Fetch, developers could now write cleaner code while fetching data from servers and interacting with APIs seamlessly.</p>
<p>The evolution from XHR to AJAX to Fetch represents a significant shift in web development paradigms. Today, thanks to Fetch and other modern technologies, web applications can provide dynamic, real-time interactions without interrupting the user experience.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694328776486/0b4971df-3ce8-4e9f-a0b7-7d8b0f25a777.jpeg" alt class="image--center mx-auto" /></p>
<p>In conclusion, the evolution of AJAX has been nothing short of remarkable. From its origins as a Microsoft-exclusive feature to becoming a cornerstone of modern web development, AJAX has changed the way we build and experience web applications. As we look to the future, who knows what innovations await us, but one thing is for certain: the journey from page refreshing to page improvising is far from over, and we're excited to see where it takes us next.</p>
<p>Ref: <a target="_blank" href="https://www.linkedin.com/posts/priyank90_ajax-asynchronous-webdevelopment-activity-7052852504388149248-_bwp?utm_source=share&amp;utm_medium=member_desktop">https://www.linkedin.com/posts/priyank90_ajax-asynchronous-webdevelopment-activity-7052852504388149248-_bwp?utm_source=share&amp;utm_medium=member_desktop</a></p>
]]></content:encoded></item><item><title><![CDATA[Unlock Your Tech Enthusiasm with Supabase: The Perfect Playground for Developers]]></title><description><![CDATA[Unlock Your Tech Enthusiasm with Supabase: The Perfect Playground for Developers
Hey there, tech enthusiasts! If you're the kind of person who lives and breathes technology, who finds joy in tinkering with the latest gadgets and building innovative p...]]></description><link>https://priyankpatel.dev/unlock-your-tech-enthusiasm-with-supabase-the-perfect-playground-for-developers</link><guid isPermaLink="true">https://priyankpatel.dev/unlock-your-tech-enthusiasm-with-supabase-the-perfect-playground-for-developers</guid><category><![CDATA[app development]]></category><category><![CDATA[Databases]]></category><category><![CDATA[APIs]]></category><category><![CDATA[software development]]></category><category><![CDATA[#freeplan]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sun, 10 Sep 2023 05:16:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694322627632/aaedba68-8afd-4659-9f7d-b5a1a7c2d834.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-unlock-your-tech-enthusiasm-with-supabase-the-perfect-playground-for-developers">Unlock Your Tech Enthusiasm with Supabase: The Perfect Playground for Developers</h2>
<p>Hey there, tech enthusiasts! If you're the kind of person who lives and breathes technology, who finds joy in tinkering with the latest gadgets and building innovative projects, then you're about to discover a platform that's tailor-made for you. Meet Supabase, the place where your tech dreams can truly take flight. 🚀</p>
<h3 id="heading-supabase-where-tech-dreams-become-reality-discover-supabasehttpssupabasecom"><strong>Supabase: Where Tech Dreams Become Reality</strong> <a target="_blank" href="https://supabase.com/">Discover Supabase</a></h3>
<p>Supabase is not your run-of-the-mill platform. It's a haven for developers and tech lovers, offering a fantastic FREE plan designed to fuel your passion and elevate your projects. Let's take a closer look at what Supabase has in store:</p>
<h3 id="heading-seamless-integration-with-over-20-frameworks">🛠️ <strong>Seamless Integration with Over 20 Frameworks</strong></h3>
<p>Building with the tools you love has never been easier. Supabase seamlessly integrates with more than 20 popular frameworks, allowing you to code with your preferred stack. Whether you're a React aficionado or a Vue.js enthusiast, Supabase has got your back.</p>
<h3 id="heading-unlimited-api-requests">🌐<strong>Unlimited API Requests</strong></h3>
<p>Forget about those pesky request limits. With Supabase, you can make unlimited API requests, ensuring that your projects run smoothly and efficiently.</p>
<h3 id="heading-effortless-social-authentication">🔐<strong>Effortless Social Authentication</strong></h3>
<p>Tired of wrestling with user logins? Supabase simplifies authentication by supporting your favorite Social OAuth providers. Connect effortlessly with platforms like Google, Facebook, and GitHub, making user authentication a breeze.</p>
<h3 id="heading-generous-database-space">🧮<strong>Generous Database Space</strong></h3>
<p>You'll enjoy up to 500MB of database space, which is perfect for your pet projects or small-scale applications. Supabase provides the room you need to store your data and run your applications without a hitch.</p>
<h3 id="heading-ample-file-storage">💽<strong>Ample File Storage</strong></h3>
<p>Every tech experiment needs data, and Supabase lets you store up to 1GB of files. Keep your project assets organized and easily accessible.</p>
<h3 id="heading-2gb-of-bandwidth-share">🌐<strong>2GB of Bandwidth</strong> Share</h3>
<p>your creations with the world! With up to 2GB of bandwidth, you can ensure that your projects are accessible to users far and wide.</p>
<h3 id="heading-effortless-file-uploads">📤<strong>Effortless File Uploads</strong></h3>
<p>Say goodbye to file size restrictions. Supabase lets you easily upload files up to 50MB in size, giving you the freedom to work with the assets you need.</p>
<h3 id="heading-connect-with-a-large-user-base">👥 <strong>Connect with a Large User Base</strong></h3>
<p>Reach up to 50,000 monthly active users on the FREE plan. Share your passion projects and connect with a global community of tech enthusiasts.</p>
<h3 id="heading-edge-functionality">✨ <strong>Edge Functionality</strong></h3>
<p>Take your projects to the edge with the ability to run up to 500K Edge Function invocations. Enjoy low latency and high performance for your applications.</p>
<h3 id="heading-realtime-capabilities">🕒<strong>Realtime Capabilities</strong></h3>
<p>Handle up to 200 concurrent Realtime connections for those live, interactive experiences that captivate your users.</p>
<h3 id="heading-millions-of-realtime-messages">📩 <strong>Millions of Realtime Messages</strong></h3>
<p>Keep your users engaged and informed by sending up to 2 million Realtime messages.</p>
<h3 id="heading-1-day-log-retention">📅 <strong>1-Day Log Retention</strong></h3>
<p>Have peace of mind knowing that you can look back on your project's logs for up to one day.</p>
<p>With Supabase, you're not just getting a hosting platform; you're getting your very own dedicated PostgreSQL database. PostgreSQL is a trusted and powerful database system relied upon by millions of developers worldwide. It's like having a playground for your tech dreams, where you can experiment, innovate, and create without limitations.</p>
<h2 id="heading-ready-to-dive-in-explore-supabase-documentationhttpssupabasecomdocs"><strong>Ready to Dive In?</strong> <a target="_blank" href="https://supabase.com/docs">Explore Supabase Documentation</a></h2>
<p>Supabase doesn't just offer a feature-rich FREE plan; it also provides extensive documentation to help you get started and make the most of the platform. Whether you're a seasoned developer or just starting your tech journey, Supabase is your ideal companion for bringing your tech dreams to life.</p>
<p>So, what are you waiting for? Dive into the world of Supabase and unleash your creativity. It's time to turn your tech dreams into reality, one project at a time. 🌟</p>
<p>Ref: <a target="_blank" href="https://www.linkedin.com/posts/priyank90_supabase-the-open-source-firebase-alternative-activity-7101076126642413568-Pzp4?utm_source=share&amp;utm_medium=member_desktop">https://www.linkedin.com/posts/priyank90_supabase-the-open-source-firebase-alternative-activity-7101076126642413568-Pzp4?utm_source=share&amp;utm_medium=member_desktop</a></p>
]]></content:encoded></item><item><title><![CDATA[Fig.io: The Future of Terminals is Here – Mac Exclusive for Now, but Linux and Windows Support on the Horizon!]]></title><description><![CDATA[Hey there, tech enthusiasts! I have some exciting news to share, and it's all about the future of terminals. Imagine a terminal that's not only cutting-edge but also game-changing. Well, hold on to your seats because we're about to introduce you to F...]]></description><link>https://priyankpatel.dev/figio-the-future-of-terminals-is-here-mac-exclusive-for-now-but-linux-and-windows-support-on-the-horizon</link><guid isPermaLink="true">https://priyankpatel.dev/figio-the-future-of-terminals-is-here-mac-exclusive-for-now-but-linux-and-windows-support-on-the-horizon</guid><category><![CDATA[terminal]]></category><category><![CDATA[innovation]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Wed, 06 Sep 2023 20:42:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694032313343/8b6a1c81-978a-42ac-8992-9a7477243570.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there, tech enthusiasts! I have some exciting news to share, and it's all about the future of terminals. Imagine a terminal that's not only cutting-edge but also game-changing. Well, hold on to your seats because we're about to introduce you to <a target="_blank" href="http://Fig.io">Fig.io</a>, your new terminal buddy!</p>
<h1 id="heading-whats-the-buzz-all-about"><strong>What's the Buzz All About? 🐝</strong></h1>
<p><a target="_blank" href="http://Fig.io">Fig.io</a> is making waves in the tech world, and for a good reason. While it's currently an exclusive treat for Mac users, here's the thrilling part: Linux and Windows support are on the way! 🍎➡️🖥️</p>
<p>But that's not all. There's more exciting news – Amazon has acquired Fig's technology! 🚀 Curious to learn more? Check out the details <a target="_blank" href="https://lnkd.in/dXCi2bNP"><strong>here</strong></a>.</p>
<h2 id="heading-meet-figiohttpfigio-your-terminal-game-changer"><strong>Meet</strong> <a target="_blank" href="http://Fig.io"><strong>Fig.io</strong></a><strong>: Your Terminal Game-Changer 🤖</strong></h2>
<p><a target="_blank" href="http://Fig.io">Fig.io</a> is packed with features that will revolutionize the way you interact with your terminal:</p>
<h3 id="heading-autocomplete"><strong>✨ Autocomplete</strong></h3>
<p>Say goodbye to endless typing with <a target="_blank" href="http://Fig.io">Fig.io</a>'s IDE-style autocomplete. It offers inline descriptions and powerful suggestions, making coding tasks a breeze. And the best part? It's open-source and fully customizable.</p>
<h3 id="heading-ssh-credentials"><strong>🔒 SSH Credentials</strong></h3>
<p>Access your SSH servers swiftly and securely with <a target="_blank" href="http://Fig.io">Fig.io</a>. Share servers and identities effortlessly with your team and enjoy instant access to remote machines through a user-friendly GUI or the command line interface (CLI).</p>
<h3 id="heading-plugins"><strong>🔌 Plugins</strong></h3>
<p><a target="_blank" href="http://Fig.io">Fig.io</a> simplifies the world of shell plugins. With one-click installation and seamless syncing across devices, the terminal experience just got a whole lot smoother.</p>
<h2 id="heading-what-else-can-you-expect"><strong>What Else Can You Expect? 🚀</strong></h2>
<p>There's so much more to <a target="_blank" href="http://Fig.io">Fig.io</a> that you can explore. To discover all the fantastic features and possibilities, head over to <a target="_blank" href="http://Fig.io"><strong>Fig.io</strong></a> and don't forget to <a target="_blank" href="https://fig.io/download"><strong>download</strong></a> your copy!</p>
<p><strong>Join the Waitlist!</strong></p>
<p>Excited to get your hands on <a target="_blank" href="http://Fig.io">Fig.io</a> for Linux and Windows? Join the waitlist, and you'll be among the first to know when these exciting releases drop.</p>
<p>Stay in the loop with the latest in terminal innovations by following these hashtags on social media: 🚀💻</p>
<p>The future of terminals is bright, and <a target="_blank" href="http://Fig.io">Fig.io</a> is leading the way. Get ready for a whole new level of terminal magic! 🌟</p>
<p>Ref: <a target="_blank" href="https://www.linkedin.com/posts/priyank90_fig-activity-7105276920434503680-K7eI?utm_source=share&amp;utm_medium=member_desktop">https://www.linkedin.com/posts/priyank90_fig-activity-7105276920434503680-K7eI?utm_source=share&amp;utm_medium=member_desktop</a></p>
]]></content:encoded></item><item><title><![CDATA[Dealing with "Oops! Something Went Wrong" in RabbitMQ: How to Make Failed Messages Behave]]></title><description><![CDATA[Introduction
So, you've come across this nifty tool called RabbitMQ that lets different parts of your software have a chat. You're probably pretty excited about getting messages to bounce around between different areas of your app. But, let's be real...]]></description><link>https://priyankpatel.dev/dealing-with-oops-something-went-wrong-in-rabbitmq-how-to-make-failed-messages-behave</link><guid isPermaLink="true">https://priyankpatel.dev/dealing-with-oops-something-went-wrong-in-rabbitmq-how-to-make-failed-messages-behave</guid><category><![CDATA[rabbitmq]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[performance]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Wed, 09 Aug 2023 09:37:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/sdTL4qTynfM/upload/c0c2b0e6c9ad1df8eab674d46b0f8b82.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="hn-embed-widget" id="video-rbmq-dlq"></div><p> </p>
<h1 id="heading-introduction">Introduction</h1>
<p>So, you've come across this nifty tool called RabbitMQ that lets different parts of your software have a chat. You're probably pretty excited about getting messages to bounce around between different areas of your app. But, let's be real for a second - not all message exchanges go off without a hitch. Sometimes, messages trip over their own feet, and that's where two superheroes come in: <strong>the Delayed Message Exchange Plugin and the Dead Letter Queue (DLQ).</strong></p>
<p>They're like the problem solvers of the messaging world, ensuring that even if a message takes a misstep or can't be delivered right away, it's not the end of the world. In this blog, we're going to take a beginner-friendly journey into the heart of these concepts. We'll learn how the Delayed Message Exchange Plugin adds a twist to the usual messaging game, and how the DLQ offers a safety net for messages that encounter a hiccup on their way to their destination. So, whether you're new to messaging or just curious to learn more, get ready to uncover the magic that keeps messages moving smoothly in the world of RabbitMQ!</p>
<h2 id="heading-understanding-the-rabbitmq-delayed-message-exchange-plugin">Understanding the RabbitMQ Delayed Message Exchange Plugin</h2>
<p>It lets you slow down how messages get handled, which comes in handy, especially when dealing with messages that didn't quite make it. Imagine giving those messages a breather and a chance to try again after a little time has passed. When messages have tried and tried but just can't get through, they get shifted to a special place where we can figure out what went wrong and make things better (the DLQ <strong>Zone</strong>).</p>
<h3 id="heading-whats-this-dlq-magic-anyway">What's this DLQ Magic, Anyway?</h3>
<p>The RabbitMQ Dead Letter Queue (DLQ) serves as a backup storage location for messages that could not be delivered successfully. When a message encounters too many hurdles or fails to reach its destination, RabbitMQ routes it to the DLQ for further research. It's a method for determining what went wrong and improving the message process. In a nutshell, DLQ acts as a safety net, helping you understand and fix delivery issues to make your messaging system more reliable.</p>
<h2 id="heading-lets-get-started">Let's get started</h2>
<h3 id="heading-setting-up-the-delayed-message-exchange"><strong>Setting Up the Delayed Message Exchange</strong></h3>
<ol>
<li><p>Navigate to the RabbitMQ plugins directory. It's usually located in <code>/usr/lib/rabbitmq/plugins</code> for Linux systems or <code>C:\Program Files\RabbitMQ\plugins</code> for Windows systems.</p>
</li>
<li><p><a target="_blank" href="https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases">Download the RabbitMQ Delayed Message Exchange Plugin.</a> Ensure that the version of the plugin you download matches the version of your installed RabbitMQ.</p>
</li>
<li><p>Copy the plugin file (with a <code>.ez</code> extension) to the plugins directory.</p>
</li>
<li><p>Enable the plugin by running the following command:</p>
<ul>
<li><pre><code class="lang-bash">  rabbitmq-plugins <span class="hljs-built_in">enable</span> rabbitmq_delayed_message_exchange
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Restart RabbitMQ</strong> for the changes to take effect.</p>
</li>
</ol>
<h3 id="heading-declare-the-necessary-queues-and-exchanges-the-primary-queue-the-dead-letter-queue-dlq-and-the-delayed-exchange">Declare the necessary queues and exchanges: the primary queue, the Dead Letter Queue (DLQ), and the delayed exchange.</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> amqp = <span class="hljs-built_in">require</span>(<span class="hljs-string">"amqplib"</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> amqp.connect(<span class="hljs-string">"amqp://localhost"</span>);
    <span class="hljs-keyword">const</span> channel = <span class="hljs-keyword">await</span> connection.createChannel();

    <span class="hljs-comment">// Define exchange names</span>
    <span class="hljs-keyword">const</span> PRIMARY_EXCHANGE = <span class="hljs-string">"primary_exchange"</span>;
    <span class="hljs-keyword">const</span> DELAY_EXCHANGE = <span class="hljs-string">"delay_exchange"</span>;
    <span class="hljs-keyword">const</span> DEAD_LETTER_EXCHANGE = <span class="hljs-string">"dead_letter_exchange"</span>;

    <span class="hljs-comment">// Define queue names</span>
    <span class="hljs-keyword">const</span> PRIMARY_QUEUE = <span class="hljs-string">"primary_queue"</span>;
    <span class="hljs-keyword">const</span> DEAD_LETTER_QUEUE = <span class="hljs-string">"dead_letter_queue"</span>;

    <span class="hljs-comment">// Define dead letter routing name</span>
    <span class="hljs-keyword">const</span> DEAD_LETTER_ROUTING = <span class="hljs-string">"dead_letter_routing"</span>;

    <span class="hljs-comment">// Setup primary queue</span>
    <span class="hljs-keyword">const</span> createPrimaryExchangeAndQueue = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">await</span> channel.assertExchange(PRIMARY_EXCHANGE, <span class="hljs-string">"direct"</span>, {
        <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
      });
      <span class="hljs-keyword">await</span> channel.assertQueue(PRIMARY_QUEUE, {
        <span class="hljs-attr">exclusive</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">deadLetterExchange</span>: DEAD_LETTER_EXCHANGE,
        <span class="hljs-attr">deadLetterRoutingKey</span>: DEAD_LETTER_ROUTING,
      });
      <span class="hljs-keyword">await</span> channel.bindQueue(PRIMARY_QUEUE, PRIMARY_EXCHANGE);
    };

    <span class="hljs-comment">// Setup delayed exchange</span>
    <span class="hljs-keyword">const</span> createDelayExchange = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">await</span> channel.assertExchange(DELAY_EXCHANGE, <span class="hljs-string">"x-delayed-message"</span>, {
        <span class="hljs-attr">autoDelete</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">arguments</span>: { <span class="hljs-string">"x-delayed-type"</span>: <span class="hljs-string">"direct"</span> },
      });
      <span class="hljs-keyword">await</span> channel.bindQueue(PRIMARY_QUEUE, DELAY_EXCHANGE);
    };

   <span class="hljs-comment">// Setup DLQ</span>
    <span class="hljs-keyword">const</span> createDeadLetterExchangeAndQueue = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">await</span> channel.assertExchange(DEAD_LETTER_EXCHANGE, <span class="hljs-string">"direct"</span>, {
        <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
      });
      <span class="hljs-keyword">await</span> channel.assertQueue(DEAD_LETTER_QUEUE, {
        <span class="hljs-attr">exclusive</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
      });
      <span class="hljs-keyword">await</span> channel.bindQueue(
        DEAD_LETTER_QUEUE,
        DEAD_LETTER_EXCHANGE,
        DEAD_LETTER_ROUTING
      );
    };

    createPrimaryExchangeAndQueue();
    createDelayExchange();
    createDeadLetterExchangeAndQueue();

    <span class="hljs-keyword">await</span> connection.close();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Setup complete."</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error during setup:"</span>, error);
  }
}

setup();
</code></pre>
<p>Let's break down the main three functions step by step:</p>
<ol>
<li><strong>Creating the Primary Exchange and Queue:</strong></li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> createPrimaryExchangeAndQueue = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> channel.assertExchange(PRIMARY_EXCHANGE, <span class="hljs-string">"direct"</span>, {
    <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
  });
  <span class="hljs-keyword">await</span> channel.assertQueue(PRIMARY_QUEUE, {
    <span class="hljs-attr">exclusive</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">deadLetterExchange</span>: DEAD_LETTER_EXCHANGE,
    <span class="hljs-attr">deadLetterRoutingKey</span>: DEAD_LETTER_ROUTING,
  });
  <span class="hljs-keyword">await</span> channel.bindQueue(PRIMARY_QUEUE, PRIMARY_EXCHANGE);
};
</code></pre>
<p>This function creates a direct exchange named <code>primary_exchange</code>, an associated queue named <code>primary_queue</code>, and binds the queue to the exchange. The <code>deadLetterExchange</code> and <code>deadLetterRoutingKey</code> options are set, meaning that if a message in the primary queue fails to be processed, it will be routed to the <code>dead_letter_exchange</code> with the specified routing key.</p>
<ol>
<li><p><strong>Creating the Dead Letter Exchange and Queue:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> createDeadLetterExchangeAndQueue = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">await</span> channel.assertExchange(DEAD_LETTER_EXCHANGE, <span class="hljs-string">"direct"</span>, {
     <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
   });
   <span class="hljs-keyword">await</span> channel.assertQueue(DEAD_LETTER_QUEUE, {
     <span class="hljs-attr">exclusive</span>: <span class="hljs-literal">false</span>,
     <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
   });
   <span class="hljs-keyword">await</span> channel.bindQueue(
     DEAD_LETTER_QUEUE,
     DEAD_LETTER_EXCHANGE,
     DEAD_LETTER_ROUTING
   );
 };
</code></pre>
<p> This function establishes a direct exchange called <code>dead_letter_exchange</code> along with an associated queue named <code>dead_letter_queue.</code> The queue is then linked to the exchange using the designated routing key. Consequently, when a message is negatively acknowledged (<strong>nack</strong>), any message connected to the main queue will be relocated to this designated queue.</p>
<p> These messages will remain there indefinitely, offering us the opportunity to thoroughly investigate and determine the root cause of any issues that may have occurred.</p>
</li>
<li><p><strong>Creating the Delay Exchange:</strong></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> createDelayExchange = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">await</span> channel.assertExchange(DELAY_EXCHANGE, <span class="hljs-string">"x-delayed-message"</span>, {
     <span class="hljs-attr">autoDelete</span>: <span class="hljs-literal">false</span>,
     <span class="hljs-attr">durable</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">passive</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">arguments</span>: { <span class="hljs-string">"x-delayed-type"</span>: <span class="hljs-string">"direct"</span> },
   });
   <span class="hljs-keyword">await</span> channel.bindQueue(PRIMARY_QUEUE, DELAY_EXCHANGE);
 };
</code></pre>
<p> This function sets up a delayed message exchange called <code>delay_exchange</code> using a special RabbitMQ plugin ("x-delayed-message"). This plugin makes messages wait before being delivered. The <code>passive</code> option is set to true to see if the exchange is already there.</p>
<p> This exchange is connected to the <code>primary_queue.</code> So, if a message needs another shot at getting through, it will be sent back to the <code>primary_queue</code> based on our <strong>retry schedule</strong>. This cycle goes on until we give a thumbs-up(<strong>ack)</strong> or thumbs-down(<strong>nack</strong>) to the message.</p>
</li>
</ol>
<h3 id="heading-now-lets-create-the-consumer-to-see-the-final-action-and-mimic-a-real-world-situation">Now, let's create the consumer to see the final action and mimic a real-world situation.</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> PRIMARY_QUEUE = <span class="hljs-string">"primary_queue"</span>;
<span class="hljs-keyword">const</span> DELAY_EXCHANGE = <span class="hljs-string">"delay_exchange"</span>;

<span class="hljs-keyword">const</span> DELAY_DEFAULT = <span class="hljs-number">1000</span>;
<span class="hljs-keyword">const</span> RETRY_LIMIT = <span class="hljs-number">3</span>;
<span class="hljs-keyword">const</span> DEAD_LETTER_DELAY = <span class="hljs-number">3000</span>;

<span class="hljs-keyword">const</span> consumer = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> amqp.connect(<span class="hljs-string">"amqp://localhost"</span>);
  <span class="hljs-keyword">const</span> channel = <span class="hljs-keyword">await</span> connection.createChannel();

  <span class="hljs-comment">// Process max 10 messages at the same time</span>
  channel.prefetch(<span class="hljs-number">10</span>);

  <span class="hljs-comment">// Consume the msg</span>
  <span class="hljs-keyword">await</span> channel.consume(
    PRIMARY_QUEUE,
    <span class="hljs-keyword">async</span> (msg) =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">//<span class="hljs-doctag">TODO:</span> Business logic to process message</span>

        channel.ack(msg);
      } <span class="hljs-keyword">catch</span> (err) {
        moveMessageToDelayExchange(channel, msg);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Server is down. Message is moved to delay exchange."</span>);
      }
    },
    { <span class="hljs-attr">noAck</span>: <span class="hljs-literal">false</span> }
  );
};

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveMessageToDelayExchange</span>(<span class="hljs-params">channel, msg</span>) </span>{
  <span class="hljs-comment">// Move message to DL queue if msg fails to process withing maximum defined attempt</span>
  <span class="hljs-keyword">let</span> maxRetryLimit = msg.properties.headers[<span class="hljs-string">"x-retry-limit"</span>];
  <span class="hljs-keyword">let</span> retryCount = msg.fields.deliveryTag;

  <span class="hljs-comment">// Move msg to dead letter after max retry happened</span>
  <span class="hljs-keyword">if</span> (retryCount &gt;= maxRetryLimit) {
    <span class="hljs-comment">// If allUpTo is truthy, all outstanding messages prior to and including the given message are rejected</span>
    <span class="hljs-comment">// If requeue is truthy, the server will try to put the message or messages back on the queue or queues from which they came.</span>
    channel.nack((message = msg), (allUpTo = <span class="hljs-literal">false</span>), (requeue = <span class="hljs-literal">false</span>));
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-comment">// Ack the msg to remove it from primary queue</span>
  channel.ack(msg);

  <span class="hljs-comment">// Transfer msg to delay exchange so it will retry message based on max retry count</span>
  <span class="hljs-keyword">let</span> newDelay = getDelayRetryInterval(retryCount, DELAY_DEFAULT);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`New delay time <span class="hljs-subst">${newDelay}</span> ms`</span>);
  <span class="hljs-keyword">await</span> channel.publish(DELAY_EXCHANGE, <span class="hljs-string">""</span>, msg.content, {
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"x-delay"</span>: newDelay,
      <span class="hljs-string">"x-retry-limit"</span>: RETRY_LIMIT,
    },
  });
}

<span class="hljs-comment">// Helper function to give linear increasing seconds based on retry count.</span>
<span class="hljs-keyword">const</span> getDelayRetryInterval = <span class="hljs-function">(<span class="hljs-params">retryCount, defaultDelay</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> interval = <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, retryCount - <span class="hljs-number">1</span>) * defaultDelay;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Next message will be retried after <span class="hljs-subst">${interval / <span class="hljs-number">1000</span>}</span> sec`</span>);
  <span class="hljs-keyword">return</span> interval;
};


consumer();
</code></pre>
<ol>
<li><p><strong>Setting Up the Consumer Function</strong>:</p>
<p> The consumer function establishes a connection with the Primary queue to receive and handle incoming messages. By using the <code>prefetch</code> method, it's designed to manage up to 10 messages simultaneously. Think of the <code>prefetch</code> method as a way to control how many messages we handle at once. <strong>It's a crucial setting to prevent overwhelming the system, especially when faced with a sudden influx of thousands of messages.</strong></p>
<p> Now, picture this: when a message smoothly goes through the processing and the code reaches the <code>ack</code> statement within the try block. This is essentially us giving a thumbs-up to the message, signaling that everything went well. As a result, the message earns its exit ticket from the primary queue.</p>
</li>
<li><p><strong>Moving Messages to Delayed Exchange</strong>:</p>
<p> If something goes wrong while we're handling a message (you know, when things don't quite work out), we've got a special trick up our sleeve. We call on the "moveMessageToDelayExchange" function to deal with the hiccup. This function is like the <strong>star of the show in this article</strong> – it's the reason we're here, talking about Delayed Message Exchange and DLQ in the first place.</p>
<p> Now, let's talk about this <code>deliveryTag</code> thing. It's like a special number that comes with the message when we use Delayed Exchanges. It <strong>keeps track of how many times we've tried to pass that message</strong> around. It's like a handy counter that helps us know when to say, "Okay, that's enough trying for now." We have to be smart about it, though. If we keep trying forever, we could end up with a big mess and everything crashing. So, we set a limit on how many times we'll give a message another shot. It's all about finding the right balance!</p>
<ol>
<li><p>The function first checks the number of retry attempts (<code>retryCount</code>) and compares it with the maximum defined attempts (<code>maxRetryLimit</code>) specified in the message headers.</p>
</li>
<li><p>If the retry count exceeds the limit, the message is "nacked" using <code>channel.nack</code>, which will send it to a Dead Letter Queue and that message will be no entertained further.</p>
</li>
<li><p>If the retry count is within the limit, the original message is acknowledged using <code>channel.ack</code> to remove it from the primary queue.</p>
</li>
<li><p>The message is then transferred to a delayed exchange (<code>DELAY_EXCHANGE</code>) with a delay interval (<code>x-delay</code>) based on a retry strategy determined by the <code>getDelayRetryInterval</code> function.</p>
</li>
<li><p>The <code>getDelayRetryInterval</code> function calculates a delay interval for retrying messages. It uses a linear increasing interval strategy, where the interval increases exponentially based on the retry count.</p>
</li>
</ol>
</li>
</ol>
<h3 id="heading-wrapping-things-up">Wrapping things up:</h3>
<p>Dealing with messages that hit a bump in the road is a big deal when you're putting together strong and trustworthy systems with RabbitMQ. Luckily, the RabbitMQ Delayed Message Exchange Plugin is like your secret weapon here. It lets you tackle message detours, retries, and even sets up Dead Letter Queues – all like a pro.</p>
<p>By fine-tuning how often we give messages another shot and how many times we'll try, along with the magic of Dead Letter Queues, we're making sure that even when things hiccup, we're on top of it. We're not just retrying blindly; we're investigating what went wrong and making things right. This smart strategy adds a hefty dose of stability and resilience to your distributed applications, ensuring they can handle whatever comes their way.</p>
]]></content:encoded></item><item><title><![CDATA[Efficiently Handle Large task with Ease: A Guide to Async Generator Functions for Batch Processing]]></title><description><![CDATA[Batch process is a common task when we are working with a large dataset and especially when every single unit of the process is time-consuming. Async generator functions in JavaScript offer an efficient way to process huge datasets asynchronously, wh...]]></description><link>https://priyankpatel.dev/efficiently-handle-large-task-with-ease-a-guide-to-async-generator-functions-for-batch-processing</link><guid isPermaLink="true">https://priyankpatel.dev/efficiently-handle-large-task-with-ease-a-guide-to-async-generator-functions-for-batch-processing</guid><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[performance]]></category><category><![CDATA[asynchronous]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Mon, 06 Mar 2023 14:59:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678114005977/700d1db1-024d-4a28-b522-d668aa9ce213.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Batch process is a common task when we are working with a large dataset and especially when every single unit of the process is time-consuming. Async generator functions in JavaScript offer an efficient way to process huge datasets asynchronously, which can enhance performance and use less time to finish the overall job.</p>
<p>Memory consumption, on the other hand, might be increased as multiple operations execute concurrently depending on the process.</p>
<p>Async generator functions are a combination of two concepts: async functions and generator functions. So let's check the generator function first with a simple example before moving to the async generator function.</p>
<h2 id="heading-generator-function">Generator function</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677994142184/f8b34589-157f-4770-9dfe-d85cca35fdd7.png" alt class="image--center mx-auto" /></p>
<p>The <code>function*</code> syntax is used to define generator functions rather than the usual <code>function</code> syntax. <strong>The</strong> <code>yield</code> <strong>keyword is used within the generator function to pause the function and return a value to the caller.</strong> When you're ready to resume function execution, call the <code>next()</code> method on the <strong>iterator object</strong> to resume execution where it left off.</p>
<p>The generator object contains the <code>next</code> method, which returns another object with the property <code>value</code> and ``done.</p>
<p><code>value</code> will contain the returned value, whereas done will be a boolean that, if true, will end the iteration.</p>
<p>In this case, the <code>createSequence</code> function is an <strong>endless sequence generator</strong>, which means that no matter how many times you call the next method, it will always return a value and the done property will always be false.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">createSequence</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
    <span class="hljs-keyword">yield</span> i++;
  }
}

<span class="hljs-keyword">const</span> generator = createSequence();
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: 1, done: false }</span>
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: 2, done: false }</span>
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: 3, done: false }</span>
</code></pre>
<p>Let's take the previous example and apply a maximum limit to construct a sequence. In the next example, we set the maximum limit to 2, so that if you call the next method <strong>a third time, the value is undefined and the done property returns a false value</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">createSequenceUpTo</span>(<span class="hljs-params">n</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt;= n; i++) {
    <span class="hljs-keyword">yield</span> i;
  }
}

<span class="hljs-keyword">const</span> generator = createSequenceUpTo(<span class="hljs-number">2</span>);
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: 1, done: false }</span>
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: 2, done: false }</span>
<span class="hljs-built_in">console</span>.log(generator.next()); <span class="hljs-comment">// { value: undefined, done: true }</span>
</code></pre>
<h3 id="heading-understand-the-done-attributes-usability">Understand the "Done" attributes usability</h3>
<p>If we insert the generator function from the previous example into the for loop, the for loop would automatically stop after two iterations since we have only yielded the generator function two times, which is how the "done" attribute returned by the next function is beneficial in loops.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">createSequenceUpTo</span>(<span class="hljs-params">n</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt;= n; i++) {
    <span class="hljs-keyword">yield</span> i;
  }
}

<span class="hljs-keyword">for</span>(<span class="hljs-keyword">const</span> number <span class="hljs-keyword">of</span> createSequenceUpTo(<span class="hljs-number">2</span>)) {
  <span class="hljs-built_in">console</span>.log(number)
}
</code></pre>
<h2 id="heading-async-generator-function">Async generator function</h2>
<p><a target="_blank" href="https://unsplash.com/photos/Nzxqc-Vb6zw"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677996768876/b91ea1d3-5085-4114-9d96-c92e5a8220d7.png" alt class="image--center mx-auto" /></a></p>
<p>So far, we've figured out how the generator function works. To spice things up, let's add the Async keywords to the generator function.</p>
<p>The async generator method returns an <strong>asynchronous generator</strong>. Asynchronous generators provide asynchronous iteration, which means they <strong>can produce data without blocking</strong>.</p>
<p>Since we are using dealing with <strong>asynchronous generators</strong>, we have to use <strong>for loop followed by the await keyword.</strong> The necessity for await... comes when the computation of the current iteration on an asynchronous iterator is dependent on some of the previous iterations.</p>
<p><strong>In simpler terms, the</strong> <code>for await</code> <strong>loop is iterating over the async generator function, and the next function will not be iterated until the promise of the current execution is fulfilled.</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">simulateDelay</span>(<span class="hljs-params">value, delay</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> resolve(value), delay));
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">generateNumbers</span>(<span class="hljs-params">n</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; n; i++) {
    <span class="hljs-keyword">yield</span> simulateDelay(i, <span class="hljs-number">1000</span>);
  }
}

(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> number <span class="hljs-keyword">of</span> generateNumbers(<span class="hljs-number">5</span>)) {
    <span class="hljs-built_in">console</span>.log(number);
  }
})();
</code></pre>
<h2 id="heading-batch-processing-with-async-generator-functions">Batch Processing with Async Generator Functions</h2>
<p>Let's look at how we can use async generator functions for batch processing now.</p>
<p>A big dataset is divided into manageable chunks during batch processing, and then each chunk is handled separately.</p>
<p>In order to create batch processing with async generator functions, we can change our generator function to produce a batch of values rather than just one.</p>
<p>Here's an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">generateBatches</span>(<span class="hljs-params">data, batchSize</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; data.length; i += batchSize) {
    <span class="hljs-keyword">yield</span> data.slice(i, i + batchSize);
  }
}

(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> batch <span class="hljs-keyword">of</span> generateBatches(data, <span class="hljs-number">100</span>)) {
    <span class="hljs-keyword">await</span> processBatch(batch);
  }
})();
</code></pre>
<h3 id="heading-a-complete-example-of-an-async-batch-process">A complete example of an Async Batch Process</h3>
<ul>
<li><p>postIds - List of random post Ids that we want to post to the server for the process</p>
</li>
<li><p>longRunningProcess - Assume a long-running process like posting data to the server</p>
</li>
<li><p>tasks - List of longRunningProcess functions</p>
</li>
<li><p>batchTasks - A generator function to process a list of task(longRunningProcess) in batch</p>
</li>
<li><p>sleep - Helper function to a mock long-running process</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">batchTasks</span>(<span class="hljs-params">tasks, limit</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; tasks.length; i = i + limit) {
    <span class="hljs-keyword">const</span> batch = tasks.slice(i, i + limit);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(batch.map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task()));
    <span class="hljs-keyword">yield</span> result;
  }
}

<span class="hljs-keyword">const</span> postIds = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">10</span> }).map(<span class="hljs-function">(<span class="hljs-params">e, idx</span>) =&gt;</span> idx);
<span class="hljs-keyword">const</span> longRunningProcess = <span class="hljs-keyword">async</span> (postId) =&gt; {
  <span class="hljs-comment">// Dummy sleep between 0 to 10 second to mimic long process</span>
  <span class="hljs-keyword">await</span> sleep();
  <span class="hljs-keyword">return</span> postId;
};

<span class="hljs-keyword">const</span> tasks = postIds.map(<span class="hljs-function">(<span class="hljs-params">postId</span>) =&gt;</span> <span class="hljs-function">() =&gt;</span> longRunningProcess(postId));

<span class="hljs-comment">// console.log(tasks);</span>
<span class="hljs-keyword">const</span> CONCURRENT_PROCESS = <span class="hljs-number">3</span>;
(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> batch <span class="hljs-keyword">of</span> batchTasks(tasks, CONCURRENT_PROCESS)) {
    <span class="hljs-comment">//Do something with the processed batch</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Processed batch"</span>, batch);
  }
})();

<span class="hljs-comment">/*
 * Timeout function
 */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Random timeout between 0 to 10 second</span>
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> ms = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">5000</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`process time <span class="hljs-subst">${~~(ms / <span class="hljs-number">1000</span>)}</span> Sec`</span>);
    <span class="hljs-built_in">setTimeout</span>(resolve, ms);
  });
}
</code></pre>
<h2 id="heading-boost-batch-processing-through-pooling">Boost batch processing through pooling</h2>
<p>Batch processing groups a number of "n" tasks to be processed all at once, but it waits for all processes in the current batch to be completed before initiating the next batch.</p>
<p>Imagine you have ten batches, each with ten tasks. When the first batch runs, 10 tasks are processed concurrently. Let's assume three of them are completed too soon, while the remaining seven are still in progress.</p>
<p>If you want to select a new set of three tasks to run, we are still fine because we have enough room to do so. We certainly don't want to finish the remaining 7 to fill the room.</p>
<p><strong>And this is where the Pool concept is useful, ensuring that 10 jobs are constantly in flight regardless of the status of the entire batch.</strong></p>
<p>I have a separate article on how to take a batch process to the next level.</p>
<p><a target="_blank" href="https://priyankpatel.dev/boost-nodejs-performance-by-promise-pool">Boost Node.JS performance by Promise Pool</a></p>
]]></content:encoded></item><item><title><![CDATA[Understanding Time Complexity: A Guide for Beginners]]></title><description><![CDATA[What is time complexity?
Time complexity is a measure of an algorithm's efficiency based on the amount of time it takes to run as the input size grows. Big O notation is typically used to represent how long an algorithm will take to complete.
so, Wha...]]></description><link>https://priyankpatel.dev/understanding-time-complexity-a-guide-for-beginners</link><guid isPermaLink="true">https://priyankpatel.dev/understanding-time-complexity-a-guide-for-beginners</guid><category><![CDATA[Time Complexity]]></category><category><![CDATA[performance]]></category><category><![CDATA[#big o notation]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[datastructure]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Fri, 24 Feb 2023 16:12:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/dhZtNlvNE8M/upload/e3e0c2d5127d5b17e0ed569e2037cf82.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-is-time-complexity">What is time complexity?</h1>
<p>Time complexity is a measure of an algorithm's efficiency based on the amount of time it takes to run as the input size grows. Big O notation is typically used to represent how long an algorithm will take to complete.</p>
<h2 id="heading-so-what-is-big-o-notation">so, What is Big O notation?</h2>
<p>Big O notation is a way to determine how quickly an algorithm expands as the size of its input increases. It's like estimating the time it will take to sort a list of numbers based on the amount of numbers in the list.</p>
<p>Assume you have a list of 100 numbers you wish to sort. You could have a list-sorting method that takes 10 seconds. Assume you have a list of 1,000 numbers to sort. You might anticipate that the identical algorithm will take 100 seconds. Big O notation makes it easy to represent this growth rate.</p>
<h2 id="heading-here-are-some-common-time-complexities">Here are some common time complexities.</h2>
<p><strong>O(1): Constant time.</strong> The algorithm's processing time is independent of the size of the input. This type of time complexity is the most efficient. <strong>It is linked to finding items in an array by index or getting information from a dictionary by key</strong>.</p>
<p><strong>O(log n): Logarithmic time.</strong> When the size of the input rises, the algorithm's execution time gradually grows. This time complexity is often associated <strong>with binary search and other divide-and-conquer algorithms</strong>.</p>
<p><strong>O(n): Linear time.</strong> The algorithm's execution time increases linearly with the size of the input. An example of a linear time complexity algorithm is <strong>searching an array and operating on each entry</strong>.</p>
<p><strong>O(n log n): Linearithmic time.</strong> It has a linearithmic time complexity and will have an execution time that increases proportionally to the input size (n), multiplied by the logarithm of the input size (log n). This time complexity is often <strong>associated with sorting algorithms</strong>.</p>
<p><strong>O(n^2): Quadratic time.</strong> It takes a long time to run as the input size increases, and the time it takes to complete the algorithm increases at an exponential rate. This time complexity is often <strong>associated with nested loop operations</strong>.</p>
<p><strong>O(2^n): Exponential time.</strong> Even for inputs of a reasonable size, it can be extremely sluggish and inefficient. Its time complexity is frequently <strong>connected with recursive algorithms</strong>, which produce all viable combinations of a set of elements or search for a solution thoroughly.</p>
<h2 id="heading-explaining-time-complexity-with-examples-from-the-real-world">Explaining Time Complexity with Examples from the Real World</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677254664540/dfe98c48-def8-46b3-be35-d3d49dea9b24.jpeg" alt class="image--center mx-auto" /></p>
<p>For the sake of simplification, I will only use examples with O(1) and O(n) time complexity.</p>
<p>As a developer, we are dealing with almost every day to perform filters over the array as per the demand of the task. Everything goes smoothly until the data size is smaller but the filter operation gets slow as the array size keeps increasing.</p>
<p>The array filter function scans each element in the array to get a result as per a given condition, therefore <a target="_blank" href="https://en.wikipedia.org/wiki/Time_complexity">time complexity is O(n</a>) for the filter function.</p>
<h3 id="heading-understand-the-challenge-of-searching-data-within-big-arrays-owing-to-on-complexity">Understand the challenge of searching data within big Arrays owing to O(n) complexity.</h3>
<p>We deal with performing filters over arrays almost every day as developers.   Everything works OK until the data size is small, however as the array size grows larger, the filter operation becomes slow.</p>
<p>The array filter function scans each member in the array to determine the outcome based on a given condition, hence the filter function's time complexity is O(n).</p>
<p><strong>Let's begin by performing a filter search over an array containing 10 million data points.</strong></p>
<p>In the code snippet shown below, I first filled the array with 10 million fake data and then I added a second array size of 50, which we would use to search each item in the large array.</p>
<p>The time it takes to find all 50 objects from that big array is close to 4 or 5 seconds. To view it, click the CodePen link.</p>
<p><a target="_blank" href="https://codepen.io/priyankatgit/pen/wvxwNyM">CodePen</a></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Populate Array size of 10 Million data 😱</span>
<span class="hljs-keyword">let</span> data = [];
<span class="hljs-keyword">const</span> tenMillion = <span class="hljs-number">10</span>_000_000;
resultElement.innerText = <span class="hljs-string">"Preparing Array"</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; tenMillion; i++) {
  data.push({ <span class="hljs-attr">item</span>: i, <span class="hljs-attr">number</span>: <span class="hljs-string">`Number_<span class="hljs-subst">${i}</span>`</span> });
}

<span class="hljs-comment">// Populate Array size of 50 having random numbers.</span>
<span class="hljs-comment">// We will search each item of this array in that big size of array 🤒</span>
<span class="hljs-keyword">const</span> itemsToSearch = <span class="hljs-built_in">Array</span>.from(
  { <span class="hljs-attr">length</span>: <span class="hljs-number">50</span> },
  <span class="hljs-function">() =&gt;</span> ~~(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">9</span>_000_000)
);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Array search starts"</span>);
<span class="hljs-keyword">const</span> startTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
<span class="hljs-keyword">const</span> timeLogs = itemsToSearch.map(<span class="hljs-function">(<span class="hljs-params">searchItem</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> start = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  <span class="hljs-keyword">const</span> item = data.filter(<span class="hljs-function">(<span class="hljs-params">d</span>) =&gt;</span> d.item === searchItem);
  <span class="hljs-keyword">const</span> end = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  <span class="hljs-keyword">return</span> <span class="hljs-string">`Took <span class="hljs-subst">${end - start}</span> Milliseconds to find <span class="hljs-subst">${searchItem}</span>`</span>;
});
<span class="hljs-keyword">const</span> endTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();

<span class="hljs-built_in">console</span>.log(
  <span class="hljs-string">`Searching the array took <span class="hljs-subst">${endTime - startTime}</span> milliseconds for <span class="hljs-subst">${
    itemsToSearch.length
  }</span> items over 10 Million size of Array.`</span>
);
</code></pre>
<h3 id="heading-improvement-using-dictionary-dataset">Improvement using dictionary dataset</h3>
<p>Let us enhance the process of identifying an item in an array. To accomplish this, we changed an array to a dictionary, where the key of the dictionary is set to the item we're looking for. It is a random unique number in this case.</p>
<p>The time it takes to discover 50 entries in the dictionary is almost between 0 and 1 milliseconds. However, we have introduced extra overhead in code to convert the array to a dictionary, but the time to do that action is only 300 to 400 milliseconds, which is pretty acceptable for overall speed.</p>
<p>We changed the program's operational complexity from O(n) to O (1).</p>
<p><a target="_blank" href="https://codepen.io/priyankatgit/pen/yLqBmXB">CodePen</a></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Populate Array size of 10 Million data 😱</span>
<span class="hljs-keyword">let</span> data = [];
<span class="hljs-keyword">const</span> tenMillion = <span class="hljs-number">10</span>_000_000;
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"starts"</span>);
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">"prepare array"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; tenMillion; i++) {
  data.push({ <span class="hljs-attr">item</span>: i, <span class="hljs-attr">number</span>: <span class="hljs-string">`Number_<span class="hljs-subst">${i}</span>`</span> });
}
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">"prepare array"</span>);

<span class="hljs-comment">// Populate Array size of 50 having random numbers.</span>
<span class="hljs-comment">// We will search each item of this array in that big size of array 🤒</span>
<span class="hljs-keyword">const</span> itemsToSearch = <span class="hljs-built_in">Array</span>.from(
  { <span class="hljs-attr">length</span>: <span class="hljs-number">50</span> },
  <span class="hljs-function">() =&gt;</span> ~~(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">9</span>_000_000)
);

<span class="hljs-built_in">console</span>.time(<span class="hljs-string">"transform_array_to_dictionary"</span>);
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">"time_including_tranforming_array_to_dict"</span>);
<span class="hljs-keyword">let</span> dataDict = {};
data.forEach(<span class="hljs-function">(<span class="hljs-params">d</span>) =&gt;</span> (dataDict[d.item] = d));
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">"transform_array_to_dictionary"</span>);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Dictionary search starts"</span>);
<span class="hljs-keyword">const</span> startTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
<span class="hljs-keyword">const</span> timeLogs = itemsToSearch.map(<span class="hljs-function">(<span class="hljs-params">searchItem</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> start = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  <span class="hljs-keyword">const</span> item = dataDict[searchItem];
  <span class="hljs-keyword">const</span> end = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  <span class="hljs-keyword">return</span> <span class="hljs-string">`Took <span class="hljs-subst">${end - start}</span> Milliseconds to find <span class="hljs-subst">${searchItem}</span>`</span>;
});
<span class="hljs-keyword">const</span> endTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
<span class="hljs-comment">// console.log(timeLogs);</span>
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">"time_including_tranforming_array_to_dict"</span>);

<span class="hljs-built_in">console</span>.log(
  <span class="hljs-string">`Searching the array took <span class="hljs-subst">${endTime - startTime}</span> milliseconds for <span class="hljs-subst">${
    itemsToSearch.length
  }</span> items over 10 Million size of Array.`</span>
);
</code></pre>
<h3 id="heading-in-summary">IN SUMMARY,</h3>
<p>In summary, by understanding time complexity, we can provide more efficient and effective solutions that can solve problems quickly and efficiently, regardless of input size. As technology continues to advance and data sets grow larger, the importance of time complexity will only increase. Therefore, it's essential to continue learning and mastering this concept to become a successful programmer.</p>
]]></content:encoded></item><item><title><![CDATA[Balancing Performance and Scalability
with Elasticsearch Shards and Replicas]]></title><description><![CDATA[Disclaimer

The entire article is based on a Stack Overflow response about shards and replicas, and all credit goes to Javanna for providing an outstanding explanation.
The explanation is so simple that even if you have no idea what the hell shard an...]]></description><link>https://priyankpatel.dev/balancing-performance-and-scalability-with-elasticsearch-shards-and-replicas</link><guid isPermaLink="true">https://priyankpatel.dev/balancing-performance-and-scalability-with-elasticsearch-shards-and-replicas</guid><category><![CDATA[elasticsearch]]></category><category><![CDATA[sharding]]></category><category><![CDATA[optimization]]></category><category><![CDATA[BigData]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sat, 18 Feb 2023 07:47:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676702761887/e63ba735-8777-4aaf-9107-d0e6fd7a56e2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-disclaimer">Disclaimer</h1>
<blockquote>
<p>The entire article is based on a <a target="_blank" href="https://stackoverflow.com/a/15705989/696602">Stack Overflow</a> response about shards and replicas, and all credit goes to <a target="_blank" href="https://stackoverflow.com/users/633239/javanna">Javanna</a> for providing an outstanding explanation.</p>
<p>The explanation is so simple that even if you have no idea what the hell shard and replica are, you should be able to grasp high-level notions within a few minutes.</p>
<p>It is simply an attempt to draw attention to folks who may want to recognize the distinction between Shards and Replicas without using jargon.</p>
</blockquote>
<h2 id="heading-how-is-data-dispersed-throughout-the-shard">How is data dispersed throughout the shard?</h2>
<p>When you download elasticsearch and start it up, you create an elasticsearch node that tries to join an existing cluster if available or creates a new one. Let's say you created your own new cluster with a single node, the one that you just started up. We have no data, therefore we need to create an index.</p>
<p>When you create an index (an index is automatically created when you index the first document as well) you can define how many shards it will be composed of. If you don't specify a number it will have the default number of shards: 5 primaries. What does it mean?</p>
<p>It means that elasticsearch will create 5 primary shards that will contain your data:</p>
<pre><code class="lang-javascript"> ____    ____    ____    ____    ____
| <span class="hljs-number">1</span>  |  | <span class="hljs-number">2</span>  |  | <span class="hljs-number">3</span>  |  | <span class="hljs-number">4</span>  |  | <span class="hljs-number">5</span>  |
|____|  |____|  |____|  |____|  |____|
</code></pre>
<p>Every time you index a document, elasticsearch will decide which primary shard is supposed to hold that document and will index it there. Primary shards are not a copy of the data, they are the data! Having multiple shards does help take advantage of parallel processing on a single machine, but the whole point is that if we start another elasticsearch instance on the same cluster, the shards will be distributed in an even way over the cluster.</p>
<p>Node 1 will then hold for example only three shards:</p>
<pre><code class="lang-javascript"> ____    ____    ____ 
| <span class="hljs-number">1</span>  |  | <span class="hljs-number">2</span>  |  | <span class="hljs-number">3</span>  |
|____|  |____|  |____|
</code></pre>
<p>Since the remaining two shards have been moved to the newly started node:</p>
<pre><code class="lang-javascript"> ____    ____
| <span class="hljs-number">4</span>  |  | <span class="hljs-number">5</span>  |
|____|  |____|
</code></pre>
<p>Why does this happen? Because elasticsearch is a distributed search engine and this way you can make use of multiple nodes/machines to manage big amounts of data.</p>
<p>Every elasticsearch index is composed of at least one primary shard since that's where the data is stored. Every shard comes at a cost, though, therefore if you have a single node and no foreseeable growth, just stick with a single primary shard.</p>
<h2 id="heading-why-do-we-require-a-replica">Why do we require a replica?</h2>
<p>Another type of shard is a replica. The default is 1, meaning that every primary shard will be copied to another shard that will contain the same data. Replicas are used to increase search performance and for fail-over. A replica shard is never going to be allocated on the same node where the related primary is (it would pretty much be like putting a backup on the same disk as the original data).</p>
<p>Back to our example, with 1 replica we'll have the whole index on each node, since 2 replica shards will be allocated on the first node and they will contain exactly the same data as the primary shards on the second node:</p>
<pre><code class="lang-javascript"> ____    ____    ____    ____    ____
| <span class="hljs-number">1</span>  |  | <span class="hljs-number">2</span>  |  | <span class="hljs-number">3</span>  |  | <span class="hljs-number">4</span>R |  | <span class="hljs-number">5</span>R |
|____|  |____|  |____|  |____|  |____|
</code></pre>
<p>Same for the second node, which will contain a copy of the primary shards on the first node:</p>
<pre><code class="lang-javascript"> ____    ____    ____    ____    ____
| <span class="hljs-number">1</span>R |  | <span class="hljs-number">2</span>R |  | <span class="hljs-number">3</span>R |  | <span class="hljs-number">4</span>  |  | <span class="hljs-number">5</span>  |
|____|  |____|  |____|  |____|  |____|
</code></pre>
<p>With a setup like this, if a node goes down, you still have the whole index. The replica shards will automatically become primaries and the cluster will work properly despite the node failure, as follows:</p>
<pre><code class="lang-javascript"> ____    ____    ____    ____    ____
| <span class="hljs-number">1</span>  |  | <span class="hljs-number">2</span>  |  | <span class="hljs-number">3</span>  |  | <span class="hljs-number">4</span>  |  | <span class="hljs-number">5</span>  |
|____|  |____|  |____|  |____|  |____|
</code></pre>
<p>Since you have <code>"number_of_replicas":1</code>, the replicas cannot be assigned anymore as they are never allocated on the same node where their primary is. That's why you'll have 5 unassigned shards, the replicas, and the cluster status will be <code>YELLOW</code> instead of <code>GREEN</code>. No data loss, but it could be better as some shards cannot be assigned.</p>
<p>As soon as the node that had left is backed up, it'll join the cluster again and the replicas will be assigned again. The existing shard on the second node can be loaded but they need to be synchronized with the other shards, as write operations most likely happened while the node was down. At the end of this operation, the cluster status will become <code>GREEN</code>.</p>
]]></content:encoded></item><item><title><![CDATA[Boost Node.JS  performance by Promise Pool]]></title><description><![CDATA[The async function, which is at the core of JavaScript, is constantly utilized to improve the user experience. As JavaScript evolved, Promises were introduced to alleviate the burden of managing callback functions when an application handles a lot of...]]></description><link>https://priyankpatel.dev/boost-nodejs-performance-by-promise-pool</link><guid isPermaLink="true">https://priyankpatel.dev/boost-nodejs-performance-by-promise-pool</guid><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[concurrency]]></category><category><![CDATA[performance]]></category><category><![CDATA[promises]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Mon, 15 Aug 2022 18:18:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659784804476/g-COxojjm.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The async function, which is at the core of JavaScript, is constantly utilized to improve the user experience. As JavaScript evolved, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> were introduced to alleviate the burden of managing callback functions when an application handles a lot of async functions concurrently.</p>
<p>Promise Pool is a concept to handle numerous concurrent operations more effectively in the progression of async functions.</p>
<h1 id="heading-lets-begin-with-a-real-world-use-scenario">Let's begin with a real-world use scenario.</h1>
<p>Consider the scenario when we need to add a lot of products to the database from a CSV file or any other external API source.</p>
<p>The following code snippet represents one possible implementation.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="4d64723d36b3657686fa4b2ce0c45fbb"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/priyankatgit/4d64723d36b3657686fa4b2ce0c45fbb" class="embed-card">https://gist.github.com/priyankatgit/4d64723d36b3657686fa4b2ce0c45fbb</a></div><p> </p>
<p>However, a seasoned developer can make the observation and will say - <em>"Hey dude, your code is inefficient because it waits for each import product process sequentially, thus overall product import process would take much more time."</em> 👎</p>
<p>That's correct, so let's use the promise all feature to make it better so that each product import process can run concurrently and the whole import process will be incredibly quick.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="850ad430e00916cebf5779c2ffb6b24e"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/priyankatgit/850ad430e00916cebf5779c2ffb6b24e" class="embed-card">https://gist.github.com/priyankatgit/850ad430e00916cebf5779c2ffb6b24e</a></div><p> </p>
<h2 id="heading-but-there-are-always-drawbacks-to-advantages">But there are always drawbacks to advantages. 🤔</h2>
<p>Now imagine that you are importing thousands of products. If you were to use <code>promise.all()</code> in that scenario, you would end up running thousands of operations concurrently, which would result in a locking involved database tables, high CPU usage on the server, a backlog of requests for the V8 engine to process, as well as other problems.</p>
<p>Promise pools libraries can help in this situation. The idea is straightforward; it gives us the ability to manage multiple operations at once. The same principle is shared by many libraries, however in this article I'll focus on the <a target="_blank" href="https://github.com/supercharge/promise-pool">Supercharge Promise Pool</a> library.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="a04ace9f04d691e007afd249a7f6313f"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/priyankatgit/a04ace9f04d691e007afd249a7f6313f" class="embed-card">https://gist.github.com/priyankatgit/a04ace9f04d691e007afd249a7f6313f</a></div><p> </p>
<p>With its <code>withConcurrency</code> API, we can define any positive arbitrary number, and it will carry out that many operations concurrently at any given time.</p>
<p>The <code>process</code> function takes a callback function where any processing function can be passed and promises are resolved based on the defined concurrent operation capacity.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>While both the Promise.all() and Promise Pool libraries can run several processes concurrently, the Promise Pool library is better if there is a larger amount of data to be processed because it has the advantage of providing API control over the parallel process.</p>
]]></content:encoded></item><item><title><![CDATA[Key points to focus for new developer after getting a Job 🎯]]></title><description><![CDATA[I've spent around 10+ years in a small organization and by far I have worked with many new developers. Based on that experience, I'm sharing some key points that might be useful for new developers who have landed their first job.
One who is a beginne...]]></description><link>https://priyankpatel.dev/key-points-to-focus-for-new-developer-after-getting-a-job</link><guid isPermaLink="true">https://priyankpatel.dev/key-points-to-focus-for-new-developer-after-getting-a-job</guid><category><![CDATA[Career]]></category><category><![CDATA[communication]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[programing]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Wed, 20 Apr 2022 12:41:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637909832295/x0vGvuXUZ.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've spent around 10+ years in a small organization and by far I have worked with many new developers. Based on that experience, I'm sharing some key points that might be useful for new developers who have landed their first job.</p>
<p>One who is a beginner and hired of course would have basic to advance level knowledge in a relevant stack but every company has a different work model in terms of application development which they have prepared over the years by having experience in performance in the application, developer onboarding process and team productivity. </p>
<p>Sorry, I don't mean to overwhelm anyone 😱 but if you are just starting and you find that you're overwhelmed during the onboarding process, don't worry, things take time. Please be patient and follow the few simple points below to make sure your mentor and your path run smoothly. 🗻</p>
<h1 id="heading-1-keep-a-notebook-in-meetings">1. Keep a notebook in meetings 📝</h1>
<p>Keep a notebook always with you when you go for meetings or when you have a conversation about any issue or topic. Note down all the points that you would like to have a deeper look at on your desk.</p>
<p>As a beginner sometimes you will hear lots of jargon during the conversation with a senior. Do not hesitate to clarify those words in simple terms that you will understand and also keep note of that word for your reference.</p>
<h1 id="heading-2-make-a-list-of-all-your-questions">2. Make a list of all your questions 🧾</h1>
<p>Initially, one could have many questions and doubts while working on the assignment. Please don't ask them at any time if they are not your immediate blocker. Instead, prepare a list of all your doubts and clarify them in one go each day based on the time conventions of your mentor.</p>
<p>This way, your mentor and you both can work effectively without compromising productivity.</p>
<h1 id="heading-3-be-honest-and-say-no">3. Be honest and say "No" 😬</h1>
<p>If you don't know something that comes up all of a sudden that you are supposed to know, feel free to say "No" but in a different way. </p>
<blockquote>
<p>I did not get a chance to explore this particular topic, let me buy some time to go through more in detail and I will come back to you if I have any questions. </p>
</blockquote>
<p>Don't make any vague assumptions, because you have to speak anyway, it will put you in a more awkward situation.  </p>
<h1 id="heading-4-jump-down-the-rabbit-hole-and-ask-clear-questions">4. Jump down the rabbit hole and ask clear questions 📢</h1>
<p>Just read <a target="_blank" href="https://genericmikechen.hashnode.dev/how-to-ask-questions-as-a-new-engineer#heading-before">"How to ask questions as a new engineer"</a>.
Thanks, <a target="_blank" href="https://hashnode.com/@genericmikechen">Mike</a> for the amazing article. I cannot write better than this.</p>
<h1 id="heading-5-work-like-a-pro">5. Work like a Pro  👩‍💻👨‍💻</h1>
<p>Learn and use <a target="_blank" href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf">shortcuts</a> of the IDE that you're using. Learn shortcuts for the browser. Save your keyboard keystrokes (<strong>especially Ctrl + S</strong>). Turn on autosave in IDE. If you don't like autosave, at least <strong>don't use Ctrl + S repeatedly for no reason</strong>. Take care of your fingers if you're not planning to retire early.</p>
<p><strong>Start observing around</strong>, mainly your coworkers, how they are being productive, what extra tools they are using which you may use to ease your work, etc...</p>
<h1 id="heading-6-focus">6 Focus 📵</h1>
<p>Mobile is the only reason for most people to be constantly distracted. To be more focused just keep your mobile silent(<strong>Not even on vibrate mode</strong>). If you tend to keep your mobile on the desk, flip it to the other side.</p>
<h1 id="heading-7-think-simple-and-make-complex-things-simple">7. Think simple and make complex things simple 🤹🏻‍♀️</h1>
<p>In any onboarding process, task complexity moves from easy to complex. Your mentor is always available to help you when you need them. </p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks">Bookmark</a> every relevant function in code so you can pick up where you left off easily in your assignment, so you don't get lost in a massive spider project of hundreds of files and folders.</p>
<p>Write down pseudo-code and flow in your notebook if you think you need to get verified before you start. Break up your big assignment into several individual tasks instead of eating up everything at once. Prepare task list properly with all details like input, output, validations, etc... Connect all tasks one by one, and test them as a single unit.</p>
<h1 id="heading-8-use-your-weekend">8. Use your weekend 💪🏼</h1>
<blockquote>
<p>Don't get me wrong, I never mean you should sacrifice your family and friends time.</p>
</blockquote>
<p>After spending the first week in your job, you will get a general idea of what types of assignments are given to you, what expectations have been set, what area requires more focus, etc... Start spending your weekends improving the technical side and turning your weaknesses into strengths.</p>
<h1 id="heading-9-dont-feel-burnout-andamp-be-motivated">9. Don't feel burnout &amp; Be motivated 🧎🏻‍♂️</h1>
<p>Use your weekend wisely while you're at it. Don't feel burnout and keep your energy up for Monday too.
As I mentioned earlier, one can feel overwhelmed at the beginning, but do not lose your patience.
Read articles, practice them, and improve your knowledge every day. Try your best to follow some simple steps, and keep taking steps.</p>
<h1 id="heading-read-these-astonishing-articles">Read these astonishing articles.</h1>
<p><a target="_blank" href="https://curtiseinsmann.hashnode.dev/soft-skills-help-developers-level-up-here-are-the-10-id-tell-my-junior-self">Soft skills help developers level up</a></p>
<p><a target="_blank" href="https://hackernoon.com/10-soft-skills-every-developer-needs-66f0cdcfd3f7">10 Soft Skills Every Developer Needs</a></p>
]]></content:encoded></item><item><title><![CDATA[Google Trends Unveiled: Analyzing Technology Stack and Tools Trends]]></title><description><![CDATA[Disclaimer: This article is not in favor of any particular stack. Please don't get offended.

It is to take a quick look at how the popularity of tech stacks has changed over time using Google Trends.
Some people may believe that a few of the trends ...]]></description><link>https://priyankpatel.dev/google-trends-unveiled-analyzing-technology-stack-and-tools-trends</link><guid isPermaLink="true">https://priyankpatel.dev/google-trends-unveiled-analyzing-technology-stack-and-tools-trends</guid><category><![CDATA[full stack]]></category><category><![CDATA[Google]]></category><category><![CDATA[data analysis]]></category><category><![CDATA[Developer]]></category><category><![CDATA[framework]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Tue, 19 Apr 2022 11:30:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/qac9Q3pWHWg/upload/v1650365246347/UHsfHga8M.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>Disclaimer: This article is not in favor of any particular stack. Please don't get offended.</p>
</blockquote>
<p>It is to take a quick look at how the popularity of tech stacks has changed over time using Google Trends.</p>
<p>Some people may believe that a few of the trends aren't living up to the hype. Let me know if it can be made more precise by tuning the search category or using a better keyword.</p>
<p><a target="_blank" href="https://glitch.com/edit/#!/last-10-years-tech-trends">Glitch</a></p>
<iframe src="https://last-10-years-tech-trends.glitch.me" style="height:6000px;width:100%"></iframe>]]></content:encoded></item><item><title><![CDATA[Build Virtual Reality experiences using A-Frame framework]]></title><description><![CDATA[Who's this article for?
This article is for the beginner in virtual reality development. Therefore to keep it simple, the article contains the key focus area points to get quickly on board. 
https://vrprofile.glitch.me/ 



Building virtual reality e...]]></description><link>https://priyankpatel.dev/build-virtual-reality-experiences-using-a-frame-framework</link><guid isPermaLink="true">https://priyankpatel.dev/build-virtual-reality-experiences-using-a-frame-framework</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[ThreeJS]]></category><category><![CDATA[Virtual Reality]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[WebGL]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Fri, 19 Nov 2021 20:52:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637350351830/O9VoJLOyS.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-whos-this-article-for">Who's this article for?</h3>
<p>This article is for the beginner in virtual reality development. Therefore to keep it simple, the article contains the key focus area points to get quickly on board. </p>
<p><a target="_blank" href="https://vrprofile.glitch.me">https://vrprofile.glitch.me/</a> </p>
<iframe height="400" style="width:100%" src="https://vrprofile.glitch.me/">
</iframe>

<p>Building virtual reality experiences is one of the next things that every tech giant company is focusing on. And why not, this experience is so awesome that anyone can get amazed in a second. </p>
<p>Facebook takes....sorry, Meta takes it too seriously. 😆 </p>
<p>But taking a hand into the development for a new person is tedious as it requires installing development tools/SDK(For instance Unity), needs to learn new tools; maybe language too, and then deployment of an app for the final result to feel it in a real.</p>
<p><strong>A-Frame takes initiative to remove all these obstacles and provides the web-based framework that the majority of the developer know; HTML &amp; JAVASCRIPT</strong> </p>
<p><a target="_blank" href="https://aframe.io/">A-Frame</a> is built upon <a target="_blank" href="https://threejs.org/">Three.js</a>. Three.js is a JavaScript library which deals with 3D objects and animation using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a>. <br />
In a simple term, A-Frame provides top-level abreaction based on WebGL language and gives an API to build web-based VR applications.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637228494991/QAYNkt8Uo.png" alt="stack.png" /></p>
<p>One of the important feature: <a target="_blank" href="https://github.com/aframevr/aframe#features">Declarative HTML</a></p>
<blockquote>
<p>❤️  HTML is easy to read and copy-and-paste. Since A-Frame can be used from HTML, A-Frame is accessible to everyone: web developers, VR enthusiasts, educators, artists, makers, kids.</p>
</blockquote>
<p>Literally, you can just write couple of html lines and feel proud on your self 😏. <br /></p>
<h3 id="heading-by-using-aframe">By using Aframe</h3>
<iframe height="305" style="width:100%" src="https://codepen.io/priyankatgit/embed/PoKVmgW?default-tab=html%2Cresult">
  See the Pen <a href="https://codepen.io/priyankatgit/pen/PoKVmgW">
  AFrame - First Example</a> by Priyank (<a href="https://codepen.io/priyankatgit">@priyankatgit</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<h3 id="heading-almost-same-thing-but-by-using-threejs">Almost same thing but by using Threejs</h3>
<iframe height="556" style="width:100%" src="https://codepen.io/priyankatgit/embed/eYExWQL?default-tab=js%2Cresult">
  See the Pen <a href="https://codepen.io/priyankatgit/pen/eYExWQL">
  Untitled</a> by Priyank (<a href="https://codepen.io/priyankatgit">@priyankatgit</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<p>A-Frame is not the replacement of Threejs but it provides quick setup and abstraction to build VR apps.
<br />
ThreeJS is the generalized framework that is used to develop 3D objects and animation.</p>
<h3 id="heading-primitives">Primitives</h3>
<p>Primitives are the predefined components by the A-Frame such as box, circle, sky, cylinder, etc... That makes it super easy to do some exciting stuff even for the novice developer in this domain. <br />
If you want to render a box at some position then put it below primitive and there you go! </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a-box</span>  <span class="hljs-attr">position</span>=<span class="hljs-string">"-1 1.5 -5"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#00ff00"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a-box</span>&gt;</span>
</code></pre>
<h3 id="heading-lets-see-under-the-hood-action">Let's see under the hood action</h3>
<p>But wait, before moving to the custom primitive, we still need to check one more thing; <strong>Component</strong>. <br />
A component is a reusable piece of an element. A-frame provides <strong>registerComponent</strong> API to create it and exposes several events to handle objects dynamically.</p>
<pre><code class="lang-javascript">AFRAME.registerComponent(<span class="hljs-string">'foo'</span>, {
  <span class="hljs-attr">schema</span>: {}, <span class="hljs-comment">// Used to defined properties for the component</span>
  <span class="hljs-attr">init</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}, <span class="hljs-comment">// Called once when the component is initialized. Used to set up initial state and instantiate variables.</span>
  <span class="hljs-attr">update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}, <span class="hljs-comment">// Called both when the component is initialized and whenever any of the component’s properties is updated </span>
  <span class="hljs-attr">tick</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}, <span class="hljs-comment">// Called continuously(Render loop) and where all magic animation is of object is done.</span>
  <span class="hljs-attr">remove</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}, <span class="hljs-comment">// Called whenever the component is detached from the entity</span>
  <span class="hljs-attr">pause</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}, <span class="hljs-comment">// Called when the entity or scene pauses</span>
  <span class="hljs-attr">play</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{} <span class="hljs-comment">// Called once when the component is initialized and is called when the entity or scene resumes.</span>
});
</code></pre>
<p>Check out an example of the custom component "<strong>animate-circle</strong>".
<code>tick</code> method in a component is called 90 times per second and radius is managed at a certain point to the up and down.<br />
Schema is passed as a key-pair value separated by a semicolon in the HTML.</p>
<iframe height="468" style="width:100%" src="https://codepen.io/priyankatgit/embed/ExvMPaP?default-tab=html%2Cresult">
  See the Pen <a href="https://codepen.io/priyankatgit/pen/ExvMPaP">
  Aframe-Register Component</a> by Priyank (<a href="https://codepen.io/priyankatgit">@priyankatgit</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<h3 id="heading-a-entity">a-entity</h3>
<p>A component can be attached to the entity(<strong>a-entity</strong>). An entity is like a <code>&lt;div&gt;</code> in A-frame and without attaching a component to it, it's just like an empty <code>&lt;div&gt;</code>. </p>
<h3 id="heading-finally-custom-primitives">Finally, Custom Primitives</h3>
<p>In the previous example, a custom component was made and it was added to the <code>a-entity</code> whereas if we define primitives, it can be used directly as an HTML tag(<code>&lt;a-animate-cirlce&gt;</code>) and schema value can be passed as an individual attribute. <br />
Primitives can consider as syntactic sugar which is more readable to the newcomers.</p>
<iframe height="444" style="width:100%" src="https://codepen.io/priyankatgit/embed/eYEXdPd?default-tab=html%2Cresult">
  See the Pen <a href="https://codepen.io/priyankatgit/pen/eYEXdPd">
  AFrame Premitive</a> by Priyank (<a href="https://codepen.io/priyankatgit">@priyankatgit</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<h3 id="heading-key-points-to-focus-on-first-if-youre-relatively-new">Key points to focus on first if you're relatively new</h3>
<h4 id="heading-related-to-the-placement-of-an-object">Related to the placement of an object</h4>
<ul>
<li><a target="_blank" href="https://aframe.io/docs/1.2.0/primitives/a-camera.html#attributes">Camera</a>: It is used to control the field of view(FOV) that is on the screen. Using the different properties view area(viewport) of the screen can be adjusted.</li>
<li><a target="_blank" href="https://aframe.io/docs/1.2.0/components/position.html#value">Position</a>: Used to define the placement of the component in 3D space. X, Y, and Z coordinates manage the arrangement of the objects in the scene.<br /> </li>
<li><a target="_blank" href="https://aframe.io/docs/1.2.0/components/rotation.html#value">Rotation</a>: Used to define the orientation of an object. It takes the value in degree for all three axes; X, Y, and Z. </li>
<li><a target="_blank" href="https://aframe.io/docs/1.2.0/introduction/javascript-events-dom-apis.html">JavaScript, Events, DOM APIs</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Realtime Drawing by using WebSocket and FabricJS]]></title><description><![CDATA[By using Channel and FebricJS, I've made a real-time drawing sample.

Looks cool, isn't it? 
You can find complete implemented example at 
github/priyankatgit/realtime_draw_websocket
FebricJS

Fabric.js is a powerful and simple Javascript HTML5 canva...]]></description><link>https://priyankpatel.dev/realtime-drawing-by-using-websocket-and-fabricjs</link><guid isPermaLink="true">https://priyankpatel.dev/realtime-drawing-by-using-websocket-and-fabricjs</guid><category><![CDATA[websockets]]></category><category><![CDATA[Python]]></category><category><![CDATA[Django]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[canvas]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Sat, 23 Oct 2021 03:40:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634560470120/95cS5mWco.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>By using Channel and FebricJS, I've made a real-time drawing sample.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634959146544/unVNGx2t8.gif" alt="screencast 2021-10-23 08-43-16.gif" /></p>
<p>Looks cool, isn't it? 
You can find complete implemented example at 
<a target="_blank" href="https://github.com/priyankatgit/realtime_draw_websocket">github/priyankatgit/realtime_draw_websocket</a></p>
<h3 id="heading-febricjshttpfabricjscom"><a target="_blank" href="http://fabricjs.com/">FebricJS</a></h3>
<blockquote>
<p><a target="_blank" href="https://www.nostalgia.dev/fabricjs-made-canvas-easy-as-pie">Fabric.js</a> is a powerful and simple Javascript HTML5 canvas library· Fabric provides interactive object model on top of canvas element </p>
</blockquote>
<h2 id="heading-what-is-websockethttpswwwgeeksforgeeksorgwhat-is-web-socket-and-how-it-is-different-from-the-http"><a target="_blank" href="https://www.geeksforgeeks.org/what-is-web-socket-and-how-it-is-different-from-the-http/">What is WebSocket?</a></h2>
<blockquote>
<p>WebSocket: WebSocket is bidirectional, a full-duplex protocol that is used in the same scenario of client-server communication, unlike HTTP it starts from ws:// or wss://. It is a stateful protocol, which means the connection between client and server will keep alive until it is terminated by either party (client or server). after closing the connection by either of the client and server, the connection is terminated from both the end. </p>
</blockquote>
<p><a target="_blank" href="https://www.geeksforgeeks.org/what-is-web-socket-and-how-it-is-different-from-the-http/">Check this reference</a> to know the difference between HTTP and WebSocket in detail.</p>
<p>For the WebSocket implementation, we need a client-server architecture and I'm using the Django web framework to establish full-duplex communication channels.</p>
<p><a target="_blank" href="https://channels.readthedocs.io/en/stable/introduction.html">Channel</a> is the python package that extends Django asynchronous requests and gives out-of-the-box functionality to handle long-lived connections.</p>
<p>So, before diving further let me divide the channel into three simple steps to establish a socket connection.</p>
<ol>
<li>Routing setup - It's similar to Django URL configuration</li>
<li>Defining consumer - Where business logic lives </li>
<li>Setup channel Layer - Communication bridge across different instances </li>
</ol>
<h3 id="heading-1-http-and-websocket-routing">1. HTTP and WebSocket routing</h3>
<p>In a simple term, we need to first assign a job to handle regular HTTP requests to Django ASGI's application and Webscoket connection to the channel handler.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.core.asgi <span class="hljs-keyword">import</span> get_asgi_application

application = ProtocolTypeRouter({
    <span class="hljs-string">"http"</span>: get_asgi_application(),
    <span class="hljs-string">"websocket"</span>: AuthMiddlewareStack(
        URLRouter(
            draw.routing.websocket_urlpatterns
        )
    ),
})
</code></pre>
<pre><code class="lang-python">websocket_urlpatterns = [
    re_path(<span class="hljs-string">r'ws/draw/(?P&lt;room_name&gt;\w+)/$'</span>, consumers.DrawConsumer.as_asgi()),
]
</code></pre>
<p>URLRouter just contains the list of URL patterns that are mapped to the consumers. You can compare the consumer to the Django view.</p>
<h3 id="heading-2-define-consumer">2. Define consumer</h3>
<p>The consumer is just a list of the derived function from the WebsocketConsumer or AsyncWebsocketConsumer. These functions are called automatically when the event happens.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyConsumer</span>(<span class="hljs-params">AsyncWebsocketConsumer</span>):</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect</span>(<span class="hljs-params">self</span>):</span>
        self.room_name = self.scope[<span class="hljs-string">'url_route'</span>][<span class="hljs-string">'kwargs'</span>][<span class="hljs-string">'room_name'</span>]

        // Join the group
        <span class="hljs-keyword">await</span> self.channel_layer.group_add(
            self.room_name,
            self.channel_name
        )

        <span class="hljs-keyword">await</span> self.accept()

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">disconnect</span>(<span class="hljs-params">self, close_code</span>):</span>
        <span class="hljs-comment"># Exit from the group</span>
        <span class="hljs-keyword">await</span> self.channel_layer.group_discard(
            self.room_name,
            self.channel_name
        )

   // Receive message <span class="hljs-keyword">from</span> WebSocket
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">receive</span>(<span class="hljs-params">self, msg</span>):</span>

        // Send message to all member of group
        <span class="hljs-keyword">await</span> self.channel_layer.group_send(
            self.room_name,
            {
                <span class="hljs-string">'type'</span>: <span class="hljs-string">'foo'</span>,
                <span class="hljs-string">'message'</span>: msg
            }
        )

    // Receive the delegated message
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">foo</span>(<span class="hljs-params">self, event</span>):</span>
        <span class="hljs-keyword">pass</span>
</code></pre>
<h4 id="heading-connect-event">Connect Event</h4>
<p>Connect event is called when a socket connection is established without an error and every connection is given to a unique random name and that value is assigned to<code>channel_name</code>.</p>
<p><code>self.room_name</code> is a group name and by using <code>group_add</code> API, we can make a group that has multiple connection(channel_name) details.</p>
<h4 id="heading-receive-event">Receive Event</h4>
<p>When any message is posted to a particular group, this event is triggered. We can use <code>group_send</code> API further and the same message can be delivered to all members using the group name. 
In this example, the group name is stored in the <code>self.room_name</code> variable.</p>
<h4 id="heading-disconnect-event">Disconnect Event</h4>
<p>This event is called when a connection is dropped either by the client or by the server.</p>
<h3 id="heading-3-define-channel-layer">3. Define channel layer</h3>
<p>The Channel layer is used to persist messages which are passed between different instances. 
Redis is used as a message broker in the backend and it is recommended to use in Production. It is required to install <code>channels_redis</code> package for the Redis channel layer.</p>
<p>However, <a target="_blank" href="https://channels.readthedocs.io/en/latest/topics/channel_layers.html#in-memory-channel-layer">In-Memory Channel Layer</a> can also be used in the development mode.</p>
<pre><code class="lang-python">CHANNEL_LAYERS = {
    <span class="hljs-string">'default'</span>: {
        <span class="hljs-string">'BACKEND'</span>: <span class="hljs-string">'channels_redis.core.RedisChannelLayer'</span>,
        <span class="hljs-string">'CONFIG'</span>: {
            <span class="hljs-string">"hosts"</span>: [(<span class="hljs-string">'localhost'</span>, <span class="hljs-number">6379</span>)],
        },
    },
}
</code></pre>
<h3 id="heading-let-move-to-the-client-side">Let move to the client-side</h3>
<p>Once server configuration is done, we can initiate Websocket connection from the browser as follow:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> socketConnection = <span class="hljs-keyword">new</span> WebSocket(
    <span class="hljs-string">"ws://"</span> + <span class="hljs-built_in">window</span>.location.host + <span class="hljs-string">"/ws/draw/free_draw/"</span>
 );
</code></pre>
<p>Notice that <code>/ws/draw/free_draw/</code> is matched to the pattern which is defined in the 
URL pattern list where <code>free_draw</code> is group name in which everybody else will be joined.</p>
<p>onmessage event will be triggered if anybody will send the message in the "free_draw" group.</p>
<pre><code class="lang-javascript">socketConnection.onmessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">e</span>) </span>{ }
</code></pre>
<p>Send API can be used to post a message to all joined members to the group "free_draw"</p>
<pre><code class="lang-javascript">socketConnection.send();
</code></pre>
]]></content:encoded></item><item><title><![CDATA[NSQ - Things that nobody will tell you]]></title><description><![CDATA[This article requires a general understanding of the message queue system. If you're not familiar with that concept, I recommend you understand the concept first.
Nowadays companies promote the microservice based architecture for the enterprise level...]]></description><link>https://priyankpatel.dev/nsq-things-that-nobody-will-tell-you</link><guid isPermaLink="true">https://priyankpatel.dev/nsq-things-that-nobody-will-tell-you</guid><category><![CDATA[Microservices]]></category><category><![CDATA[message queue]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[messaging]]></category><category><![CDATA[realtime]]></category><dc:creator><![CDATA[Priyank Patel]]></dc:creator><pubDate>Wed, 13 Oct 2021 11:45:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634111507579/ZdAJHgXah.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article requires a general understanding of the message queue system. If you're not familiar with that concept, I recommend you understand the concept first.</p>
<p>Nowadays companies promote the microservice based architecture for the enterprise level projects and message queue service is the fundamental component to achieve that. </p>
<p><strong>Microservice</strong> is nothing else but the division of a big project into the smaller applications based on their work scope yet connected to each other which shares essential information from one to another app to move forward the workflow of the system.</p>
<h3 id="so-how-nsqhttpsnsqio-works">So how <a target="_blank" href="https://nsq.io/">NSQ</a> works?</h3>
<p>Don't worry, I will not flood this article with the same things which have already been written many times over the web. Go through the given below articles to have more insight about NSQ.</p>
<ul>
<li>https://segment.com/blog/scaling-nsq/</li>
<li>https://dev.to/vguleaev/nsq-tutorial-build-a-simple-message-queue-using-nsq-43eh</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634111673793/uto0TkFLd.gif" alt="nsq.gif" /></p>
<p>That's right, now you've knowledge how NSQ does its job but in <strong>production work</strong> the most important aspect is to handle messages which consumer(subscriber) is not able to process, mostly <em>due to the failure of business logic while processing the message.</em> </p>
<p>NSQ supports many languages to process messages at <a target="_blank" href="https://nsq.io/clients/client_libraries.html">client side</a>. <br />
Let's take a looks at <a target="_blank" href="https://github.com/dudleycarr/nsqjs">JavaScript</a> implementation </p>
<h3 id="without-failure-handling">Without failure handling</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> nsq = <span class="hljs-built_in">require</span>(<span class="hljs-string">'nsqjs'</span>)

<span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> nsq.Reader(<span class="hljs-string">'sample_topic'</span>, <span class="hljs-string">'test_channel'</span>, {
  <span class="hljs-attr">lookupdHTTPAddresses</span>: <span class="hljs-string">'127.0.0.1:4161'</span>
})

reader.connect()

reader.on(<span class="hljs-string">'message'</span>, <span class="hljs-function"><span class="hljs-params">msg</span> =&gt;</span> {
  <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Business logic to process message</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Received message [%s]: %s'</span>, msg.id, msg.body.toString())
  msg.finish()
})
</code></pre>
<p>Message considered as processed once <code>msg.finish()</code> is called inside the <code>Reader.MESSAGE</code> event. If the <code>finish()</code> method is not called then the nsq client add the message in queue again subsequently after some delay until the message is not processed successfully. </p>
<p>NSQ client decides to requeue the message based on the <code>maxAttempts</code> configuration, after the max attempts, the message is declared as a dead and marked as finished automatically; and that's where we have to log down dead message to handle it manually.</p>
<blockquote>
<p><a target="_blank" href="https://github.com/dudleycarr/nsqjs#usage">maxAttempts: 0</a></p>
<p>The number of times a given message will be attempted (given to MESSAGE handler) before it will be handed to the DISCARD handler and then automatically finished. 0 means that there is no limit. If no DISCARD handler is specified and maxAttempts &gt; 0, then the message will be finished automatically when the number of attempts has been exhausted.</p>
</blockquote>
<h3 id="with-failure-handling">With failure handling</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> nsq = <span class="hljs-built_in">require</span>(<span class="hljs-string">"nsqjs"</span>);

<span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> nsq.Reader(<span class="hljs-string">"chat"</span>, <span class="hljs-string">"chat"</span>, {
  <span class="hljs-attr">lookupdHTTPAddresses</span>: <span class="hljs-string">"127.0.0.1:4161"</span>,
});

reader.connect();

reader.on(<span class="hljs-string">"message"</span>, <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> isProcessed = processMessage(msg);
  <span class="hljs-keyword">if</span>(isProcessed) {
    msg.finish();
  }
});

reader.on(<span class="hljs-string">"discard"</span>, <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
  <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Log dead messages in the Database or File to handle it manually.</span>
  msg.finish();
});

<span class="hljs-keyword">const</span> processMessage= <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
   <span class="hljs-keyword">try</span>{
     <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Business logic to process message</span>
     <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Received message [%s]: %s"</span>, msg.id, msg.body.toString());

     <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>

   }<span class="hljs-keyword">catch</span>(error) {
     <span class="hljs-built_in">console</span>.error(error)
     <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
   }
}
</code></pre>
<p>Consider <code>processMessage</code> is the function where the app's logic resides to take action on a message. If everything goes ok, we mark the message as finished by calling the <code>finish</code> method else the message will be requeued constantly until max attempt is reached. </p>
<p>After the max retry, <code>Reader.DISCARD</code> is called, where dead message detail can be written to the file or database to handle it manually. </p>
<p>As I said earlier, nsq has different clients to process messages and different clients may have different ways to handle dead messages. <br />
For instance, <a target="_blank" href="https://pynsq.readthedocs.io/en/latest/">pynsq</a> client is for python and it has <a target="_blank" href="https://pynsq.readthedocs.io/en/latest/reader.html#nsq.Reader.giving_up"><code>giving_up()</code></a> API to handle dead messages.</p>
<h3 id="bonus">Bonus</h3>
<p>There are many distributed open source messaging systems and Philip Feng has described most of them in his <a target="_blank" href="https://medium.com/@philipfeng/modern-open-source-messaging-apache-kafka-rabbitmq-nats-pulsar-and-nsq-ca3bf7422db5">article</a></p>
<p>Credits: <br />
Banner image <a target="_blank" href="https://pixabay.com/photos/queue-playmobil-to-wave-655820/">siskav</a>, nsq gif <a target="_blank" href="https://nsq.io/overview/design.html">nsq</a> <br />
NSQ Article reference: <a target="_blank" href="https://segment.com/blog/scaling-nsq/">Calvin French-Owen</a>,  <a target="_blank" href="https://dev.to/vguleaev/nsq-tutorial-build-a-simple-message-queue-using-nsq-43eh">Vladislav Guleaev</a>, <a target="_blank" href="https://medium.com/@philipfeng/modern-open-source-messaging-apache-kafka-rabbitmq-nats-pulsar-and-nsq-ca3bf7422db5">Philip Feng Ph.D</a></p>
]]></content:encoded></item></channel></rss>