<?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[The Trojan (Apoorv Tyagi)]]></title><description><![CDATA[The Senior Engineer’s Playbook: Real-World Case Studies in Computer Science and Software Design.]]></description><link>https://apoorvtyagi.tech</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1768144730193/8ff6e18b-57a5-4958-bb12-8e6fc3fe7469.png</url><title>The Trojan (Apoorv Tyagi)</title><link>https://apoorvtyagi.tech</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 17:38:48 GMT</lastBuildDate><atom:link href="https://apoorvtyagi.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[What is Jib? A Complete Guide to Java Containerization Without Dockerfiles]]></title><description><![CDATA[Introduction
When I joined PayPay, one of the first things I tried to understand was how our services were containerized.
A common exercise when joining a new backend team is to look at the Dockerfile]]></description><link>https://apoorvtyagi.tech/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles</link><guid isPermaLink="true">https://apoorvtyagi.tech/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles</guid><category><![CDATA[General Programming]]></category><category><![CDATA[Docker]]></category><category><![CDATA[containerization]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Tue, 10 Mar 2026 14:27:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5f40aec3cce6c969208c9d45/cae20999-e285-4676-b110-349cfec4cfde.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Introduction</strong></h2>
<p>When I joined PayPay, one of the first things I tried to understand was how our services were containerized.</p>
<p>A common exercise when joining a new backend team is to look at the Dockerfiles used across services as they often reveal interesting patterns:</p>
<ul>
<li><p>Which base images are used</p>
</li>
<li><p>Whether the builds are optimized</p>
</li>
<li><p>If multi-stage builds are implemented</p>
</li>
<li><p>Opportunities for reducing image size or improving caching</p>
</li>
</ul>
<p>So naturally, I went looking for the Dockerfile.</p>
<p>But to my surprise… I couldn't find one.</p>
<p>After digging a bit deeper, I realized something interesting. The project wasn’t using a Dockerfile at all. Instead, it was using <a href="https://github.com/GoogleContainerTools/jib">Jib</a>.</p>
<hr />
<h2>📦 Enter Jib</h2>
<p>Imagine shipping a Java microservice where changing a single line of code doesn’t force your CI pipeline to rebuild a massive container image.</p>
<p>That’s exactly what Jib enables.</p>
<p>Jib is an open-source container image builder for Java applications that:</p>
<ul>
<li><p><strong>Eliminates the need for a Dockerfile</strong></p>
</li>
<li><p><strong>Does not require a Docker daemon</strong></p>
</li>
<li><p><strong>Integrates directly with Maven and Gradle</strong></p>
</li>
</ul>
<p>Instead of packaging your application as a single fat layer, Jib understands Java project structure and splits your application into optimized layers:</p>
<ul>
<li><p>Runtime (base image)</p>
</li>
<li><p>Dependencies</p>
</li>
<li><p>Resources</p>
</li>
<li><p>Application classes</p>
</li>
</ul>
<p>Because of this layered structure, when you change only your application code, only the top layer is rebuilt and pushed.</p>
<p>The result?</p>
<ul>
<li><p>⚡ Faster builds</p>
</li>
<li><p>🧱 Better caching</p>
</li>
<li><p>🚀 Simpler CI pipelines</p>
</li>
<li><p>🔧 Less Dockerfile maintenance</p>
</li>
</ul>
<p>In this post, we'll explore how Jib works, when to use it, and how it compares to traditional Dockerfiles.</p>
<hr />
<h1>🚀 What's Jib?</h1>
<p>If you build Java applications and ship containers, you’ve probably written Dockerfiles like this:</p>
<pre><code class="language-dockerfile">FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
</code></pre>
<p>It works.</p>
<p>But it’s not optimized for Java.</p>
<p>This is where Jib changes the game.</p>
<hr />
<h1>🧱 The Problem With Traditional Docker Builds</h1>
<p>Before Jib, containerizing Java apps required:</p>
<ul>
<li><p>Writing and maintaining Dockerfiles</p>
</li>
<li><p>Installing Docker everywhere (including CI)</p>
</li>
<li><p>Packaging fat JARs</p>
</li>
<li><p>Rebuilding full images for small code changes</p>
</li>
<li><p>Manually optimizing layers</p>
</li>
</ul>
<p>Even a small code change could invalidate caching and rebuild everything.</p>
<p>That’s inefficient.</p>
<hr />
<h1>🧠 How Jib Works</h1>
<p>Jib builds container images by splitting your app into logical layers:</p>
<ol>
<li><p>Base Image (JRE)</p>
</li>
<li><p>Dependencies</p>
</li>
<li><p>Resources</p>
</li>
<li><p>Application classes</p>
</li>
</ol>
<p>This means:</p>
<ul>
<li><p>If dependencies don’t change → layer reused</p>
</li>
<li><p>If only code changes → only top layer rebuilt</p>
</li>
</ul>
<p>This drastically improves CI speed.</p>
<hr />
<h1>🛠️ Getting Started with Jib</h1>
<h2>Maven Setup</h2>
<p>Add this to your <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;plugin&gt;
  &lt;groupId&gt;com.google.cloud.tools&lt;/groupId&gt;
  &lt;artifactId&gt;jib-maven-plugin&lt;/artifactId&gt;
  &lt;version&gt;3.4.0&lt;/version&gt;
  &lt;configuration&gt;
    &lt;to&gt;
      &lt;image&gt;ghcr.io/yourorg/yourapp&lt;/image&gt;
    &lt;/to&gt;
  &lt;/configuration&gt;
&lt;/plugin&gt;
</code></pre>
<p>Build &amp; push:</p>
<pre><code class="language-shell">mvn compile jib:build
</code></pre>
<hr />
<h2>Gradle Setup</h2>
<pre><code class="language-kotlin">plugins {
  id("com.google.cloud.tools.jib") version "3.4.0"
}

jib {
  to {
    image = "ghcr.io/yourorg/yourapp"
  }
}
</code></pre>
<p>Build:</p>
<pre><code class="language-shell">./gradlew jib
</code></pre>
<hr />
<h1>⚔️ Dockerfile vs Jib - Which Is Better?</h1>
<p>This is the real question.</p>
<p>The answer depends on some of the use cases.</p>
<h2>✅ When Jib Is Better</h2>
<h3>1. Standard Java Microservices</h3>
<ul>
<li><p>Spring Boot</p>
</li>
<li><p>Micronaut</p>
</li>
<li><p>Quarkus</p>
</li>
<li><p>Plain Maven/Gradle apps</p>
</li>
</ul>
<p>Jib integrates directly with your build system.</p>
<h3>2. Faster CI/CD Pipelines</h3>
<p>Jib:</p>
<ul>
<li><p>Does not require a Docker daemon</p>
</li>
<li><p>Builds incremental layers</p>
</li>
<li><p>Pushes smaller diffs</p>
</li>
<li><p>Produces reproducible builds</p>
</li>
</ul>
<p>If CI time matters, Jib usually wins.</p>
<h3>3. Developer Simplicity</h3>
<p>No Dockerfile. No manual layering. Less DevOps friction.</p>
<hr />
<h2>🏗️ When Dockerfile Is Better</h2>
<h3>1. OS-Level Customization</h3>
<p>If you need:</p>
<ul>
<li><p><code>apt-get install</code></p>
</li>
<li><p>Native libraries</p>
</li>
<li><p>Custom shell scripts</p>
</li>
</ul>
<p>Jib does not support arbitrary RUN commands.</p>
<p>Dockerfile wins here.</p>
<h3>2. Polyglot Applications</h3>
<p>If your container includes:</p>
<ul>
<li><p>Node + Java</p>
</li>
<li><p>Python + Java</p>
</li>
<li><p>Multiple build tools</p>
</li>
<li><p>Custom entrypoints</p>
</li>
</ul>
<p>Dockerfile provides full flexibility.</p>
<h3>3. Complex Multi-Stage Builds</h3>
<p>Example:</p>
<ul>
<li><p>Compile native binaries</p>
</li>
<li><p>Build frontend assets</p>
</li>
<li><p>Run security scans during build</p>
</li>
<li><p>Copy artifacts between stages</p>
</li>
</ul>
<p>Dockerfile is more powerful here.</p>
<h1>📊 Side-by-Side Comparison</h1>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Jib</th>
<th>Dockerfile</th>
</tr>
</thead>
<tbody><tr>
<td>Requires Docker daemon</td>
<td>❌ No</td>
<td>✅ Yes</td>
</tr>
<tr>
<td>Requires Dockerfile</td>
<td>❌ No</td>
<td>✅ Yes</td>
</tr>
<tr>
<td>OS Customization</td>
<td>❌ Limited</td>
<td>✅ Full</td>
</tr>
<tr>
<td>Java Layer Optimization</td>
<td>✅ Automatic</td>
<td>❌ Manual</td>
</tr>
<tr>
<td>CI/CD Simplicity</td>
<td>✅ High</td>
<td>⚠️ Medium</td>
</tr>
<tr>
<td>Multi-language builds</td>
<td>❌ No</td>
<td>✅ Yes</td>
</tr>
<tr>
<td>Learning Curve</td>
<td>Low</td>
<td>Medium</td>
</tr>
</tbody></table>
<hr />
<h1>🎯 Real-World Scenarios</h1>
<h2>Scenario A: 20 Spring Boot Microservices</h2>
<ul>
<li><p>Kubernetes</p>
</li>
<li><p>GitHub Actions</p>
</li>
<li><p>CI cost matters</p>
</li>
</ul>
<p>👉 Jib is usually the better choice.</p>
<h2>Scenario B: Enterprise App With Native Dependencies</h2>
<ul>
<li><p>Custom Alpine base image</p>
</li>
<li><p>OS packages</p>
</li>
<li><p>Hardening scripts</p>
</li>
<li><p>Multi-stage builds</p>
</li>
</ul>
<p>👉 Dockerfile is better.</p>
<h2>Scenario C: Small Startup Team</h2>
<ul>
<li><p>Java-only stack</p>
</li>
<li><p>No DevOps team</p>
</li>
<li><p>Want fast pipelines</p>
</li>
</ul>
<p>👉 Jib simplifies everything.</p>
<hr />
<h1>🔬 Performance Insight</h1>
<p>Because Jib separates dependencies and classes:</p>
<ul>
<li><p>Code-only changes rebuild in seconds</p>
</li>
<li><p>Docker layer cache invalidation is minimized</p>
</li>
<li><p>CI builds are more predictable</p>
</li>
</ul>
<p>In large microservice ecosystems, this adds up significantly.</p>
<hr />
<h1>🚀 Closing Thoughts</h1>
<p>Jib is optimized for:</p>
<blockquote>
<p>Java developer productivity.</p>
</blockquote>
<p>Dockerfile is optimized for:</p>
<blockquote>
<p>Infrastructure control.</p>
</blockquote>
<p>If you build modern Java microservices → Start with Jib.</p>
<p>If you need deep OS-level control → Use Dockerfile.</p>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">Containerization doesn’t have to be complicated. If your stack is Java-centric and you value speed, reproducibility, and developer autonomy, then Jib is one of the smart tools you can adopt today.</mark></p>
]]></content:encoded></item><item><title><![CDATA[Kafka Consumer Container Restarts in Kubernetes: A Production Case Study]]></title><description><![CDATA[Background
At my current org, I got introduced to a very fun tool, PagerDuty - because who doesn't love being woken up at 3:31 AM?
A similar alert flared up for one of our merchant services. While it mercifully avoided the 3 AM slot, the diagnostic w...]]></description><link>https://apoorvtyagi.tech/kafka-consumer-container-restarts-in-kubernetes-a-production-case-study</link><guid isPermaLink="true">https://apoorvtyagi.tech/kafka-consumer-container-restarts-in-kubernetes-a-production-case-study</guid><category><![CDATA[General Programming]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[kafka]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Tue, 10 Feb 2026 12:02:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769363448790/9021ae13-5e0d-4723-af09-ab6570646cb2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-background">Background</h2>
<p>At my current org, I got introduced to a very fun tool, PagerDuty - because who doesn't love being woken up at 3:31 AM?</p>
<p>A similar alert flared up for one of our merchant services. While it mercifully avoided the 3 AM slot, the diagnostic was clear: The containers running were restarting. There’s no bad deployment, just a burst of events on a Kafka topic and a trail of exit code 137.</p>
<p>This is the story of how we tracked down the memory issue in one of our core merchant services at PayPay that wasn't exactly a leak, but a partition mismatch, and a battle between Garbage Collectors.</p>
<hr />
<h2 id="heading-the-incident-when-bursts-turn-into-crashes">The Incident: When Bursts Turn Into Crashes</h2>
<p>It started with a Kafka topic.</p>
<p>This topic powers merchant payouts in Japan and, on average, processes around 3,500 messages per day. On paper, that volume sounds harmless. In reality, the traffic pattern was anything but smooth. Instead of being evenly distributed, most of those messages arrived in short, aggressive bursts.</p>
<p>And that’s when things began to fall apart.</p>
<p>Every time a burst hit, our merchant service pods would suddenly spike in memory usage. Within minutes, they would hiy their memory limit and get terminated by Kubernetes with an <strong>OOMKill</strong>.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769363435809/e054cc12-c9d6-43f6-beae-8a7895fe84fb.png" alt="Kubernetes pod restarts   Animated" class="image--center mx-auto" /></p>
</blockquote>
<h2 id="heading-the-investigation">The Investigation</h2>
<p>When we looked at the consumer topology, the first red flag was almost too obvious to ignore:</p>
<ul>
<li><p><strong>Kafka partitions:</strong> 6</p>
</li>
<li><p><strong>Active consumer pods:</strong> 10</p>
</li>
</ul>
<p>In Kafka, this setup has a very specific behavior. A single partition can be consumed by only one consumer within a consumer group. So with 6 partitions and 10 pods, <strong>4 pods were effectively idle</strong>, waiting on the sidelines.</p>
<p>Every burst of messages was being funneled into just 6 pods, concentrating the entire load on 60% of our fleet, while the remaining pods contributed nothing. Under normal traffic, this imbalance went unnoticed. But during bursts, those active pods suddenly did significantly more work than they were sized for.</p>
<p>That explained <em>where</em> the pressure was landing, but not <em>why</em> it was causing hard crashes.</p>
<p>To answer that, we moved to the next step: capturing a heap &amp; thread dump in our staging environment while simulating a <strong>5X production load</strong>. And that’s where things started getting really interesting.</p>
<h3 id="heading-the-zgc-struggle">The ZGC Struggle</h3>
<p>We were initially running the service on <a target="_blank" href="https://wiki.openjdk.org/spaces/zgc/pages/34668579/Main"><strong>ZGC</strong></a>.</p>
<p>On paper, ZGC is impressive - microsecond-level pause times and near-zero stop-the-world events. But what often gets missed is its biggest trade-off: <strong>ZGC needs a lot of breathing room</strong>. It relies heavily on having heap memoryto keep allocation and reclamation in balance.</p>
<p>When we profiled the system, the numbers told a worrying story. The old-generation worker alone had consumed over 584 seconds of CPU time. ZGC wasn’t idle - it was working relentlessly, trying to keep up with a flood of newly allocated objects.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769538073166/af11df31-7cc0-4341-b31f-7de1919bcc0d.png" alt="Thread dump" class="image--center mx-auto" /></p>
</blockquote>
<p>But it simply couldn’t reclaim memory fast enough.</p>
<p>The heap kept expanding, allocation pressure kept rising, and eventually the pod crossed its memory limit and was OOMKilled. Low pause times didn’t matter if the process couldn’t stay alive long enough to benefit from them.</p>
<h3 id="heading-the-substitute-g1gc">The Substitute: G1GC</h3>
<p>At this point, we decided to switch strategies and flipped the JVM to <a target="_blank" href="https://www.oracle.com/technical-resources/articles/java/g1gc.html">G1GC</a>, then reran the same load test.</p>
<p>The difference was immediate:</p>
<ul>
<li><p><strong>Memory usage:</strong> Stabilized under 1 GiB (previously went up all the way to 3 GiB)</p>
</li>
<li><p><strong>Pause times:</strong> Increased slightly to around 35 ms, still comfortably within our SLAs</p>
</li>
<li><p><strong>Stability:</strong> No crashes. No restarts.</p>
</li>
</ul>
<p><strong>G1GC traded a bit of pause time for predictable memory behavior</strong>, which turned out to be exactly what this workload needed. In a burst-heavy system, consistency beats theoretical best-case latency every single time.</p>
<h3 id="heading-the-side-quest-the-slack-notifier-leak">The Side-Quest: The Slack Notifier "Leak"</h3>
<p>While digging through the thread dumps, we found a "Red Herring." Our <code>SlackNotifier</code> class, which is responsible for sending failure alerts, was instantiating a new <code>OkHttpClient</code> for every single error notification.</p>
<p>Each <code>OkHttpClient</code> spins up its own connection pool and thread pool. In a high-error scenario, this could have quietly expanded into dozens, if not hundreds, of threads, steadily pushing the JVM toward thread exhaustion and memory pressure.</p>
<p>Interestingly, this wasn’t the direct cause of the production crashes. During the Kafka bursts, no errors were actually being emitted, which meant this code path wasn’t even executed. But left unfixed, it was a ticking time bomb waiting for the next incident.</p>
<p>The fix was straightforward: refactor the notifier to use a single, shared <code>OkHttpClient</code> singleton, ensuring controlled resource usage and predictable behavior.</p>
<p>Not the root cause, but a critical cleanup uncovered at exactly the right time.</p>
<h2 id="heading-final-fixes">Final Fixes</h2>
<p>To stabilize Merchant Finance, we didn’t just tweak application code—we <strong>re-aligned the infrastructure to match the workload it was actually handling.</strong></p>
<p>Here’s what we changed.</p>
<ol>
<li><h3 id="heading-memory-alignment">Memory Alignment</h3>
</li>
</ol>
<p>We set <code>memory.request</code> to match <code>memory.limit</code> at <strong>3 GiB</strong>.</p>
<p>This ensured the <strong>node reserved the full memory upfront</strong>, eliminating eviction pressure during bursts and preventing Kubernetes from stepping in with an OOMKill when memory usage spiked. [<a target="_blank" href="https://www.reddit.com/r/kubernetes/comments/182op5z/why_is_it_a_good_idea_to_set_pod_requests_equal/">A reddit thread worth exploring</a>]</p>
<ol start="2">
<li><h3 id="heading-partition-scaling">Partition Scaling</h3>
</li>
</ol>
<p>We scaled the Kafka topic from <strong>6 partitions to 10</strong>.</p>
<p>This change ensured that <strong>every merchant service pod became an active consumer</strong>, evenly distributing the workload instead of concentrating it on a subset of the fleet. Burst traffic stopped being a stress test for a few pods and became a shared responsibility across all of them.</p>
<ol start="3">
<li><h3 id="heading-the-gc-switch">The GC Switch</h3>
</li>
</ol>
<p>We officially moved this service to G1GC.</p>
<p>For this workload profile, we chose <strong>predictable memory behavior over ultra-low pause times</strong>. Slightly higher pauses were a small price to pay for stability under burst-heavy traffic.</p>
<ol start="4">
<li><h3 id="heading-cpu-buffering">CPU Buffering</h3>
</li>
</ol>
<p>We increased the CPU request from <strong>100 millicores to 500 millicores</strong>.</p>
<p>This wasn’t about average CPU usage; it was about headroom. During peak allocation and garbage collection cycles, G1GC needs consistent CPU availability to do its job efficiently. An under-provisioned CPU would only delay GC work and amplify memory pressure.</p>
<ol start="5">
<li><h3 id="heading-fixing-slacknotifier">Fixing <code>SlackNotifier</code></h3>
</li>
</ol>
<p>Finally, we refactored <code>SlackNotifier</code> to use a single shared <code>OkHttpClient</code> instance instead of creating a new one per notification.</p>
<p>It wasn’t the root cause, but it removed a hidden risk that could have turned a future incident into something far worse.</p>
<h2 id="heading-results">Results</h2>
<p>After applying the infrastructure and JVM changes, we reran the same burst-heavy load tests and monitored JVM, Kubernetes, and Kafka metrics.</p>
<p>The difference wasn’t subtle 👇</p>
<ol>
<li><h3 id="heading-jvm-behavior-zgc-vs-g1gc">JVM Behavior (ZGC v.s G1GC)</h3>
</li>
</ol>
<ul>
<li><p>GC pause <strong>frequency dropped significantly</strong></p>
</li>
<li><p>GC avg pause <strong>times increase</strong></p>
</li>
</ul>
<p>The change is clearly visible around <strong>12:00–12:10</strong>, which is when the GC and infrastructure updates were applied.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769537655545/444ced94-c3b4-43a1-948d-3e92d45c875e.png" alt="Comparison of JVM memory usage under high load showing ZGC heap growth leading to instability versus G1GC maintaining stable memory usage in a Kubernetes environment." class="image--center mx-auto" /></p>
<ol start="2">
<li><h3 id="heading-g1gc-under-load">G1GC Under Load</h3>
</li>
</ol>
<p>Switching away from ZGC did increase pause times, but well within acceptable limits.</p>
<ul>
<li><p><strong>Average GC pause:</strong> ~30–40 ms</p>
</li>
<li><p><strong>Consistency:</strong> Flat, predictable, no spikes</p>
</li>
<li><p><strong>Impact:</strong> No effect on SLAs</p>
</li>
</ul>
<p>This was an intentional trade-off. We gave up ultra-low pause times in exchange for a lower GC pause count and memory predictability.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769537466518/e42d3718-d568-4bb7-b503-bab52f57162f.png" alt="JVM garbage collection pause time and GC count metrics using G1GC under burst traffic, showing consistent pause times and predictable garbage collection behavior." class="image--center mx-auto" /></p>
<ol start="3">
<li><h3 id="heading-kubernetes-pods-stopped-restarting">Kubernetes Pods Stopped Restarting</h3>
</li>
</ol>
<p>From a platform perspective, this was the most important outcome.</p>
<ul>
<li><p><strong>Pod restarts:</strong> 0</p>
</li>
<li><p><strong>OOM events:</strong> None</p>
</li>
<li><p><strong>Memory usage:</strong> Stable across all pods</p>
</li>
<li><p><strong>CPU usage:</strong> Predictable, with sufficient headroom during GC cycles</p>
</li>
</ul>
<p>Container-level metrics after the fixes - memory usage remains stable, CPU has sufficient headroom, and pod restarts drop to zero.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769537627414/143dcbf3-0fe1-4984-9011-056c07dc3365.png" alt="Kubernetes pod metrics after infrastructure fixes, showing stable memory usage, controlled CPU consumption, zero pod restarts, and no OOMKill events under load." class="image--center mx-auto" /></p>
<ol start="4">
<li><h3 id="heading-kafka-kept-up-with-bursts-without-errors">Kafka Kept Up With Bursts Without Errors</h3>
</li>
</ol>
<p>Finally, we looked at the Kafka side of the system.</p>
<ul>
<li><p><strong>Consumer lag:</strong> Spiked briefly during bursts, then drained smoothly</p>
</li>
<li><p><strong>Consumer latency (P95):</strong> Stable</p>
</li>
<li><p><strong>Errors:</strong> None observed</p>
</li>
<li><p><strong>Throughput:</strong> Fully sustained during burst windows</p>
</li>
</ul>
<p>Increasing the partition count ensured every pod actively participated in consumption, preventing load concentration and smoothing out processing during spikes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769537676738/9c79823d-bde1-4db8-8257-f24338b22cab.png" alt="Kafka consumer metrics during burst traffic including throughput, consumer lag, and P95 latency, demonstrating stable consumption and zero consumer errors." class="image--center mx-auto" /></p>
<p>Kafka consumer metrics during burst traffic. Lag increases temporarily but recovers quickly, with no errors and stable latency.</p>
<h2 id="heading-final-outcome">Final Outcome</h2>
<p>After all fixes were applied:</p>
<ul>
<li><p>✅ No pod restarts during burst traffic</p>
</li>
<li><p>✅ No OOMKills</p>
</li>
<li><p>✅ Predictable JVM behavior under load</p>
</li>
<li><p>✅ Kafka bursts handled without errors</p>
</li>
</ul>
<p>Resilience isn’t just about handling errors after they happen, it’s about understanding how your system behaves under load.</p>
<p>If you’re running JVM workloads on Kubernetes, it’s worth taking a hard look at both your garbage collector choice and your resource requests versus limits. These decisions don’t show their impact during steady state traffic, but they matter enormously when load arrives in bursts.</p>
<p>Sometimes, the “latest and greatest” option isn’t the right fit for every workload. Stability often comes from choosing the tool that behaves <em>predictably</em> under stress, not the one that looks best on paper.</p>
<p>In production, boring and predictable almost always win.</p>
]]></content:encoded></item><item><title><![CDATA[How we solved cache invalidation in Kubernetes with a headless service]]></title><description><![CDATA[⬅️ Background
At my previous organization, we were building a health platform, and one of the most critical, high-traffic components was our Lab test booking service. One of its core functions is to serve package details like inclusions, prices, and ...]]></description><link>https://apoorvtyagi.tech/how-we-solved-cache-invalidation-in-kubernetes-with-a-headless-service</link><guid isPermaLink="true">https://apoorvtyagi.tech/how-we-solved-cache-invalidation-in-kubernetes-with-a-headless-service</guid><category><![CDATA[General Programming]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Mon, 29 Dec 2025 05:45:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1766733918067/fe25c6da-b3a4-4b95-9de9-3491b8bec736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-background">⬅️ Background</h2>
<p>At my previous organization, we were building a health platform, and one of the most critical, high-traffic components was our <a target="_blank" href="https://www.bajajfinservhealth.in/lab-tests">Lab test booking service</a>. One of its core functions is to serve package details like inclusions, prices, and provider information for thousands of user requests daily.</p>
<p>The initial architecture was simple: every single request meant a new query to a database. As traffic scaled, our database struggled. Latency spiked, and CPU usage became a constant concern.</p>
<p>With mostly static data that rarely changes, the clear solution was to cache it. But the execution is where we got creative. This is the story of how we implemented a zero-cost, in-memory cache in our Node.js microservices and used a Kubernetes feature, “<a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/#headless-services"><strong>The</strong> <strong>Headless Service</strong></a><strong>”</strong> to handle distributed cache invalidation flawlessly.</p>
<hr />
<h2 id="heading-the-problem-fast-caching-amp-scalable-invalidation">🛑 The Problem: Fast Caching &amp; Scalable Invalidation</h2>
<p>We decided on <strong>in-memory caching</strong> using a library like <code>@nestjs/cache-manager</code> to slash DB load and boost response times. However, in a Kubernetes cluster, where our service runs across multiple, dynamic pods, this creates a major headache: <strong>Cache Inconsistency</strong>.</p>
<p>If an admin updates a package price in the MySQL database, only the single pod that handled the write sees the change immediately. The other pods are serving users stale data - consistency, gone.</p>
<p>Furthermore, Kubernetes pod IPs are temporary. They change during restarts, deployments, and scaling events. We couldn't rely on hardcoded lists. Our invalidation system needed a reliable way to discover every running pod at the exact moment of a data update.</p>
<p>We needed a broadcasting mechanism.</p>
<hr />
<h2 id="heading-the-solution-the-k8s-headless-service">🛠️ The Solution: The K8s Headless Service</h2>
<p>Our strategy was a hybrid approach: <strong>local caching for performance</strong>, and a <strong>targeted internal HTTP broadcast for invalidation</strong>.</p>
<h3 id="heading-step-1-headless-services-for-pod-discovery">Step 1: Headless Services for Pod Discovery</h3>
<p>This is the key to the whole solution. A standard Kubernetes service acts as a load balancer with a single Virtual IP. But a <strong>Headless Service</strong> is different. By setting <code>clusterIP: None</code> in the Service manifest (<code>.spec.clusterIP</code>), Kubernetes skips the load balancer and, crucially, <strong>returns a list of individual DNS A records for every active pod’s IP address</strong>.</p>
<p>Here is the simple(yet powerful) Headless Service manifest we deployed:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">booking-service-headless</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">clusterIP:</span> <span class="hljs-string">None</span>             <span class="hljs-comment"># THE TRICK: Makes it Headless</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">booking-service</span>
  <span class="hljs-attr">ports:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">targetPort:</span> <span class="hljs-number">3000</span>
</code></pre>
<p>Now, when we resolve <code>booking-service-headless.default.svc.cluster.local</code>, we get an array of all current, healthy pod IPs.</p>
<p>For visualization, here's a diagram of Headless Services in action:</p>
<p><img src="https://www.plural.sh/blog/content/images/2025/04/image-79.png" alt="Kubernetes Headless Service Explained" /></p>
<h3 id="heading-step-2-amp-3-broadcast-implementation">Step 2 &amp; 3: Broadcast Implementation</h3>
<p>In the next step, we added <code>kubectl</code> into our Docker image for API queries. This gives the pod the power to query the Kubernetes API directly.</p>
<p>To implement this safely, we followed the <a target="_blank" href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">Principle of Least Privilege</a>. We created a dedicated <code>ServiceAccount</code> for our booking service and bound it to a specific <code>Role</code> using RBAC (Role-Based Access Control). This Role was strictly limited: it only allowed the <code>list</code> and <code>get</code> operations on the <code>endpoints</code> resource within its own namespace. This ensures that even if a pod is compromised, an attacker cannot delete resources or view sensitive secrets.</p>
<p>Second, we created a simple, internal <code>/invalidate-cache</code> API endpoint on our booking service. When we hit this endpoint, it clears a specific cache key (passed in the request body) using the in-memory cache’s <code>del()</code> method.</p>
<p>When an admin update happens, and the data is written to MySQL, the pod that handles the write executes a bash script using <code>kubectl</code> and <code>curl</code>:</p>
<p>It uses <code>kubectl</code> to get the list of IPs from the Headless Service endpoints, then sends a <strong>direct HTTP POST request</strong> to the internal <code>/invalidate-cache</code> endpoint on <em>each pod</em>.</p>
<pre><code class="lang-javascript"># Executed by the Node.js process on update
pod_ips=$(kubectl get endpoints listing-headless-service -o jsonpath=<span class="hljs-string">'{.subsets[0].addresses[*].ip}'</span>)

<span class="hljs-keyword">for</span> ip <span class="hljs-keyword">in</span> $pod_ips; <span class="hljs-keyword">do</span>
   curl -X POST http:<span class="hljs-comment">//$ip:3000/v2/invalidate\</span>
       -H <span class="hljs-string">"Content-Type: application/json"</span> \
       -d <span class="hljs-string">'{"key": "package-123"}'</span> # Clears the specific key
done
</code></pre>
<p>This ensures the system is:</p>
<ul>
<li><p><strong>Dynamic:</strong> The IP list is fresh at invalidation time, handling upscaling, downscaling and restarts seamlessly.</p>
</li>
<li><p><strong>Targeted:</strong> We clear only the stale package key, maximizing cache retention.</p>
</li>
<li><p><strong>Cost-Effective:</strong> Zero new service bills.</p>
</li>
<li><p><strong>Reliability</strong>: Add curl retries and logging for failed broadcasts.</p>
</li>
</ul>
<blockquote>
<p>For those looking to keep their Docker images clean, you can avoid installing <code>kubectl</code> and <code>curl</code> entirely by using the official <code>@kubernetes/client-node</code> library. By using the library, your Node.js process can query the Kubernetes API directly from within the code. This makes the logic more testable, allows for better error handling, and removes the overhead of spawning shell processes. It turns your infrastructure logic into standard application code.</p>
</blockquote>
<hr />
<h2 id="heading-production-results-and-takeaways">📈 Production Results and Takeaways</h2>
<p>Post-rollout, our MySQL database load has consistently remained low, and our cache hit rate has remained above 95%+. We have had zero reported incidents of users seeing stale package data. The Headless Service trick proved robust, even during high-traffic deployments.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*HhCIXRjVZnUn2QXrNJEUlQ.png" alt="CPU Graph" /></p>
<p>This solution proves that sometimes, the most elegant and cheapest solution isn't an expensive managed service, but a creative application of your existing tools. It’s about being smart with your infrastructure, not just throwing money at the problem.</p>
]]></content:encoded></item><item><title><![CDATA[Going Vernacular: Engineering Our Way to Process Multilingual Names]]></title><description><![CDATA[Introduction
At our current organization, earlier this year as we were looking at the errors at one of our signup API, we observed that nearly 5% of our requests were getting failed, all due to 400 BAD REQUEST errors, and the root cause was traced ba...]]></description><link>https://apoorvtyagi.tech/going-vernacular-engineering-our-way-to-process-multilingual-names</link><guid isPermaLink="true">https://apoorvtyagi.tech/going-vernacular-engineering-our-way-to-process-multilingual-names</guid><category><![CDATA[General Programming]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[System Architecture]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Mon, 04 Dec 2023 06:00:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/IhWYiwSxm8g/upload/5d16046a953c05d14734871c4385a166.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>At our current organization, earlier this year as we were looking at the errors at one of our signup API, we observed that nearly 5% of our requests were getting failed, all due to <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400">400 BAD REQUEST</a> errors, and the root cause was traced back to a regex check.</p>
<p>This regex was a constraint that our system allows only English characters for users to input their first and last names, yet many individuals opted to enter their names in their native languages. Particularly, these customers were the people who were interested in purchasing health policies from our platform hence making them a crucial segment of our user base.</p>
<p>In response to this, we decided to address the 5% case by enabling users to enter their names in any language they preferred. However, this brings up a lot of challenges that we need to solve.</p>
<h2 id="heading-challenges">Challenges</h2>
<h3 id="heading-1-data-storage-strategy">1. Data Storage Strategy</h3>
<p>We rely on MongoDB for storage and retrieval of user names. While MongoDB allows storage for all UTF-8 compatible characters, the problem comes when dealing with search. For English names, our search operations utilize the <a target="_blank" href="https://www.mongodb.com/docs/manual/reference/collation/">simple collation</a> method. The corresponding fields are appropriately indexed to optimize query performance.</p>
<p>While the option to implement a <a target="_blank" href="https://www.mongodb.com/docs/manual/reference/collation/">collation index</a> for other languages also exists in MongoDB, this approach necessitates informing DB about the specific language for which we intend to search. The challenge here is that our user base spans many languages, with India alone having more than 20 diverse languages.</p>
<p>Since our objective was to extend support to at least all Indian languages, implementing collation indexes for every supported language would lead to an increased number of indexes and hence an increase in index size over time as well.</p>
<p>Additionally, this approach would place the responsibility on developers to remember to add an index for each new language as our language support expands, which is far from an efficient solution.</p>
<h3 id="heading-2-api-gateway-constraint">2. API Gateway Constraint</h3>
<p>All our APIs are exposed behind an API gateway and just before the gateway forwards a request to the respective API service, an inbound policy verifies the user's authentication status. Once the user is authenticated, it retrieves basic user details such as name, mobile number, and other metadata, and appends it to a request header of that API.</p>
<p>A multitude of APIs rely on this user-specific data in headers for their further processing.</p>
<p>However, there's a restriction imposed by the gateway – it allows only <a target="_blank" href="https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html">ASCII</a> characters for processing and inclusion in the headers. So we had to make sure even though the name is in any other language, the response we share must be exclusively in English.</p>
<p>Also, this process must remain fast, as any delay in authentication could lead to sluggish API performance.</p>
<h3 id="heading-3-external-partners-challenge-with-vernacular-names">3. External Partners' Challenge with Vernacular Names</h3>
<p>Even if we started to accept names in multiple languages, there were our partners who had to accept those names from us. If they don't support multilingual names, the user journey breaks. One such was our payment partner. We had to make sure our payments team always received the English name even when users provided names in other languages.</p>
<p>Also, we wanted to avoid those annoying pop-ups prompting users to enter their names in English whenever we needed to. So keeping these problems in mind we had to build a viable solution.</p>
<h2 id="heading-solutioning">Solutioning</h2>
<p>While utilizing a third-party transliteration service might have been the easiest route, we opted to develop an in-house solution to control costs and maintain full control.</p>
<p>Considering the API gateway and the requirements of payment partners, it became clear that we needed to transform non-English names into English equivalents. However, presenting this English name to the user was counterintuitive – for example entering a name in Hindi, only to see it transformed into English upon logging in seemed contradictory.</p>
<p>Therefore, we developed a dual-naming strategy. The original fields, <code>"firstName"</code> and <code>"lastName"</code> would retain the user-entered names in their entered language, while we introduced two additional fields, <code>"englishFirstName"</code> and <code>"englishLastName"</code> dedicated to storing the English counterparts of these names. These English names could then be shared with the API gateway and our payment partners.</p>
<p>Coming back to the challenge of storing these names efficiently, we anticipated that managing collation indexes as the number of supported languages grew would become unmanageable. Additionally, searching would require specifying the collation for each query, creating an added layer of complexity. Hence, we decided to pivot away from this approach.</p>
<p>Our second approach involved using Unicode. As we aimed to support multiple languages without constraint, we recognized that Unicode could effectively represent characters in nearly every language. Consequently, we decided to store Unicode representations for first and last names in their respective MongoDB fields.</p>
<p>We just added another layer between our DB and the application that converts these Unicode strings to the original values in the local language while retrieving the names from DB and converting the local names to their respective English names for storing them in <code>englishFirstName</code> and <code>englishLastName</code> at the time of any insert or update.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699777686379/79ebd2a2-aeda-4f06-8bef-25ca6a7f0a6c.png" alt class="image--center mx-auto" /></p>
<p>This strategy provided the flexibility we needed to manage multilingual names seamlessly.</p>
<h3 id="heading-key-design-considerations">Key Design Considerations</h3>
<h4 id="heading-1-unicode-optimization">1. Unicode Optimization</h4>
<p>Unicode representation typically comprises a 6 character string, with 'a' represented as 'U+0061' and 'P' as 'U+0050,' commonly commencing with 'U+00.' To conserve space in our database storage, we opted to omit the 'U+' prefix and leading zeros, optimizing our data storage.</p>
<h4 id="heading-2-transliteration-vs-translation">2. Transliteration vs. Translation</h4>
<p>Initially, our aim was transliteration, which requires converting names from one script to another while retaining their phonetic sound. For example, the Hindi word <code>"प्रतीक्षा"</code> should be transformed to <code>"Partiksha"</code> and not translated to its English equivalent i.e. <code>"Wait"</code>. However, we recognized that Google Translate primarily focuses on translation, not transliteration. Again we didn't want to go directly for the paid Google transliterate service in our first iteration hence we developed our transliteration service using the free version of Google translate.</p>
<h4 id="heading-3-contextual-enhancements">3. Contextual Enhancements</h4>
<p>Another and the most crucial observation that we had was providing context to the Google Translate API that influenced its responses. To leverage this, we experimented with adding statement prefixes to non-English names to establish context. After a few hits and trials, we realized that for shorter names (less than 5 characters), a more extensive prefix statement didn't yield desirable results, and Google often returned the same Hindi word. For longer names, we employed lengthier statements, determining the optimal balance through trial and error.</p>
<hr />
<p>Translating names normally led to their literal translation. For example "प्रतीक्षा" to "Wait" instead of "Pratiksha":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699726163389/b8b39f05-928b-4801-a2e8-7fc6db3279b1.png" alt class="image--center mx-auto" /></p>
<p>Adding a prefix statement corrected it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699726207309/3e1dd55c-dfa1-4106-8f7f-abef22b4e880.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-initial-code">Initial Code</h2>
<p>After our first iteration, we developed the below code for transliteration. Here we are using the <code>@iamtraction/google-translate</code> library which is a wrapper written over free Google translate API.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> translate = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@iamtraction/google-translate'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getGoogleTranslateText</span>(<span class="hljs-params">localName</span>) </span>{
  <span class="hljs-comment">/*
    Adding an English sentence before the name so that
    it doesn't get translated to its literal meaning.
    For eg परीक्षा to Exam instead of Pariksha.
  */</span>
  <span class="hljs-keyword">if</span> (localName.length &lt;= <span class="hljs-number">5</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`name: <span class="hljs-subst">${localName}</span>`</span>;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-string">`your name is: <span class="hljs-subst">${localName}</span>`</span>;
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">translateNameToEnglish</span>(<span class="hljs-params">localName</span>) </span>{
  <span class="hljs-keyword">if</span> (localName.match(<span class="hljs-regexp">/^[a-zA-Z ]+$/i</span>)) {
    <span class="hljs-comment">// If the name is already in English just return</span>
    <span class="hljs-keyword">return</span> localName;
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> translate(getGoogleTranslateText(localName), {
      <span class="hljs-attr">to</span>: <span class="hljs-string">'en'</span>,
    });
    <span class="hljs-keyword">const</span> translatedName = res.text.split(<span class="hljs-string">':'</span>)[<span class="hljs-number">1</span>].trim();
    <span class="hljs-keyword">return</span> translatedName;
  } <span class="hljs-keyword">catch</span> (err) {}
  <span class="hljs-comment">// In case of error, Return the Unicode string</span>
  <span class="hljs-keyword">return</span> localName;
}
</code></pre>
<h2 id="heading-beta-release-and-production-challenges">Beta Release and Production Challenges</h2>
<p>Once we built this, we released the feature in beta, and approximately 250 users signed up with non-English names within the first few days.</p>
<p>Upon simple eyeballing on translated texts, we found out that the process of converting the name from its local language to Unicode was working perfectly fine and users were able to view their names properly in the application in the language they preferred but we identified two issues as far as the process of transliteration to English was concerned:</p>
<ol>
<li><p><strong>Some names were incorrectly transliterated</strong>. This occurrence could be attributed to our dependence on Google Translate, a general translation service, rather than a specialized transliteration service.</p>
</li>
<li><p><strong>Some names remained unaltered and were not transliterated</strong>. These names were returned in the same language as the original one. This meant adding context with prefix sentences before the translation was causing problems for specific names.</p>
</li>
</ol>
<p>This prompted a further investigation that led us to another npm package called "unidecode," which converts Unicode to the original string. While initial tests with unidecode showed accuracy, they also revealed minor spelling discrepancies. In contrast, Google consistently delivered translations with correct spellings. We just needed to find a way of using the best of both worlds.</p>
<p>Hence, we incorporated unidecode into our algorithm as part of our solution.</p>
<h2 id="heading-improved-solution">Improved Solution</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> translate = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@iamtraction/google-translate'</span>);
<span class="hljs-keyword">const</span> unidecode = <span class="hljs-built_in">require</span>(<span class="hljs-string">'unidecode'</span>);
<span class="hljs-keyword">const</span> { isAlmostEqualStrings } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./levenshtein'</span>);
<span class="hljs-comment">/**
 *
 * @param {String} localName
 * @description Generates text for Google (shorter statement context for short names) based on localName length
 * @returns {String} returns text to translate
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getGoogleTranslateText</span>(<span class="hljs-params">localName</span>) </span>{
  <span class="hljs-comment">/*
    Adding an English sentence before name so that
    it doesn't get translated to its literal meaning.
    For eg परीक्षा to Exam instead of Pariksha.
  */</span>
  <span class="hljs-keyword">if</span> (localName.length &lt;= <span class="hljs-number">5</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`name: <span class="hljs-subst">${localName}</span>`</span>;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-string">`your name is: <span class="hljs-subst">${localName}</span>`</span>;
}

<span class="hljs-comment">/**
 *
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">localName</span></span>
 * <span class="hljs-doctag">@description </span>Give an ALMOST transliterated name
 * <span class="hljs-doctag">@returns <span class="hljs-type">{String}</span> </span>returns a converted transliterated name from the local language
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transliterate</span>(<span class="hljs-params">localName, googleTranslatedName</span>) </span>{
  <span class="hljs-keyword">const</span> decodedName = unidecode(localName);
  <span class="hljs-keyword">if</span> (
    decodedName &amp;&amp;
    <span class="hljs-built_in">Array</span>.from(decodedName)[<span class="hljs-number">0</span>]?.toLowerCase() !==
      <span class="hljs-built_in">Array</span>.from(googleTranslatedName)[<span class="hljs-number">0</span>]?.toLowerCase() &amp;&amp;
    !isAlmostEqualStrings(decodedName, googleTranslatedName)
  ) {
    <span class="hljs-keyword">return</span> decodedName;
  }
  <span class="hljs-keyword">return</span> googleTranslatedName;
}

<span class="hljs-comment">/**
 *
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> </span>Input non English string
 * <span class="hljs-doctag">@description </span>translates non-english string to English
 * <span class="hljs-doctag">@returns <span class="hljs-type">{String}</span> </span>returns translated string
 */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">translateNameToEnglish</span>(<span class="hljs-params">localName</span>) </span>{
  <span class="hljs-keyword">if</span> (!localName || localName.match(<span class="hljs-regexp">/^[a-zA-Z ]+$/i</span>)) {
    <span class="hljs-comment">// If name is already in English just return</span>
    <span class="hljs-keyword">return</span> localName;
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> translate(getGoogleTranslateText(localName), {
      <span class="hljs-attr">to</span>: <span class="hljs-string">'en'</span>,
    });
    <span class="hljs-keyword">const</span> translatedName = res.text.split(<span class="hljs-string">':'</span>)[<span class="hljs-number">1</span>].trim();
    <span class="hljs-keyword">return</span> transliterate(localName, translatedName);
  } <span class="hljs-keyword">catch</span> (err) {}
  <span class="hljs-comment">// In case of error, Return original string</span>
  <span class="hljs-keyword">return</span> localName;
}
</code></pre>
<p>After obtaining the translated name, we feed it into the recently introduced <code>transliterate</code> function. Inside this function, our initial step involves extracting the decoded string using the <code>Unidecode</code> library. However, the crux of the matter arises: How do we determine which result to prioritize, i.e., the decoded string or the translated string?</p>
<p>To tackle this, we implemented <a target="_blank" href="https://en.wikipedia.org/wiki/Levenshtein_distance"><strong>Levenshtein Distance</strong></a>, an algorithm that calculates the similarity between two strings.</p>
<p>Initially, we check if the first character of the decoded name matches the first character of the translated name. If it's not, then for sure the translated name was incorrect hence we return the decoded name, even though it might contain minor spelling discrepancies it's better to use that than the incorrect translation.</p>
<p>If it does match then we go for the Levenshtein Distance algorithm.</p>
<blockquote>
<p>The Levenshtein distance is a number that tells you how similar two strings are. The higher the number, the more dissimilar the two strings are</p>
</blockquote>
<p>In the implementation, we have a function <code>isAlmostEqualStrings</code> that generates a value from 0 to 1 and returns true if the value is above a certain threshold. In our case, we set the threshold to 0.8</p>
<p>If the Levenshtein distance indicates a match exceeding 80%, we return the translated name; otherwise, we return the decoded name. This approach ensures that we prioritize accuracy, offering a reliable result based on the established similarity threshold.</p>
<p>This updated algorithm substantially reduced the above mentioned issues. Even though it's not 100% accurate it solved our 5% cases very well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The algorithm developed was entirely in-house and incurred no costs. While investing in a paid solution might have potentially offered better results, wise engineering decisions taken iteratively and a handful of clever hacks played a vital role in both reducing costs and efficiently resolving the specific problem we had.</p>
<p>The complete code for the above implementation along with the Levenshtein Distance algorithm can be found on <a target="_blank" href="https://github.com/ApoorvTyagi/english-transliterate">GitHub</a> (contributions/corrections are welcome).</p>
<p>With this, we come to the end of the article. My DMs are always open if you want to discuss further on any tech topic or if you've got any questions, suggestions, or feedback in general:</p>
<ul>
<li><a target="_blank" href="https://twitter.com/apoorv__tyagi">Twitter</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/apoorvtyagi/">LinkedIn</a></li>
</ul>
<p>Happy learning!</p>
]]></content:encoded></item><item><title><![CDATA[How to Keep Your Package Dependencies Up to Date on Azure DevOps]]></title><description><![CDATA[Introduction
As a developer, how often have you seen a repository with packages that are out of date?
New package updates generally include new features, performance improvements, and security fixes. But keeping track of all outdated dependencies in ...]]></description><link>https://apoorvtyagi.tech/how-to-keep-your-package-dependencies-up-to-date-on-azure-devops</link><guid isPermaLink="true">https://apoorvtyagi.tech/how-to-keep-your-package-dependencies-up-to-date-on-azure-devops</guid><category><![CDATA[General Programming]]></category><category><![CDATA[azure-devops]]></category><category><![CDATA[Azure]]></category><category><![CDATA[dependabot]]></category><category><![CDATA[Pipeline]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 03 Dec 2023 13:00:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1699898335897/4e3e65eb-717f-455c-89b7-eb68ed5054cf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>As a developer, how often have you seen a repository with packages that are out of date?</p>
<p>New package updates generally include new features, performance improvements, and security fixes. But keeping track of all outdated dependencies in your project can be really boring and a time consuming task, especially if you have lots of them.</p>
<p>So to do this sort of housekeeping, I tried out <a target="_blank" href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/">Dependabot</a>.</p>
<h2 id="heading-how-dependabot-works"><strong>How Dependabot Works</strong></h2>
<p>Dependabot goes through the dependency files of your project. For instance, it searches your <code>package.json</code> or <code>pom.xml</code> files and inspects for any outdated or insecure dependencies. If it finds any, it opens individual pull requests to update each one of them.</p>
<p>This tool is natively integrated with GitHub. But recently, I had to solve this problem of updating dependencies for a project running in Azure DevOps. So I decided to find a workaround to integrate Dependabot with Azure Pipelines. In this blog post, I will share my solution.</p>
<p>If you go to <a target="_blank" href="https://marketplace.visualstudio.com/azuredevops">Azure DevOps Extension Marketplace</a> and search for "Dependabot", you will find an <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=tingle-software.dependabot">extension</a> by Tingle Software. Using this extension we can easily integrate Dependabot with our repos in Azure DevOps.</p>
<p>You can check if you have this extension in your "Organization Settings" in Azure DevOps. If not, make sure you have it installed before proceeding.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/1-2.png" alt="1-2" /></p>
<p>Installed Extensions - Azure DevOps</p>
<h2 id="heading-how-to-create-the-azure-pipeline"><strong>How to Create the Azure Pipeline</strong></h2>
<p>Let's now start with creating a new <code>YAML</code> file for your Azure pipeline:</p>
<pre><code class="lang-javascript">trigger: none

<span class="hljs-attr">stages</span>:
  - stage: CheckDependencies
    <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Check Dependencies'</span>
    <span class="hljs-attr">jobs</span>:
      - job: Dependabot
        <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
        <span class="hljs-attr">pool</span>:
          vmImage: <span class="hljs-string">'ubuntu-latest'</span>
        <span class="hljs-attr">steps</span>:
          - task: dependabot@<span class="hljs-number">1</span>
            <span class="hljs-attr">displayName</span>: <span class="hljs-string">'Run Dependabot'</span>
            <span class="hljs-attr">inputs</span>:
              packageManager: <span class="hljs-string">'npm'</span>
              <span class="hljs-attr">targetBranch</span>: <span class="hljs-string">'develop'</span>
              <span class="hljs-attr">openPullRequestsLimit</span>: <span class="hljs-number">10</span>
</code></pre>
<p>In the task parameters, I have specified three params:</p>
<ol>
<li><p><strong>packageManager</strong>: It specifies the type of packages to check for dependency upgrades. Examples: <code>nuget</code>, <code>maven</code>, <code>gradle</code>, <code>npm</code>, and so on.</p>
</li>
<li><p><strong>targetBranch</strong>: It is an optional parameter that defines the branch to be targeted when creating pull requests. When not specified, Dependabot will pick the <code>default</code> branch of the repository.</p>
</li>
<li><p><strong>openPullRequestsLimit</strong>: This is again an optional parameter that specifies the maximum number of open pull requests to have at any one time. By default, it opens 5 pull requests at a time.</p>
</li>
</ol>
<p>You can go through all the <a target="_blank" href="https://github.com/tinglesoftware/dependabot-azure-devops/blob/main/src/extension/README.md#task-parameters">Task Parameters</a> that the extension supports to tweak your implementation. Now just simply configure this YAML file with a new azure pipeline and then you're ready to run it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/3-2.png" alt="3-2" /></p>
<p>Pipeline Configuration - Azure DevOps</p>
<p>The next step is to give your repository's <code>Project Collection Build Service</code> access so that Dependabot can create the pull request to your project's repositories.</p>
<p>For that, go to your project settings. Here, you click on the repositories and search for the repo where you have integrated the pipeline.</p>
<p>After you have selected that, click on the security tab and search for <strong>project collection build service</strong>. You have to allow the following access to it:</p>
<ul>
<li><p>Contribute</p>
</li>
<li><p>Contribute to pull request</p>
</li>
<li><p>Create Branch</p>
</li>
<li><p>Create Tag</p>
</li>
<li><p>Force Push</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/2-1.png" alt="2-1" /></p>
<p>Access to raise PR in Repo</p>
<p>With this, you're completely ready to run the pipeline. Once you do it, you'll start receiving pull requests in your repository with the updated packages.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/5-3.png" alt="5-3" /></p>
<p>PR raised by Dependabot</p>
<h2 id="heading-how-to-schedule-the-pipeline"><strong>How to Schedule the Pipeline</strong></h2>
<p>Up to this point, you've had to manually trigger the pipeline to run. To make it run automatically, you can configure schedules for your pipelines. This will trigger your pipeline to start based on a schedule.</p>
<p>Use the following syntax and add it to the very top of your <code>YAML</code> file:</p>
<pre><code class="lang-javascript">schedules:
- cron: string
  <span class="hljs-attr">displayName</span>: string
  <span class="hljs-attr">branches</span>:
    include: [ string ]
  <span class="hljs-attr">always</span>: boolean
</code></pre>
<p>The branche<em>s’</em> <code>include</code> parameter specifies which branches the schedule applies to.</p>
<p>The <code>always</code> parameter specifies whether to "always" run the pipeline or only if there have been any source code changes since the last successful scheduled run. The default is false.</p>
<p>For this case, you set its value to <strong>true</strong> as Dependabot updates are independent of any code changes.</p>
<p>The time zone for cron schedules is UTC and cron syntax is as follows:</p>
<pre><code class="lang-javascript">mm HH DD MM DW
 \  \  \  \  \__ Days <span class="hljs-keyword">of</span> week
  \  \  \  \____ Months
   \  \  \______ Days
    \  \________ Hours
     \__________ Minutes
</code></pre>
<p>So if you want to run your pipeline every week on Sunday at 12pm UTC, you would need to write - <code>cron: "0 12 * * 0"</code> (update the cron to suit your needs).</p>
<p>This is how your final <code>YAML</code> should look like after adding a schedule:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">schedules:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">"0 12 * * 0"</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">Weekly</span> <span class="hljs-string">Dependency</span> <span class="hljs-string">Updates</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-attr">include:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">develop</span>
    <span class="hljs-attr">always:</span> <span class="hljs-literal">true</span>

<span class="hljs-attr">trigger:</span> <span class="hljs-string">none</span>

<span class="hljs-attr">stages:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">CheckDependencies</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Check Dependencies'</span>
    <span class="hljs-attr">jobs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Dependabot</span>
        <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Run Dependabot'</span>
        <span class="hljs-attr">pool:</span>
          <span class="hljs-attr">vmImage:</span> <span class="hljs-string">'ubuntu-latest'</span>
        <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">dependabot@1</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Run Dependabot'</span>
            <span class="hljs-attr">inputs:</span>
              <span class="hljs-attr">packageManager:</span> <span class="hljs-string">'npm'</span>
              <span class="hljs-attr">targetBranch:</span> <span class="hljs-string">'develop'</span>
              <span class="hljs-attr">openPullRequestsLimit:</span> <span class="hljs-number">10</span>
</code></pre>
<p>This pipeline does the following for you:</p>
<p>It runs every week (Sunday 12pm UTC in this case) and looks for any outdated or insecure dependency. If it finds any, it opens pull requests to update each one of them individually.</p>
<p>Hopefully, this will help you to keep your project dependencies up to date in Azure DevOps!</p>
<h2 id="heading-wrapping-up"><strong>Wrapping Up</strong></h2>
<p>With this, we come to the end of the article. My DMs are always open if you want to discuss further on any tech topic or if you've got any questions, suggestions, or feedback in general:</p>
<ul>
<li><a target="_blank" href="https://twitter.com/apoorv__tyagi">Twitter</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/apoorvtyagi/">LinkedIn</a></li>
</ul>
<p>Happy learning!</p>
]]></content:encoded></item><item><title><![CDATA[Finding a Needle in Haystack: Fixing Mysterious Bad Gateway]]></title><description><![CDATA[Introduction
At my current org, we have many applications running behind the API gateway that interacts with the outside world using REST APIs. To track server-side failures we built an alert system that nudges every time we get any 5XX error.
As soo...]]></description><link>https://apoorvtyagi.tech/finding-a-needle-in-haystack-fixing-mysterious-bad-gateway</link><guid isPermaLink="true">https://apoorvtyagi.tech/finding-a-needle-in-haystack-fixing-mysterious-bad-gateway</guid><category><![CDATA[General Programming]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[Devops]]></category><category><![CDATA[debugging]]></category><category><![CDATA[TCP]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sat, 11 Mar 2023 06:00:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/M5tzZtFCOfs/upload/b80cb5fbf3f8a84424efbc79b58eb303.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>At my current org, we have many applications running behind the API gateway that interacts with the outside world using REST APIs. To track server-side failures we built an alert system that nudges every time we get any 5XX error.</p>
<p>As soon as we made the alert system live, we started noticing a few HTTP 502 “Bad Gateway” errors occurring every day but intermittently.</p>
<blockquote>
<p>As per <a target="_blank" href="https://tools.ietf.org/html/rfc7231#section-6.6.3">RFC7231</a>, the 502 (Bad Gateway) status code indicates that the server while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.</p>
</blockquote>
<p>With very little known information, I began chasing down the RCA for these failures.</p>
<h2 id="heading-debugging">Debugging</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677955971506/b1aabcf2-a7fb-43c6-bb6d-93b6945c5992.png" alt class="image--center mx-auto" /></p>
<p>As I started debugging the issue I wanted first to check what was going on in the application at the time when the particular request arrived. However, I discovered that this failed request never reached the server-side application.</p>
<p>We also have a proxy server sitting in between our API gateway and the application so I checked the logs of that as well and fortunately, I was able to track the request there.</p>
<p>I observed the request despite coming from the API gateway, the response sent was 502, without even communicating with my application.</p>
<p>Next, I checked the throughput when such a response was sent as I thought maybe there was a limitation in the number of concurrent requests our application can handle. But the result was again surprising because even when the throughput was &lt; 1000 TPM (Transactions Per Minute), the 502 error persisted and we had already observed our applications working well even at a TPM of well over 5000.</p>
<p>Based on these findings, I realized that issue is not with our application code but with how our proxy server interacts with my application. So I started diving deep into how HTTP connections are made during the request-response cycle.</p>
<h2 id="heading-diving-in-tcp-connection">Diving in TCP Connection</h2>
<p>In the realm of web communication, HTTP (Hypertext Transfer Protocol) initiates a unique TCP (Transmission Control Protocol) connection for every request. Setting up a TCP connection requires a three-step handshake process with the server before transmitting data. Once the data transmission is finished, a four-step process is implemented to terminate the same connection.</p>
<p>In some scenarios where limited data is transmitted, the three and four-step processes involved in establishing and terminating TCP connections can add a significant overhead. To address this issue, rather than opening and closing a socket for each HTTP request, it is possible to keep a socket open for a more extended period and leverage it for multiple HTTP requests.</p>
<p>This mechanism is known as <a target="_blank" href="https://en.wikipedia.org/wiki/HTTP_persistent_connection">HTTP keep-alive</a>, which permits clients to reuse existing connections for several requests. The decision of when to terminate these open TCP sockets is managed by timeout configurations on either the client or target server or both. This approach improves the efficiency of web communication and reduces latency.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678505457969/86dc185f-a97c-4a15-b283-0a8aa903975d.png" alt class="image--center mx-auto" /></p>
<p>An important point here to notice is that for a short amount of time, there is a possibility that a connection can be “half-open”, in which one side has terminated the connection but the other has not. The side that has terminated can no longer send any data into the connection, but the other side still can. The terminating side continues reading the data until the other side terminates as well.</p>
<p>Now coming back to our story, the proxy server acts as a messenger passing requests and responses back and forth. If the service returns an invalid or malformed response, rather than transmitting that meaningless information to the client, the proxy server sends a 502 error message.</p>
<p>This suggests that our application might have attempted to terminate the TCP connection, but the proxy server was unaware of this and continued to send the request to the same socket. This provided us with a critical hint in our investigation.</p>
<h2 id="heading-debugging-further">Debugging, further</h2>
<p>The 502 Bad Gateway error could occur when the proxy server sends a request to the application, and simultaneously, the service terminates the connection by sending the <code>FIN</code> segment to the same socket. The proxy socket acknowledges the <code>FIN</code> and starts a new handshake process.</p>
<p>Meanwhile, the socket on the server side has just received a data request referring to the previous (now closed) connection. As it is unable of handling it, it sends a <code>RST</code> segment back to the proxy server. The proxy server then returns a 502 error to the user.</p>
<p>Based on this hypothesis, we found the default HTTP keep-alive time. While the proxy server's keep-alive time was set at 75 seconds, our application had a keep-alive of only <a target="_blank" href="https://nodejs.org/api/http.html#http_server_keepalivetimeout">5 seconds</a>. This suggests that after 5 seconds, our application could close the connection, and while this process is ongoing, the proxy server could receive a request. As it has not yet received the <code>FIN</code>, it sends the request down the dead connection, receives nothing in response, and therefore throws a 502 error.</p>
<p>To verify this hypothesis, I modified the HTTP keep-alive timeout of our application to 1 ms in our development environment. We then conducted load testing on our APIs and found a significant number of API failures due to the same 502 error. This confirmed our initial hypothesis.</p>
<h2 id="heading-fix">Fix</h2>
<p>A possible solution is to ensure that the upstream (application) idle connection timeout is longer than the downstream (proxy) connection timeout.</p>
<p>In practice, this can be achieved by increasing the keep-alive time of the application server to a value greater than the proxy's connection timeout. For example, in our setup, I have increased the server's keep-alive time from 5 seconds to 76 seconds, which is 1 second longer than the proxy server's connection timeout.</p>
<p>By doing so, the downstream (proxy) server becomes the one to close the connections instead of the upstream server. This ensures that there is no race condition between the two servers and eliminates the possibility of a 502 error caused by a closed connection. <strong>Therefore, setting appropriate upstream and downstream timeouts is crucial for the smooth functioning of web applications</strong>.</p>
<h3 id="heading-the-below-example-illustrates-how-to-modify-the-default-keep-alive-timeout-for-an-expresshttpsexpressjscomenstarterhello-worldhtml-app">The below example illustrates how to modify the default keep-alive timeout for an <a target="_blank" href="https://expressjs.com/en/starter/hello-world.html">Express</a> app:</h3>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> server = app.listen(<span class="hljs-number">3000</span>);

server.keepAliveTimeout = <span class="hljs-number">76</span> * <span class="hljs-number">1000</span> <span class="hljs-comment">// Time in ms</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Theoretically, this race condition can occur anytime when the connections are reused &amp; if the upstream service drops connections before the downstream.</p>
<p>In my case, it was the proxy server that pre-connects to all the backend servers, and the TCP connection persists for reusing for further HTTP requests. The Keep-Alive time of this connection was 75 seconds from the proxy and 5 seconds from the app server.</p>
<p>This was causing a condition where the proxy thinks a connection is open, but the backend closes it. And when it sends the request down the same connection, instead of getting the TCP <code>ACK</code> for the sent request, the proxy gets TCP <code>FIN</code> (and eventually <code>RST</code>) from the upstream.</p>
<p>The proxy server then just gives up on such requests and responds immediately with HTTP 502 error to the client. <strong>And this is completely invisible on the application side!</strong> That's why no application logs were visible to us.</p>
<p>To mitigate this you can either make sure the upstream (application) idle connection timeout is longer than the downstream (proxy) connection timeout OR <a target="_blank" href="https://apoorvtyagi.tech/building-resilient-systems-retry-pattern-in-microservices">implement retries on HTTP 5xx errors</a> from the API gateway.</p>
<p>I hope you found it helpful. Comments or corrections are always welcome.</p>
]]></content:encoded></item><item><title><![CDATA[Building Resilient Systems: Retry Pattern in Microservices]]></title><description><![CDATA[Introduction
Any application that communicates with other resources over a network has to be resilient to transient failures.
These failures are sometimes self-correcting. For example, a service that is processing thousands of concurrent requests can...]]></description><link>https://apoorvtyagi.tech/building-resilient-systems-retry-pattern-in-microservices</link><guid isPermaLink="true">https://apoorvtyagi.tech/building-resilient-systems-retry-pattern-in-microservices</guid><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[best practices]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Mon, 06 Mar 2023 04:45:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678007180369/f3187b00-d171-4580-afb4-93e72f54dbd8.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Any application that communicates with other resources over a network has to be resilient to transient failures.</p>
<p>These failures are sometimes self-correcting. For example, a service that is processing thousands of concurrent requests can implement an algorithm to temporarily reject any further requests until its load gets reduced. An application that is trying to access this service may initially fail to connect, but if it tries again it might succeed.</p>
<p>While designing any system it is essential to make it resilient against such failures. In this article, we will look at one of the many ways of achieving it using <strong>Retries</strong>.</p>
<p>At our current organization, we use this mechanism throughout our microservices to make sure that we handle failures and at the same time, provide the best of our services to our customers.</p>
<p>Let’s start by first defining what we mean by failures.</p>
<h2 id="heading-what-is-a-failure">What is a failure?</h2>
<p>Failures can be caused by numerous reasons while our services communicate with each other over a network. Some examples of types of failures are:</p>
<ul>
<li><p>A slow response / No response at all</p>
</li>
<li><p>A response in the incorrect format</p>
</li>
<li><p>A response containing incorrect data</p>
</li>
</ul>
<p>In planning for failures, we should seek to handle each of these errors.</p>
<h2 id="heading-retry">Retry</h2>
<p>Retry is a process of automatically repeating a request in case any failure is detected. This helps return fewer errors to the users, improving the consumer experience on our application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665147846141/tJFbtZx1x.png" alt="image.png" class="image--center mx-auto" /></p>
<p>The only caveat when it comes to retrying is that multiple requests to the same resource should have the same effect as making a single request i.e the resource should be <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Idempotent"><strong>idempotent</strong></a>.</p>
<blockquote>
<p>In REST APIs, <code>GET</code>, <code>HEAD</code> and <code>OPTIONS</code> methods generally do not change the resource state on the server and hence are mostly retryable.</p>
</blockquote>
<h3 id="heading-when-should-we-retry-a-request">When should we retry a request?</h3>
<p>Ideally, we should only retry a failed request when we know it has any possibility of succeeding the next time otherwise it will just be a waste of resources (CPU, Memory, and Time).</p>
<p>For example, you might get an error with status code 503 (Service unavailable) when the server had an unexpected hiccup while connecting to a DB host. A retry may work here if the second call to the upstream service gets a DB instance that is available.</p>
<p>On the other hand, retrying for errors with status code 401(Unauthorised) or 403 (Forbidden) may never work because they require changing the request itself.</p>
<p>The general idea is that if an upstream request fails, we immediately try again, and probably the second request will succeed. However, this will not always benefit us. The actual implementation should include a delay between the subsequent requests. We will discuss that in the next sections.</p>
<h2 id="heading-problem-with-normal-retries">Problem with normal retries</h2>
<p>Consider what happens when we get 100,000 concurrent requests &amp; all hosts of the upstream service are down at that instance. If we were to retry immediately, these 100,000 failed requests would retry immediately on a static interval. They would also be combined with new requests from the increasing traffic and could make the service down again.</p>
<p>This creates a cycle that keeps repeating until all the retries are exhausted and will also eventually makes the upstream service overwhelm, and might further degrade the service that is already under distress. This is a common computer science problem also known as the <a target="_blank" href="https://en.wikipedia.org/wiki/Thundering_herd_problem">Thundering Herd</a> problem.</p>
<p>To tackle this, we can introduce some delay in retrying a failed request.</p>
<h3 id="heading-backoff">Backoff</h3>
<p>The wait time between a request and its subsequent retry is called the backoff.</p>
<p>With backoff, the amount of time between requests increases exponentially as the number of retry requests increases.</p>
<p>The scenario we just discussed above is where having a backoff helps, it changes the wait time between attempts based on the number of previous failures.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666863178933/-YokS4kjH.png" alt="Backoff Jitter.png" class="image--center mx-auto" /></p>
<p>From the above figure, let's say the initial request goes at the 0th millisecond and fails with a retryable status code. Assuming that we have set up the backoff time of 200ms and neglecting the request-response time, the first retry attempt happens at 200th milliseconds (1*200ms). If this fails again, the second retry then happens at 400ms (2*200). Similarly, the subsequent retry happens at 800ms till we exhaust all the retries.</p>
<p>If any of the request failures are caused by the upstream service being overloaded, this mechanism of spreading out our requests and retries gives us a better chance of getting a successful response.</p>
<h3 id="heading-jitter">Jitter</h3>
<p>The Backoff strategy allows us to distribute the load sent to the upstream services. Yet, turns out it isn't always the wisest decision because all the retries are still going to be in sync which can lead to a spike on the service.</p>
<p>Jitter is the process of breaking this synchronization by increasing or decreasing the backoff delay to further spread out the load.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666863164305/8yQ3xPoMv.png" alt="Backoff.png" class="image--center mx-auto" /></p>
<p>Coming back to our previous example, let’s say our upstream service is serving the maximum load that it can handle and four new clients send their requests which fail because the server could not handle that amount of concurrent requests. With only backoff implementation, let's say after 200 milliseconds we retry all 4 failed requests. Now, these retry requests would also fail again for the same reason. To avoid this, the retry implementation needs to have randomness.</p>
<h2 id="heading-implementation">Implementation</h2>
<p>Going through this <a target="_blank" href="https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/">AWS documentation</a> that goes deep into the exponential backoff algorithm, we have implemented our retry mechanism using <a target="_blank" href="https://axios-http.com/docs/interceptors">Axios interceptor</a></p>
<p>The example is written inside of a Nodejs application, but the process will be similar regardless of which JavaScript framework you’re using.</p>
<p>In this, we expect the following settings:</p>
<p><strong>Total Retries</strong> The number of maximum retries you want before returning a failed response to the client.</p>
<p><strong>Retry Status Codes</strong> The HTTP status codes that you want to retry for. By default, we have kept it on for all status codes &gt;=500.</p>
<p><strong>Backoff</strong> This is the minimum time we have to wait while sending any subsequent retry request.</p>
<pre><code class="lang-js">axios.interceptors.response.use(
  <span class="hljs-keyword">async</span> (error) =&gt; {

    <span class="hljs-keyword">const</span> statusCode = error.response.status
    <span class="hljs-keyword">const</span> currentRetryCount = error.response.config.currentRetryCount ?? <span class="hljs-number">0</span>
    <span class="hljs-keyword">const</span> totalRetry = error.response.config.retryCount ?? <span class="hljs-number">0</span>
    <span class="hljs-keyword">const</span> retryStatusCodes = error.response.config.retryStatusCodes ?? []
    <span class="hljs-keyword">const</span> backoff = error.response.config.backoff ?? <span class="hljs-number">100</span>

    <span class="hljs-keyword">if</span>(isRetryRequired({
      statusCode, 
      retryStatusCodes, 
      currentRetryCount, 
      totalRetry})
    ){

      error.config.currentRetryCount = 
          currentRetryCount === <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : currentRetryCount + <span class="hljs-number">1</span>;

     <span class="hljs-comment">// Create a new promise with exponential backoff</span>
     <span class="hljs-keyword">const</span> backOffWithJitterTime = getTimeout(currentRetryCount,backoff);
     <span class="hljs-keyword">const</span> backoff = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve</span>) </span>{
          <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
              resolve();
          }, backOffWithJitterTime);
      });

      <span class="hljs-comment">// Return the promise in which recalls Axios to retry the request</span>
      <span class="hljs-keyword">await</span> backoff;
      <span class="hljs-keyword">return</span> axios(error.config);

    }
  }
);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isRetryRequired</span>(<span class="hljs-params">{
  statusCode, 
  retryStatusCodes, 
  currentRetryCount, 
  totalRetry}
 </span>)</span>{

  <span class="hljs-keyword">return</span> (statusCode &gt;= <span class="hljs-number">500</span> || retryStatusCodes.includes(statusCode))
          &amp;&amp; currentRetryCount &lt; totalRetry;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTimeout</span>(<span class="hljs-params">numRetries, backoff</span>) </span>{
  <span class="hljs-keyword">const</span> waitTime = <span class="hljs-built_in">Math</span>.min(backoff * (<span class="hljs-number">2</span> ** numRetries));

  <span class="hljs-comment">// Multiply waitTime by a random number between 0 and 1.</span>
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.random() * waitTime;
}
</code></pre>
<p>While making an Axios request you have to make sure to add the variables in the request configurations:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> axios= <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);
<span class="hljs-keyword">const</span> sendRequest= <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> requestConfig = {
             <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
             <span class="hljs-attr">url</span>: <span class="hljs-string">'api.example.com'</span>,
             <span class="hljs-attr">headers</span>: { 
                <span class="hljs-string">'authorization'</span>: <span class="hljs-string">'xxx'</span>,
              },
              <span class="hljs-attr">data</span>: payload,
              <span class="hljs-attr">retryCount</span> : <span class="hljs-number">3</span>,
              <span class="hljs-attr">retryStatusCodes</span>: [<span class="hljs-string">'408'</span>, <span class="hljs-string">'429'</span>],
              <span class="hljs-attr">backoff</span>: <span class="hljs-number">200</span>,
              <span class="hljs-attr">timeout</span>: <span class="hljs-number">5000</span>
          };
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios(requestConfig);
      <span class="hljs-keyword">return</span> response.data;
}
</code></pre>
<p>When configuring the retry mechanism, it is important to tune the total retries, and maximum delay together. The goal is to tailor these values keeping in mind the worst-case response time to our consumers.</p>
<p>Pictorially this is how it will work:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669559247799/QFBHDCbQO.png" alt="image.png" /></p>
<blockquote>
<p>For Java based applications, the same can be done using <a target="_blank" href="https://resilience4j.readme.io/docs/retry">resilience4j</a></p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post, we looked at one of the many service reliability mechanisms: Retries. We saw how it works, how to configure it and tackle some of the common problems with retries using backoff and jitter.</p>
<p>I hope you found it helpful. Comments or corrections are always welcome.</p>
<p>GitHub Link for the above source code can be found <a target="_blank" href="https://github.com/ApoorvTyagi/node-retry">here</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Choose The Right Database for Your Application]]></title><description><![CDATA[Introduction
Choosing which database to use is one of the most important decisions you can make when starting working on a new app or website.
If you realize down the line that you’ve made the wrong choice, migrating to another database is very costl...]]></description><link>https://apoorvtyagi.tech/how-to-choose-the-right-database-for-your-application</link><guid isPermaLink="true">https://apoorvtyagi.tech/how-to-choose-the-right-database-for-your-application</guid><category><![CDATA[THW Web Apps]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Databases]]></category><category><![CDATA[SQL]]></category><category><![CDATA[NoSQL]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 15 May 2022 06:00:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/JlijbOtSWuw/upload/v1650301396350/NoTgtOXB2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Choosing which database to use is one of the most important decisions you can make when starting working on a new app or website.</p>
<p>If you realize down the line that you’ve made the wrong choice, migrating to another database is very costly and sometimes more complex to do with zero downtime. </p>
<p>Taking time to make an informed choice of database technology upfront can be a valuable early decision for your application.</p>
<p><em>(A bonus reason for why this is important is because understanding the different DBs and their properties &amp; which one to choose over the other is quite commonly asked in job interviews)</em></p>
<p>Each database technology has advantages and disadvantages. Cloud providers like Amazon offer various database and storage options making it harder to figure out which one is the right one.</p>
<p>Relational databases have been a primary data storage mechanism for a long time. Non-relational databases have existed since the 1960s but recently gained traction with popular options such as MongoDB.</p>
<p>In this article, we will go through the factors you should consider while choosing any database.</p>
<h2 id="heading-the-language-determines-the-database">The language determines the database</h2>
<p>First things first. The language or the technology you are going to use never determines the database ❌</p>
<p>We’ve grown accustomed to technology stacks, such as MERN (MongoDB, Express, React, Node.js) &amp; LAMP (Linux, Apache, MySQL, PHP).</p>
<p>There are certain reasons why these stacks evolved. But don’t assume these are the rules. You can use a MongoDB database in your Java project. You can use MySQL in your Node.js. You might not have found as many tutorials, but it's your requirements that should determine the database type &amp; not the language.</p>
<h2 id="heading-understanding-the-tradeoff">Understanding the Tradeoff</h2>
<p>Let's now understand the basic tradeoffs we need to deal with while making the DB decision.</p>
<p>The reason that we have many database options available today is due to the CAP Theorem. CAP stands for <strong>Consistency</strong>, <strong>Availability</strong>, and<strong> Partition tolerance</strong>.</p>
<p><strong>Consistency </strong> means that any read request will return the most recent write.</p>
<p><strong>Availability </strong> means all (non-failing) nodes are available for queries &amp; must respond in a reasonable amount of time.</p>
<p><strong>Partition Tolerance</strong> means that the system will continue to work despite node failures.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650698672357/v-5oEbWq3.png" alt="image.png" /></p>
<p>Only two of these 3 requirements can be fulfilled at any given time. If you're building a distributed app then partition tolerance is a must. So the choice remains whether we want our database to be highly available or highly consistent.</p>
<h2 id="heading-structure-of-data">Structure of Data</h2>
<p>If your data needs to be structured or there is a relation between different types of data that you're going to keep and at the same time you want strict data integrity then a relational database should be a better choice for you.</p>
<p>For example, let's say we are making a student management application where we need to store the information of certain courses and every course needs to be taken by one or more students. In this case, we can create 2 tables (<code>Students</code> and <code>Courses</code>) where the value in the <code>Student ID</code> column inside the <code>Courses</code> table points to rows in the <code>Students</code> table by the value of their <code>ID</code> column.</p>
<p>Apart from this if you want your DB to be <a target="_blank" href="https://en.wikipedia.org/wiki/ACID">ACID</a> compliant for example in cases when you're handling payments and transactions in your application then in that case too you should prefer the SQL based databases because the counterpart i.e the NoSQL database offers weak consistency.</p>
<blockquote>
<p>ACID compliance protects the integrity of your data by defining exactly what a transaction is and how it interacts with your database. It avoids database tables from becoming out-of-sync, which is super important for financial transactions. ACID compliance guarantees the validity of transactions even in failures, disastrous events, and more.</p>
</blockquote>
<p>On the other hand, if your data requirements aren’t clear or if your data is unstructured, NoSQL may be your best choice.</p>
<p>The data you store in a NoSQL database does not need a predefined schema. This provides much more flexibility and less upfront planning when managing your database.</p>
<p>A NoSQL database is a much better fit to store data like article content, social media posts, sensor data, and other types of unstructured data that won’t fit neatly into a table. NoSQL databases were built with flexibility and scalability in mind and follow the BASE consistency model, which means:</p>
<h4 id="heading-basic-availability">Basic Availability</h4>
<p>This means that while the database guarantees the availability of the data, the database may fail to obtain the requested data, or the data may be in a changing or inconsistent state.</p>
<h4 id="heading-soft-state">Soft state</h4>
<p>The state of the database can be changing over time.</p>
<h4 id="heading-eventual-consistency">Eventual consistency</h4>
<p>The database will eventually become consistent, and data will propagate everywhere at some point in the future.</p>
<p>The structure of your data is the most important factor in deciding whether to use a SQL or NoSQL database, so put a lot of thought into this before making a decision.</p>
<h2 id="heading-query-patterns">Query Patterns</h2>
<p>The next factor to consider is how you’ll query your data. This is one of the main ways to find the best database for your use case</p>
<p>Do you need retrieval by a single key, or by various other parameters? Do you also need a fuzzy search on the data?</p>
<ul>
<li><p>Use Non-Relational databases if you are going to fetch data by key, then all you need is a key-value store (e.g. DynamoDB).</p>
</li>
<li><p>On the other hand, if you will require to query many different fields you can choose both Relational DB (e.g.MySQL) or Document DB (e.g.MongoDB). </p>
</li>
<li><p>In case you are looking for fuzzy search query capabilities (free text search), then search engines like Elasticsearch(Which also comes under NoSQL DBs) are the best fit.</p>
</li>
<li><p>But in case your data is nicely structured and organized, it is very efficient to query your data with a SQL database.</p>
</li>
</ul>
<blockquote>
<p>SQL is a popular query language that has been around for over 50 years now, so it’s highly mature and well-known. It efficiently executes queries and retrieves using JOINs and edits data quickly. It’s very lightweight and declarative.</p>
</blockquote>
<h2 id="heading-consistency">Consistency</h2>
<p>Is strong consistency required (read after write) or eventual consistency is OK?</p>
<p>In case you need to read your data right after your write operation (i.e. strong consistency) then a Relational database (e.g. MySQL) is usually more suited than a Non-Relational Database (e.g.MongoDB).</p>
<h2 id="heading-performance-andamp-scaling">Performance &amp; Scaling</h2>
<p>All databases' performance degrades as the amount of read/write traffic increases. This is the time when optimizations such as indexing your data and scaling your DB come into the picture.</p>
<p>Performance depends on various factors but the overall performance depends to a very large degree on choosing the right implementation for your use case.</p>
<p>SQL and NoSQL databases scale differently, so you’ll have to think about how your data set will grow in the future.</p>
<p>SQL databases scale vertically, meaning you’ll need to increase the capacity of a single server (increasing CPU, RAM, or SSD) to scale your database. SQL databases were designed to maintain the integrity of the data so they are best to run on a single server, hence they’re not easy to scale.</p>
<p>NoSQL databases are easy to scale horizontally, which means you can add more servers as your data grows. This is an advantage that NoSQL has over SQL.</p>
<p>This uncomplicated horizontal scaling nature of non-relational databases makes them superior to relational databases as far as availability is concerned.</p>
<p>The ability of NoSQL databases to scale horizontally has to do with the lack of structure of the data. Because NoSQL requires much less structure than SQL, each stored object is pretty much self-contained. Thus objects can be easily stored on multiple servers without having to be linked. This is not the case for SQL, where each table row and column needs to be related.</p>
<p>This is also the issue regarding performance and where SQL falls short is scaling. As a database grows in size and numbers, RDBMS as we have seen requires solutions in vertical scaling. This however comes at a significant cost. Although many commercial RDBMS products offer horizontal scaling, these can also be very expensive and even complex to implement.</p>
<p>If you predict you will face such an issue, then NoSQL is to be considered, as many of them were designed specifically to tackle these scale and performance issues.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we went through the multiple factors you should consider while selecting the type of database. In short, SQL databases provide great benefits for transactional data whose structure doesn’t change frequently (or at all) and where data integrity is paramount. It’s also best for fast analytical queries. NoSQL databases provide more flexibility and scalability, which makes them useful for rapid or iteration development.</p>
<p>Here's a small summary of what all we have discussed above:</p>
<h3 id="heading-reasons-to-use-an-sql-database">Reasons to use an SQL database</h3>
<ul>
<li>When you need ACID support</li>
<li>Your application requires high transactions</li>
<li>Data integrity is essential</li>
<li>You don’t anticipate a lot of changes in the schema</li>
</ul>
<h3 id="heading-reasons-to-use-a-nosql-database">Reasons to use a NoSQL database</h3>
<ul>
<li>You want to store large amounts of data with no structure</li>
<li>You keep getting Unrelated, indeterminate, or evolving data requirements</li>
<li>Speed and scalability are critical</li>
<li>When data integrity is not your top goal and you are concerned about the availability (&amp; eventual consistency will be good enough for your use case)</li>
</ul>
<p>I hope this helps you understand what you need to think about when selecting your database. What additional questions do you think about while selecting a database? Let me know your thoughts in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[SOLID Principles in Java]]></title><description><![CDATA[In software engineering, SOLID is an acronym for 5 design principles intended to make software designs more understandable, flexible, robust, and maintainable. Adopting these practices can contribute to avoiding code smells too.
The 5 SOLID principle...]]></description><link>https://apoorvtyagi.tech/solid-principles-in-java</link><guid isPermaLink="true">https://apoorvtyagi.tech/solid-principles-in-java</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[Java]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[best practices]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Wed, 26 Jan 2022 05:33:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/uEcSKKDB1pg/upload/v1643174801172/8Bckp4euO.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In software engineering, <strong>SOLID</strong> is an acronym for 5 <a target="_blank" href="https://principles.design/">design principles</a> intended to make software designs more understandable, flexible, robust, and maintainable. Adopting these practices can contribute to avoiding code smells too.</p>
<p>The 5 SOLID principles are:</p>
<ul>
<li><strong>S</strong> - The single-responsibility principle</li>
<li><strong>O</strong> - The open-closed principle</li>
<li><strong>L</strong> - The Liskov substitution principle</li>
<li><strong>I</strong> - The interface segregation principle</li>
<li><strong>D</strong> - The dependency inversion principle</li>
</ul>
<p>Although the SOLID principles apply to any programming language, in further section I will be explaining each of them with examples written specifically in JAVA.</p>
<h2 id="heading-single-responsibility-principle">Single Responsibility Principle</h2>
<p>This principle states that “<strong>a class should have only one reason to change</strong>” which means every class should have a single responsibility.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">details</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">price</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNewVehicle</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<p>Here the class has multiple reasons to change because the <code>Vehicle</code> class has three separate responsibilities: printing details, printing price, and adding a new vehicle to Database.</p>
<p>To achieve the goal of the single responsibility principle, we should implement a separate class that performs a single functionality only.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VehicleDetails</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">details</span><span class="hljs-params">()</span> </span>{}
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CalculateVehiclePrice</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">price</span><span class="hljs-params">()</span> </span>{}
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AddVehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNewVehicle</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<h2 id="heading-open-closed-principle">Open-Closed Principle</h2>
<p>This principle states that “<strong>software entities (classes etc.) should be open for extension, but closed for modification</strong>”. This means without modifying anything in a class, it should be extendable.</p>
<p>Let's understand this principle with an example of a notification service</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span></span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String medium)</span> </span>{
         <span class="hljs-keyword">if</span> (medium.equals(<span class="hljs-string">"email"</span>)) {}
    }
}
</code></pre>
<p>Here, if you want to introduce a new medium other than email, let's say send a notification to a mobile number then you need to modify the source code in NotificationService class.</p>
<p>So to overcome this you need to design your code in such a way that everyone can reuse your feature by extending it and if they need any customization they can extend the class and add their feature on top of it.</p>
<p>You can create a new interface like:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">NotificationService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String medium)</span></span>;
}
</code></pre>
<p>Email Notification:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String medium)</span></span>{
        <span class="hljs-comment">// write Logic using for sending email</span>
    }
}
</code></pre>
<p>Mobile Notification:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MobileNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String medium)</span></span>{
        <span class="hljs-comment">// write Logic using for sending notification via mobile</span>
    }
}
</code></pre>
<h2 id="heading-liskov-substitution-principle">Liskov Substitution Principle</h2>
<p>This principle states that “<strong>derived classes must be able to substitute for their base classes</strong>”. In other words, if class A is a child of class B, then we should be able to replace B with A without interrupting the current behavior of the program.</p>
<p>Consider an example of a square class derived from Rectangle base class:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> height;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> width;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setHeight</span><span class="hljs-params">(<span class="hljs-keyword">double</span> h)</span> </span>{ height = h; }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setWidht</span><span class="hljs-params">(<span class="hljs-keyword">double</span> w)</span> </span>{ width = w; }
}
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Rectangle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setHeight</span><span class="hljs-params">(<span class="hljs-keyword">double</span> h)</span> </span>{
        <span class="hljs-keyword">super</span>.setHeight(h);
        <span class="hljs-keyword">super</span>.setWidth(h);
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setWidth</span><span class="hljs-params">(<span class="hljs-keyword">double</span> w)</span> </span>{
        <span class="hljs-keyword">super</span>.setHeight(w);
        <span class="hljs-keyword">super</span>.setWidth(w);
    }
}
</code></pre>
<p>In the <code>Rectangle</code> class, setting width and height seems perfectly logical. However, in the square class, the SetWidth() and SetHeight() don't make sense because setting one would change the other to match it. </p>
<p>In this case, Square fails the Liskov substitution test because you cannot replace the Rectangle base class with its derived class Square. The Square class has extra constraints, i.e., the height and width must be the same. Therefore, substituting Rectangle with Square class may result in unexpected behavior.</p>
<h2 id="heading-interface-segregation-principle">Interface Segregation Principle</h2>
<p>This principle applies to Interfaces and it is similar to the single responsibility principle. It states that “<strong> a client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.</strong>“.</p>
<p>Let's understand this by the example of a vehicle interface:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refuel</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openDoors</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>Let's say we now create a <code>Bike</code> class using this Vehicle interface</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bike</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refuel</span><span class="hljs-params">()</span> </span>{}

    <span class="hljs-comment">// Can not be implemented</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openDoors</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<p>Since Bike doesn't have doors we can't implement the last function. </p>
<p>To fix this, it is recommended to break down the interfaces into small multiple, interfaces so that no class is forced to implement any interface or methods, that it does not need.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refuel</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Doors</span></span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openDoors</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>Creating two classes - <code>Car</code> and <code>Bike</code></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bike</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refuel</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Vehicle</span>, <span class="hljs-title">Door</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refuel</span><span class="hljs-params">()</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openDoors</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<h2 id="heading-dependency-inversion-principle">Dependency Inversion Principle</h2>
<p>The Dependency Inversion Principle (DIP) states that "<strong>entities must depend on abstractions (abstract classes and interfaces), and not on concrete implementations (classes). Also, the high-level module must not depend on the low-level module, but both should depend on abstractions</strong>".</p>
<p>Suppose there is a  book store that enables customers to put their favorite books on a particular shelf.</p>
<p>In order to implement this functionality, we create a <code>Book</code> class and a <code>Shelf</code> class. The Book class will allow users to see reviews of each book they store on the shelves. The Shelf class will let them add a book to their shelf. For example,</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">seeReviews</span><span class="hljs-params">()</span> </span>{}
}


<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Shelf</span> </span>{
     Book book;
     <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">addBook</span><span class="hljs-params">(Book book)</span> </span>{}
}
</code></pre>
<p>Everything looks fine, but as the high-level <code>Shelf</code> class depends on the low-level <code>Book</code>, the above code violates the Dependency Inversion Principle. This becomes clear when the store asks us to enable customers to add their own reviews to the shelves, too. In order to fulfill the demand, we create a new <code>UserReview</code> class:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserReview</span></span>{
     <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">seeReviews</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<p>Now, we should modify the Shelf class so that it can accept User Reviews, too. However, this would clearly break the Open/Closed Principle too.</p>
<p>The solution is to create an abstraction layer for the lower-level classes (Book and UserReview). We’ll do so by introducing the Product interface, both classes will implement it. For example, the below code demonstrates the concept.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Product</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">seeReviews</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Product</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">seeReviews</span><span class="hljs-params">()</span> </span>{}
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserReview</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Product</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">seeReviews</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<p>Now, the Shelf can reference the Product interface instead of its implementations (Book and UserReview). The refactored code also allows us to later introduce new product types (for instance, Magazine) that customers can put on their shelves, too.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Shelf</span> </span>{
    Product product;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">addProduct</span><span class="hljs-params">(Product product)</span> </span>{}
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">customizeShelf</span><span class="hljs-params">()</span> </span>{}
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you were presented with the five principles of the SOLID Code. Adhering to SOLID principles can make your project, extendable, easily modifiable, well tested, with fewer complications.</p>
<h2 id="heading-other-articles-you-might-like">Other Articles You Might Like</h2>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/introduction-to-asynchronous-processing-and-message-queues">Introduction to Asynchronous Processing and Message Queues</a> - How to handle complex communication between a client and a server using message queues?</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment">Generating unique IDs in a Large scale Distributed environment</a> - A decent way to generate unique IDs across a distributed system that could also be used as the primary keys in the MySQL tables.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/javascript-clean-code-tips-and-good-practices">Javascript Clean Code Tips &amp; Good Practices</a> -15 tips I follow for writing better Javascript code.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/cool-python-snippets-that-will-blow-your-mind">Five++ cool Python snippets that will blow your mind🤯</a> - Few clever yet useful tricks and tips that will surely make you think hard.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/welcome-to-the-world-of-nft">Welcome to the world of "NFTs"</a> - Learn about what are NFTs and Why are they suddenly becoming the next big thing.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Message Queues and Asynchronous Processing]]></title><description><![CDATA[Introduction
In a client-server architecture, the client can request a job to be done from the server by sending messages to the server.
Handling this communication can increase in complexity when you begin to manage the rate at which messages are se...]]></description><link>https://apoorvtyagi.tech/introduction-to-asynchronous-processing-and-message-queues</link><guid isPermaLink="true">https://apoorvtyagi.tech/introduction-to-asynchronous-processing-and-message-queues</guid><category><![CDATA[distributed system]]></category><category><![CDATA[message queue]]></category><category><![CDATA[asynchronous]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Fri, 31 Dec 2021 05:55:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1640532738802/x8MHKW2HU.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In a client-server architecture, the client can request a job to be done from the server by sending messages to the server.</p>
<p>Handling this communication can increase in complexity when you begin to manage the rate at which messages are sent, the number of requests a server can handle, or the response time that the client demands.</p>
<p>In this blog, we'll see one way to handle this intricacy.</p>
<h2 id="heading-what-is-synchronous-processing">What is Synchronous Processing?</h2>
<p>In synchronous processing, a client sends a request to the server and waits for the server to complete its job and send back the response before the client can resume doing any other work.</p>
<p>This process is often referred to as a <em>blocking</em> request, as the client gets blocked from doing any other work until a response is received.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640532456293/NNIoKI1h2.png" alt="image.png" /></p>
<h2 id="heading-what-is-asynchronous-processing">What is Asynchronous Processing?</h2>
<p>Asynchronous processing is the exact opposite of synchronous processing. Here, the client doesn't wait for a response after sending a request to the server and continues doing any other work.</p>
<p>This process is referred to as a <em>non-blocking</em> request, as the execution thread of the client is not blocked. This allows systems to scale as more work can be done in a given amount of time.</p>
<h2 id="heading-synchronous-vs-asynchronous-processing">Synchronous vs Asynchronous Processing</h2>
<ul>
<li><p>Synchronous requests block the execution thread of the client, forcing them to wait for the response to come before they can perform another action. On the other hand, asynchronous requests do not block and allow for more work to be done in a given time.</p>
</li>
<li><p>Since we do not know how much time the request will take, it is difficult to build responsive applications with synchronous processing. The more blocking operations, the slower the system becomes. With asynchronous processing, response time is quicker as the client does not have to wait for the request.</p>
</li>
<li><p>Fault tolerance of asynchronous processing is higher than that of synchronous processing, as it is easy to build a retry mechanism when a request fails.</p>
</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640532560708/lA0pdjuge.png" alt="image.png" /></p>
</blockquote>
<h2 id="heading-what-are-message-queues">What are Message Queues?</h2>
<p>A message queue is a component that buffers requests from one service and broadcasts them asynchronously to another service.</p>
<p>Here, clients are the message producers, who send request messages to the queue instead of any server. They get an acknowledgment when the message is added to the queue, which enables them to continue with their other jobs without having to wait for the server.</p>
<p>Servers are known as message consumers and are served these messages from the queue based on the number of requests they can serve at any given time. This continues until all the messages in the queue have been served.</p>
<p>The two most common messaging queues are — <a target="_blank" href="https://www.rabbitmq.com/">RabbitMQ</a> and <a target="_blank" href="https://kafka.apache.org/">Kafka</a>.</p>
<h2 id="heading-structure-of-message-queues">Structure of Message Queues</h2>
<p>A message queue is primarily a broker of messages between message producers and message consumers.</p>
<p>Each distinct entity in the messaging queue setup (producers, consumers, and queue) has a responsibility and they're decoupled from each other as much as possible.</p>
<p>The only contract between all entities is the messages for which the message queue facilitates the movement from producers to consumers.</p>
<p>In the following sections, we will discuss the responsibilities of each component and look at the various modes with which the message queue delivers a message to consumers.</p>
<h3 id="heading-message-producers">Message Producers</h3>
<p>Message producers initiate the asynchronous processing request. Producers have a responsibility to generate a valid message and publish it to the message queue. Messages submitted to the queue are then queued up and delivered to consumers to be processed asynchronously.</p>
<p>Producers communicate with message queues using the Advanced Message Queuing Protocol (AMQP).</p>
<h3 id="heading-message-brokers">Message Brokers</h3>
<p>A message broker is simply just a queue. You can even implement a simple broker programmatically that buffers messages and sends them to consumers as and when needed.</p>
<p>Message brokers are the actual decoupling elements in the setup, sitting between and managing the process of communication between producers and consumers.</p>
<p>Because of their simplicity, brokers are optimized for high concurrency and throughput.</p>
<p>It is important to note that adding message brokers introduces an extra layer of complexity into your infrastructure and requires you to scale them as well. Brokers also have specific requirements and limitations when it comes to scalability.</p>
<h3 id="heading-message-consumers">Message Consumers</h3>
<p>The main responsibility of consumers is to receive and process messages from the queue.</p>
<p>Most consumers are API services that perform that actual asynchronous processing.</p>
<p>Consumers can be implemented in different application languages or technologies and maintained independently from other components.</p>
<p>To achieve decoupling, consumers should know nothing about the producers. The only contract that should exist between the two is valid messages from the queue.</p>
<p>When properly decoupled, consumers can serve as independent service layers that can be used by both the message queue setup and other components in your infrastructure.</p>
<h2 id="heading-consumer-communication-strategies">Consumer Communication Strategies</h2>
<p>Message queues need to transmit messages down to consumers, depending on how application developers implement consumers, message queues have three distinct ways of delivering messages to the consumers:</p>
<ul>
<li><strong>Pull Model</strong></li>
</ul>
<p>In this model, the consumer periodically checks the status of the queue. This is done at a scheduled interval programmed on the side of the consumer.</p>
<p>If there are messages found in the queue, the consumer picks them up until there are no more messages left to process, or when the 'N' number of messages has been consumed. This 'N' can be configured on the message broker.</p>
<ul>
<li><strong>Push Model</strong></li>
</ul>
<p>Once a message is added, the consumer is notified and the message is then pushed down to it. Messages are pushed down to consumers at a rate at which the consumer can easily regulate.</p>
<ul>
<li><strong>Subscription Model</strong></li>
</ul>
<p>In this model, consumers can subscribe to a topic. This publisher publishes a message to a topic rather than a queue. Each consumer connected to the broker maintains its private queue to receive messages from topics.</p>
<p>After the consumers subscribe to the topics and when a message is published to that topic, the message is cloned for each subscriber and added to the consumer’s private queue.</p>
<h2 id="heading-comparing-different-message-brokers">Comparing Different Message Brokers</h2>
<p>As we have seen above, for asynchronous communication we usually need a message broker.</p>
<p>Below are the few considerations you have to look at when choosing a broker for managing your asynchronous operations:</p>
<ul>
<li><p><strong>Scale</strong>: The number of messages sent per second in the system</p>
</li>
<li><p><strong>Data Persistency</strong>: The capability to recover messages</p>
</li>
<li><p><strong>Consumer Capability</strong>: The capability to manage one-to-one / one-to-many consumers</p>
</li>
</ul>
<h3 id="heading-rabbitmq">RabbitMQ</h3>
<ul>
<li><p>Scale: Based on configuration and resources.</p>
</li>
<li><p>Persistency: Both persistent and transient messages are supported.</p>
</li>
<li><p>One-to-one vs One-to-many consumers: Both.</p>
</li>
</ul>
<p>RabbitMQ supports all major languages, including Python, Java, .NET, PHP, Ruby, JavaScript, Go, Swift, and more.</p>
<h3 id="heading-kafka">Kafka</h3>
<ul>
<li><p>Scale: Can send up to a million messages per second.</p>
</li>
<li><p>Persistency: Yes.</p>
</li>
<li><p>One-to-one vs One-to-many consumers: Only one-to-many</p>
</li>
</ul>
<p>Kafka has managed SaaS on both Azure and AWS. Kafka also supports all major languages, including Python, Java, C/C++, Clojure, .NET, PHP, Ruby, JavaScript, Go, Swift, and more.</p>
<h3 id="heading-redis">Redis</h3>
<ul>
<li><p>Scale: Can send up to a million messages per second.</p>
</li>
<li><p>Persistency: Not supported (it’s an in-memory database).</p>
</li>
<li><p>One-to-one vs One-to-many consumers: Both.</p>
</li>
</ul>
<p>Redis is a bit different from the other message brokers. Redis is an in-memory data store. Originally, Redis only supported one-to-one communication with consumers. However, since Redis 5.0 introduced the pub-sub, you can have one-to-many as another option.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this blog, we covered how asynchronous processing is advantageous over its counterparts and how a message queue helps us achieve asynchronous processing along with keeping the different entities in its setup decoupled from each other.</p>
<p>We also covered some basic characteristics of the most commonly used message brokers: Redis, Kafka, and RabbitMQ.</p>
<p>Here's a bit more instruction for selecting the right message broker to use according to different use cases:</p>
<p><strong>Short-lived Messages: Redis</strong></p>
<ul>
<li>Redis is good for short-lived messages where persistence isn’t required.</li>
</ul>
<p><strong>Large Amounts of Data: Kafka</strong></p>
<ul>
<li>Kafka is good for storing a large amount of data for long periods. Kafka is also ideal for one-to-many use cases where persistency is required.</li>
</ul>
<p><strong>Complex Routing: RabbitMQ</strong></p>
<ul>
<li>RabbitMQ is good for complex routing communication.</li>
</ul>
<hr />
<p>Happy coding! 💻</p>
<p>(If you find any doubts, updates, or corrections to improve this article, Feel free to share them in the comments) 😊</p>
<hr />
<h2 id="heading-other-articles-you-might-like">Other Articles You Might Like</h2>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment">Generating unique IDs in a Large scale Distributed environment</a> - A decent way to generate unique IDs across a distributed system that could also be used as the primary keys in the MySQL tables.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/javascript-clean-code-tips-and-good-practices">Javascript Clean Code Tips &amp; Good Practices</a> -15 tips I follow for writing better Javascript code.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/how-we-solved-cache-invalidation-in-kubernetes-with-a-headless-service">How we solved cache invalidation in Kubernetes with a headless service</a> - A clever way we engineered to solve one of the finest computer science problems.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/welcome-to-the-world-of-nft">Welcome to the world of "NFTs"</a> - Learn about what are NFTs and Why are they suddenly becoming the next big thing.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/creating-blockchain-python">What is Blockchain Technology? Learn by creating one</a> - Want to know how blockchain works?</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Building Microservices using Spring Boot + HarperDB and Deploying it on AWS]]></title><description><![CDATA[Introduction
In this article, you will learn how to use Spring Boot and HarperDB to create a microservice. Later on, you will also look at how to deploy the complete application on AWS Elastic Beanstalk.
You will be building an Employee Leave Managem...]]></description><link>https://apoorvtyagi.tech/building-microservices-using-spring-boot-harperdb-and-deploying-it-on-aws</link><guid isPermaLink="true">https://apoorvtyagi.tech/building-microservices-using-spring-boot-harperdb-and-deploying-it-on-aws</guid><category><![CDATA[Spring]]></category><category><![CDATA[Databases]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Java]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Thu, 30 Sep 2021 11:22:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629301317967/PQcdszihV.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In this article, you will learn how to use <strong>Spring Boot</strong> and <strong>HarperDB</strong> to create a microservice. Later on, you will also look at how to deploy the complete application on <strong>AWS Elastic Beanstalk</strong>.</p>
<p>You will be building an <strong>Employee Leave Management System</strong>. This application will be responsible for tracking the detailed record of employees' leaves. You will also be implementing the functionality to <strong>add</strong>, <strong>edit</strong>, and <strong>cancel</strong> leaves.</p>
<p>But first, let's get a basic understanding of microservices.</p>
<h2 id="heading-what-are-microservices">What are Microservices?</h2>
<p>Microservices are another design architecture for developing software. In this, the software is composed of small independent services that communicate over REST APIs.</p>
<p>Microservices architectures make applications easier to develop and scale. It also enables an organization to evolve its technology stack easily later on if required.</p>
<h2 id="heading-monolithic-vs-microservices">Monolithic vs. Microservices</h2>
<p>In monolithic architectures, all processes run as a single service, therefore, they are tightly coupled. This means that if one process goes down, the entire application will get affected leading to a single point of failure.</p>
<p>Also, enhancing or adding new features becomes more complicated as the code base grows. This complexity makes it difficult to experiment and implement new ideas.</p>
<p>In microservices architectures, an application is built by combining different components that run independently as a service. These services communicate over a well-defined interface of lightweight REST APIs. </p>
<p>Each service is responsible for performing a single task and because they run independently, each service can be updated, deployed, and scaled to meet the demand for specific functions of an application.</p>
<h2 id="heading-introducing-harperdb">Introducing HarperDB</h2>
<p>You are going to use HarperDB as your Database. HarperDB is a complete data management solution and distributed database with native SQL operations like join, order by, etc., and NoSQL schema-less or even API-based execution.</p>
<p>The most notable features of HarperDB are:</p>
<ul>
<li>It has one endpoint for all CRUD operations</li>
<li>Execute SQL queries on JSON data</li>
<li>Supports multiple plugins like ODBC, JDBC, Node-RED, etc.</li>
<li>It has both SQL and NoSQL support</li>
<li>Eliminates the need for an ORM(Object Relational Mapping) by returning the results as arrays of JSON</li>
<li>Executes complex and ACID-compliant SQL queries on JSON without any data duplication</li>
</ul>
<p>Looks interesting, doesn't it?</p>
<h2 id="heading-configure-harperdb-database-instance">Configure HarperDB Database Instance</h2>
<p>Let's now start with configuring the HarperDB instance:</p>
<ul>
<li><p>Go to https://studio.harperdb.io/sign-up</p>
</li>
<li><p>Fill out the form with your details</p>
</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627961313361/G6TC-OzKp.png" alt="image.png" /></p>
</blockquote>
<ul>
<li><p>Click Sign Up For Free</p>
</li>
<li><p>You will then receive an email that looks like this:</p>
</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627962632182/obcAU9L_s.png" alt="image.png" /></p>
</blockquote>
<ul>
<li>Click on Log into HarperDB studio</li>
</ul>
<h3 id="heading-creating-an-instance">Creating an Instance</h3>
<ul>
<li>Click on Create HarperDB Cloud Instance</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628949438521/avQWms2cJ.png" alt="2.png" /></p>
</blockquote>
<ul>
<li>Enter Your Credentials</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627962498958/Qg8EPmOvE.jpeg" alt="7b.jpg" /></p>
</blockquote>
<p><em>Note</em>: These credentials should NOT be confused with your Studio account. This is for the superuser you are creating on this database instance. The username should NOT be in the form of an email.</p>
<ul>
<li>Pick your instance specs. You can start with a free version and upgrade later as per your need.</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627961939022/wOiImcn_o.png" alt="4.png" /></p>
</blockquote>
<ul>
<li><p>Next, review your details and click Confirm Instance Details </p>
</li>
<li><p>Finally, Click on Add Instance</p>
</li>
</ul>
<p>In another 5 to 10 minutes your instance will be ready. You'll also receive an email as soon as it's done.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627963550885/_yDJol_e-.png" alt="image.png" /></p>
</blockquote>
<p><em>The instance URL that you receive is how you can access HarperDB with REST calls</em>.</p>
<p>Initially, your instance does not have any schemas or tables. So you need to create them first. </p>
<p>I chose <strong>Employee_Leaves</strong> as the name for my schema. However, you can use any other name for your schema and then click on the green checkmark to save it.</p>
<p>Next, you need to create tables. For the moment, you'll set up two tables <strong>Employee</strong> and <strong>Leaves</strong>, the first one is for storing all the employee details like names and employee Ids and the second one is to store the leaves of employees in the company.</p>
<p>Note that you do not need to add all the columns just yet, they will be added automatically when needed. For now, while creating a table you just have to provide a <em>hash_attribute</em> name. <strong>The hash attribute is used to uniquely identify each record</strong>. For both these tables, you can use <strong>ID</strong> as hash_attribute.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629208177815/jGN3lJmMn.png" alt="image.png" /></p>
</blockquote>
<h2 id="heading-creating-a-spring-boot-app">Creating a Spring Boot App</h2>
<p>To start with spring boot, you have to create a basic application from <a target="_blank" href="https://start.spring.io/">Spring.io</a>. </p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628867450018/hLnm-o3HF.png" alt="10.png" /></p>
</blockquote>
<p>Select <code>Maven</code> project and <code>Java</code> language. For the Spring Boot version, select 2.5.3. You will also have to add the Spring-boot-starter-web and Lombok dependency.</p>
<p>Optionally, fill in the project metadata. For instance, you can set group as <code>com.employee</code>, artifact &amp; name as <code>attendance</code>, package as <code>com.employee.attendance</code>, and finally enter a short description &amp; click on Generate.</p>
<p>Extract the downloaded project and open it in your favorite IDE.</p>
<p>Next, for accessing the HarperDB instance from your Spring Boot app you first have to download the <strong>CData JDBC Driver</strong> for HarperDB.</p>
<p>The CData JDBC driver allows the most straightforward way to connect to HarperDB from any Java-based application. It wraps and hides the complexity of accessing data and provides additional powerful security features, smart caching, batching, socket management, and more.</p>
<p>Let's see the steps for integrate this driver inside your application:</p>
<ul>
<li>Navigate to - <a target="_blank" href="https://studio.harperdb.io/resources/drivers">https://studio.harperdb.io/resources/drivers</a> and then click on download.</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628949467177/NEORjFZ-B.png" alt="8.png" /></p>
</blockquote>
<ul>
<li><p>Go back to your project root directory and create a new folder called <code>lib</code>
&amp; extract the zip file contents inside this folder.</p>
</li>
<li><p>Next, to import the external jar into your spring boot app, open the <code>pom.xml</code> file and add the following dependency in it:</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cdata.jdbc.harperdb<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>cdata.jdbc.harperdb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>system<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">systemPath</span>&gt;</span>${project.basedir}/lib/cdata.jdbc.harperdb.jar<span class="hljs-tag">&lt;/<span class="hljs-name">systemPath</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>Here, the <code>${project.basedir}</code>  refers to the path where your pom.xml is saved i.e your root directory. If you have the driver installed at any other path, you have to add its absolute path inside the <code>&lt;systemPath&gt;</code> Tag.</p>
<p>An important thing to note here is that you have to set the <code>&lt;scope&gt;</code> as <strong>system</strong> and also, inside the plugins set the <code>&lt;includeSystemScope&gt;</code> as <strong>true</strong>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">includeSystemScope</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">includeSystemScope</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
</code></pre>
<p>This has to be done since you are ultimately going to deploy this application on a server(AWS) and for a server to know about any external <strong>JAR</strong> files, these configurations are necessary.</p>
<p>Now, to establish a connection between your app and the HarperDB instance, create a new package and name it <code>service</code>. Inside this, make a new Java file called <code>ConnectionService.java</code> and add the following content to it:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.employee.attendance.service;

<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> java.sql.Connection;
<span class="hljs-keyword">import</span> java.sql.DriverManager;
<span class="hljs-keyword">import</span> java.sql.SQLException;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConnectionService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> Connection <span class="hljs-title">createConnection</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>{
        <span class="hljs-keyword">return</span> DriverManager.getConnection(<span class="hljs-string">"jdbc:harperdb:Server=https:xyz.harperdbcloud.com;User=admin;Password=1234;UseSSL=true;"</span>);
    }
}
</code></pre>
<blockquote>
<p><strong>@Service</strong> annotation is used with classes that provide some business functionalities</p>
</blockquote>
<p>Here, you are making the connection with the Database using the "Connection String" inside the <code>getConnection()</code> method available under the <code>DriverManager</code> class.</p>
<p>Alternatively, you can also prepare the connection options using a Properties object. Pass the Properties object to the DriverManager:</p>
<pre><code class="lang-java">Properties prop = <span class="hljs-keyword">new</span> Properties();
prop.setProperty(<span class="hljs-string">"Server"</span>,<span class="hljs-string">"https:xyz.harperdbcloud.com"</span>);
prop.setProperty(<span class="hljs-string">"User"</span>,<span class="hljs-string">"admin"</span>);
prop.setProperty(<span class="hljs-string">"Password"</span>,<span class="hljs-string">"1234"</span>);

Connection conn = DriverManager.getConnection(<span class="hljs-string">"jdbc:harperdb:"</span>,prop);
</code></pre>
<p>Replace the <strong>server</strong>, <strong>user</strong>, and <strong>password</strong> with your own credentials and you are good to go.</p>
<h2 id="heading-designing-rest-apis">Designing REST APIs</h2>
<p>Now that a connection has been successfully established between your app and HarperDB, let's begin with creating the Restful APIs.</p>
<p>First, create a new package called <code>controller</code>. Inside this, create a new class and name it <code>AttendanceController.java</code>.</p>
<p>A controller class is where you will expose all the endpoints of your microservices. These endpoints are what different microservices use to communicate with each other.</p>
<p>For this application, you will create 4 endpoints:</p>
<ul>
<li><p>GET <code>/api/get/all/leaves/{employeeId}</code> - To get all the leaves that a particular employee has applied so far.</p>
</li>
<li><p>POST <code>/api/add/leave</code> - To add a new leave for an employee.</p>
</li>
<li><p>PUT <code>/api/edit/leave</code> - To edit the date of an existing leave.</p>
</li>
<li><p>DELETE <code>/api/cancel/leave</code> - To delete an existing leave.</p>
</li>
</ul>
<p>Here's how the complete controller class will look after adding these 4 endpoints:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.employee.attendance.controller;

<span class="hljs-keyword">import</span> com.employee.attendance.dto.EmployeeDataDTO;
<span class="hljs-keyword">import</span> com.employee.attendance.dto.EmployeeEditDataDTO;
<span class="hljs-keyword">import</span> com.employee.attendance.service.AttendanceService;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;

<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AttendanceController</span> </span>{

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> AttendanceService service;

    <span class="hljs-meta">@GetMapping(value = "/api/get/all/leaves/{employeeId}")</span>
    <span class="hljs-keyword">public</span> List&lt;HashMap&lt;String, String&gt;&gt; getAllLeavesForEmployee(<span class="hljs-meta">@PathVariable</span> String employeeId) {
        <span class="hljs-keyword">return</span> service.getAllLeavesForEmployee(employeeId);
    }

    <span class="hljs-meta">@PostMapping(value = "/api/add/leave")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">addNewLeave</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> EmployeeDataDTO employeeData)</span> </span>{
        <span class="hljs-keyword">return</span> service.addNewLeaveForEmployee(employeeData);
    }

    <span class="hljs-meta">@PutMapping(value = "/api/edit/leave")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">editLeave</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> EmployeeEditDataDTO employeeEditData)</span> </span>{
        <span class="hljs-keyword">return</span> service.editLeaveForEmployee(employeeEditData);
    }

    <span class="hljs-meta">@DeleteMapping(value = "/api/cancel/leave")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">cancelLeave</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> EmployeeDataDTO employeeData)</span> </span>{
        <span class="hljs-keyword">return</span> service.cancelLeaveForEmployee(employeeData);
    }
}
</code></pre>
<p>Let us now create another class called <code>AttendanceService.java</code> in the <code>service</code> package that you created earlier. Inside this class, you will write all your business logic. So, let's implement all 4 methods which are mentioned in your controller:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.employee.attendance.service;

<span class="hljs-keyword">import</span> com.employee.attendance.dto.EmployeeDataDTO;
<span class="hljs-keyword">import</span> com.employee.attendance.dto.EmployeeEditDataDTO;
<span class="hljs-keyword">import</span> lombok.extern.slf4j.Slf4j;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> java.sql.*;
<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-meta">@Service</span>
<span class="hljs-meta">@Slf4j</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AttendanceService</span> </span>{

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> ConnectionService connectionService;

    <span class="hljs-keyword">public</span> List&lt;HashMap&lt;String, String&gt;&gt; getAllLeavesForEmployee(String empId) {
        log.info(<span class="hljs-string">"Getting all leaves for employee - {}"</span>,empId);
        List&lt;HashMap&lt;String, String&gt;&gt; resultList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
        <span class="hljs-keyword">try</span> {
            Connection conn = connectionService.createConnection();
            PreparedStatement statement = conn.prepareStatement(<span class="hljs-string">"Select * From Employee_Leaves.Leaves where empId = ?"</span>);
            statement.setString(<span class="hljs-number">1</span>,empId);
            ResultSet resultSet = statement.executeQuery();
            <span class="hljs-keyword">while</span> (resultSet.next()) {
                HashMap&lt;String, String&gt; result = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
                result.put(<span class="hljs-string">"date_of_apply"</span>,<span class="hljs-keyword">new</span> Date(Long.parseLong(resultSet.getString(<span class="hljs-string">"__createdtime__"</span>))).toString());
                result.put(<span class="hljs-string">"last_update_date"</span>,<span class="hljs-keyword">new</span> Date(Long.parseLong(resultSet.getString(<span class="hljs-string">"__updatedtime__"</span>))).toString());
                result.put(<span class="hljs-string">"leave_applied_for"</span>,resultSet.getString(<span class="hljs-string">"date"</span>));
                result.put(<span class="hljs-string">"employee_id"</span>,resultSet.getString(<span class="hljs-string">"empId"</span>));
                resultList.add(result);
            }
            conn.close();
        } <span class="hljs-keyword">catch</span> (Exception e){
            log.error(<span class="hljs-string">"Error occurred"</span>, e);
            HashMap&lt;String, String&gt; result = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
            result.put(<span class="hljs-string">"Error"</span>,e.getMessage());
            resultList.add(result);
        }
        <span class="hljs-keyword">return</span> resultList;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">addNewLeaveForEmployee</span><span class="hljs-params">(EmployeeDataDTO employeeData)</span> </span>{
        log.info(<span class="hljs-string">"Inserting new leave for employee - {}"</span>,employeeData.getEmployeeId());
        HashMap&lt;String, String&gt; result = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
        <span class="hljs-keyword">try</span> {
            Connection conn = connectionService.createConnection();
            PreparedStatement statement = conn.prepareStatement(<span class="hljs-string">"INSERT INTO Employee_Leaves.Leaves (date, empId) VALUES (?,?)"</span>);
            statement.setString(<span class="hljs-number">1</span>, employeeData.getDate());
            statement.setString(<span class="hljs-number">2</span>, employeeData.getEmployeeId());
            <span class="hljs-keyword">int</span> count = statement.executeUpdate();
            <span class="hljs-keyword">if</span>(count&gt;<span class="hljs-number">0</span>) {
                result.put(<span class="hljs-string">"Message"</span>, <span class="hljs-string">"Success"</span>);
                result.put(<span class="hljs-string">"Affected rows"</span>, String.valueOf(count));
            }
            conn.close();
        } <span class="hljs-keyword">catch</span> (Exception e){
            log.error(<span class="hljs-string">"Error occurred"</span>, e);
            result.put(<span class="hljs-string">"Error"</span>,e.getMessage());
        }
        <span class="hljs-keyword">return</span> result;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">editLeaveForEmployee</span><span class="hljs-params">(EmployeeEditDataDTO employeeEditData)</span> </span>{
        log.info(<span class="hljs-string">"Updating leave for employee - {}"</span>,employeeEditData.getEmployeeId());
        HashMap&lt;String, String&gt; result = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
        <span class="hljs-keyword">try</span> {
            Connection conn = connectionService.createConnection();
            PreparedStatement statement = conn.prepareStatement(<span class="hljs-string">"UPDATE Employee_Leaves.Leaves SET date = ? WHERE empId=? and date = ?"</span>);
            statement.setString(<span class="hljs-number">1</span>, employeeEditData.getNewDate());
            statement.setString(<span class="hljs-number">2</span>, employeeEditData.getEmployeeId());
            statement.setString(<span class="hljs-number">3</span>, employeeEditData.getPreviousDate());
            <span class="hljs-keyword">int</span> count = statement.executeUpdate();
            <span class="hljs-keyword">if</span>(count&gt;<span class="hljs-number">0</span>) {
                result.put(<span class="hljs-string">"Message"</span>, <span class="hljs-string">"Success"</span>);
                result.put(<span class="hljs-string">"Affected rows"</span>, String.valueOf(count));
            }
            conn.close();
        } <span class="hljs-keyword">catch</span> (Exception e){
            log.error(<span class="hljs-string">"Error occurred"</span>, e);
            result.put(<span class="hljs-string">"Error"</span>,e.getMessage());
        }
        <span class="hljs-keyword">return</span> result;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> HashMap&lt;String, String&gt; <span class="hljs-title">cancelLeaveForEmployee</span><span class="hljs-params">(EmployeeDataDTO employeeData)</span> </span>{
        log.info(<span class="hljs-string">"Cancelling leave for employee - {}"</span>,employeeData.getEmployeeId());
        HashMap&lt;String, String&gt; result = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
        <span class="hljs-keyword">try</span> {
            Connection conn = connectionService.createConnection();
            PreparedStatement statement = conn.prepareStatement(<span class="hljs-string">"DELETE FROM Employee_Leaves.Leaves WHERE empId = ? and date = ?"</span>);
            statement.setString(<span class="hljs-number">1</span>, employeeData.getEmployeeId());
            statement.setString(<span class="hljs-number">2</span>, employeeData.getDate());
            <span class="hljs-keyword">int</span> count = statement.executeUpdate();
            <span class="hljs-keyword">if</span>(count&gt;<span class="hljs-number">0</span>) {
                result.put(<span class="hljs-string">"Message"</span>, <span class="hljs-string">"Success"</span>);
                result.put(<span class="hljs-string">"Affected rows"</span>, String.valueOf(count));
            }
            conn.close();
        } <span class="hljs-keyword">catch</span> (Exception e){
            log.error(<span class="hljs-string">"Error occurred"</span>, e);
            result.put(<span class="hljs-string">"Error"</span>,e.getMessage());
        }
        <span class="hljs-keyword">return</span> result;
    }
}
</code></pre>
<p>With that done, let's understand what each of these four functions is used for:</p>
<ul>
<li><code>getAllLeavesForEmployee()</code>.</li>
</ul>
<p>It will be responsible for fetching all the leaves for a particular employee from the <code>Leaves</code> table. You are simply establishing a connection and then querying the <strong>Leaves</strong> table based on employee Id.</p>
<ul>
<li><code>addNewLeaveForEmployee()</code></li>
</ul>
<p>Whenever an employee needs to apply for a leave, this function will be invoked which will take an Object of <code>EmployeeDataDTO</code> class and will be adding a new leave inside the <code>Leave</code> table of your database.</p>
<ul>
<li><code>editLeaveForEmployee()</code></li>
</ul>
<p>If in case an employee wants to change the date for which leave has been applied before, the <code>editLeaveForEmployee()</code> function will be responsible for modifying that in your Database.</p>
<ul>
<li><code>cancelLeaveForEmployee()</code></li>
</ul>
<p>It will simply cancel a particular leave for an employee i.e. Delete the row from the table. This function also takes the object of the <code>EmployeeDataDTO</code> class as its parameters.</p>
<p>Next thing is to understand the use of <code>EmployeeDataDTO</code> and <code>EmployeeEditDataDTO</code> classes. </p>
<p>These two classes will act as your Data Transfer Objects or simply DTOs. They will store the data which you will pass in the API request body &amp; carry that to the service for processing via the controller class.</p>
<p>To generate these Java files, create a new package called <code>dto</code> and add two files in it, one will be <code>EmployeeDataDTO.java</code> and another one will be <code>EmployeeEditDataDTO.java</code>.</p>
<p>Here's the content <code>EmployeeDataDTO.java</code> will hold:</p>
<ul>
<li>Employee Id</li>
<li>Date for which leave is being applied</li>
</ul>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.employee.attendance.dto;

<span class="hljs-keyword">import</span> lombok.Data;

<span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmployeeDataDTO</span> </span>{
    <span class="hljs-keyword">private</span> String employeeId;
    <span class="hljs-keyword">private</span> String date;
}
</code></pre>
<p>And <code>EmployeeEditDataDTO.java</code> will have the following properties:</p>
<ul>
<li>Employee Id</li>
<li>Previous Date which user wants to edit</li>
<li>New Date for Leave</li>
</ul>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.employee.attendance.dto;

<span class="hljs-keyword">import</span> lombok.Data;

<span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmployeeEditDataDTO</span> </span>{
    <span class="hljs-keyword">private</span> String employeeId;
    <span class="hljs-keyword">private</span> String previousDate;
    <span class="hljs-keyword">private</span> String newDate;
}
</code></pre>
<blockquote>
<p><code>@Data</code> is a useful annotation that bundles the features of <code>@ToString</code>, <code>@EqualsAndHashCode</code>, <code>@Getter</code> / <code>@Setter</code>. It is available under <strong>Lombok</strong> dependency.</p>
</blockquote>
<h3 id="heading-testing-the-endpoints">Testing the Endpoints</h3>
<p>I have manually inserted some initial data into the database tables (by clicking the '<strong>+</strong>' sign on the top right of the table) for testing purposes:</p>
<ul>
<li>Table <strong>Employee</strong> </li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629567520359/2s3QD04W7c.png" alt="EmployeeData.png" /></p>
</blockquote>
<ul>
<li>Table <strong>Leave</strong> </li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629567534131/OtLR96yhT.png" alt="LeaveData.png" /></p>
</blockquote>
<p>Now you have to hit those 4 API endpoints to check if everything is working as expected. </p>
<p>For this, you must download the Postman app in your local development environment from their <a target="_blank" href="https://www.postman.com/downloads/">official downloads</a>.</p>
<p>After downloading and successfully installing it, open the app and run your Spring Boot application.</p>
<p>In case you are using an IDE like IntelliJ IDEA, you can run the Spring Boot application by following these instructions:</p>
<ul>
<li>Click on <code>Add Configuration</code> from the top menu bar.</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629819101193/MYBHdYvM7r.png" alt="IntelliJ_Start.png" /></p>
</blockquote>
<ul>
<li>A new dialog box will open, click on <code>Add new run configurations</code> and select <code>Maven</code> from the dropdown.</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629819195835/O9rIHLBr1.png" alt="Intellij_2.png" /></p>
</blockquote>
<ul>
<li>Give your run configuration a name. The working directory will automatically get picked. You just have to put the command <code>spring-boot:run</code> inside the command line and then click Apply and OK and finally run the app.</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629819352596/Pa1cWbtj-.png" alt="IntelliJ_3.png" /></p>
</blockquote>
<p>The next thing you have to do is to hit the endpoints via the Postman app:</p>
<ul>
<li><code>/api/get/all/leaves/{employeeId}</code></li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025088432/AMc5bdmIX.png" alt="p1.png" /></p>
</blockquote>
<ul>
<li><code>/api/add/leave</code></li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025148671/URar5VLyC.png" alt="p3.png" /></p>
</blockquote>
<p>To check if the leave got added successfully or not, let's call the <code>api/get/all/leaves</code> API again which you used in the first step:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025268282/XUdyOFxDX.png" alt="p4.png" /></p>
</blockquote>
<p>As you can see in the response, the employee whose ID is 1 now has two leaves. This same has been reflected in the Database:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629208559249/sJKFsK6x6.png" alt="image.png" /></p>
</blockquote>
<ul>
<li><code>/api/edit/leave</code></li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025546222/fHKJniZaX.png" alt="p5.png" /></p>
</blockquote>
<p>Again, let's check if the previous date has been modified or not, you will get:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025558307/aFRNBYKGF.png" alt="p6.png" /></p>
</blockquote>
<p>This means that the edit functionality is also working fine.</p>
<ul>
<li><code>/api/cancel/leave</code></li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025583725/KnYNGh0Si.png" alt="p7.png" /></p>
</blockquote>
<p>And now hitting the GET leaves API, you should only get one entry in response:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629025595391/prSYQC5h6.png" alt="p8.png" /></p>
</blockquote>
<p>So, all your endpoints are working as expected in the local development environment. Let's move forward to see how you can deploy these APIs to the server.</p>
<h2 id="heading-creating-a-jar-file">Creating a JAR file</h2>
<p>A JAR(Java Archive) is a package file format used to cluster together all the Java class files and associated metadata and resources (text, images, etc.) into one file to distribute application software or libraries on the Java platform.</p>
<p>In simple terms, a JAR file contains a compressed version of .class files, audio files, image files, or other directories.</p>
<p>To create a JAR file, make sure Maven is installed in your local development environment. If not, follow the below steps to configure maven (In Windows OS):</p>
<ul>
<li><p>Navigate to the official <a target="_blank" href="https://maven.apache.org/download.cgi">Maven website</a> and download the Maven zip file. For example: apache-maven-3.8.2-src.zip.</p>
</li>
<li><p>Unzip the contents and copy the path of the <code>bin</code> folder inside.</p>
</li>
<li><p>Open your System Environment Variables from the control panel, find the <code>PATH</code> variable then click on the <code>Edit</code> button. </p>
</li>
<li><p>In the "Edit environment variable" dialog, click on <code>New</code> and add the complete path of the <code>bin</code> folder that you just copied.</p>
</li>
<li><p>Finally, click on <code>OK</code>. To test the configuration, open a new command prompt and type <code>mvn –version</code>. If a version is visible to you that means the configurations are correct.</p>
</li>
</ul>
<blockquote>
<p>If you're using any other OS, you can find the installation steps for that on the official <a target="_blank" href="https://maven.apache.org/install.html">Maven website</a>. For more detailed steps, you can check out <a target="_blank" href="https://www.baeldung.com/install-maven-on-windows-linux-mac#installing-maven-on-linux">this article</a> as well.</p>
</blockquote>
<p>Next, to create a JAR file for your application run the command <code>mvn clean install</code> in your project's root directory.</p>
<p>A new folder with the name <strong>Target</strong> will be created. Inside this folder, you'll find your newly created JAR file.</p>
<p>Another way to create a JAR file is from your IDE. For instance, in Intellij you can navigate to the <strong>maven</strong> tab from the sidebar menu and double click <strong>Install</strong>.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629024765740/0QpDvlYH9.png" alt="11.png" /></p>
</blockquote>
<p>And here's how your complete project structure should look like by now:</p>
<pre><code>├── lib
├── src
├── target
└── pom.xml
</code></pre><p>Inside <code>src&gt;main&gt;java&gt;com&gt;employee&gt;attendance</code> you should have the following files and structure:</p>
<pre><code>├── controller
│   └── AttendanceController.java
├── dto
│   └── EmployeeDataDTO.java
│   └── EmployeeEditDataDTO.java
├── service
│   └── AttendanceService.java
│   └── ConnectionService.java
└── AttendanceApplication.java
</code></pre><h2 id="heading-deploying-the-application-to-aws">Deploying the application to AWS</h2>
<p>The final step would be to deploy your code to a server. In this section, you'll learn how you can deploy the application to AWS Elastic Beanstalk.</p>
<blockquote>
<p>Using <a target="_blank" href="https://aws.amazon.com/elasticbeanstalk/">Elastic Beanstalk</a>, you can easily deploy and manage applications in the AWS Cloud without worrying about the infrastructure that runs those applications. It reduces management complexity without restricting choice or control. You simply upload your application, and Elastic Beanstalk automatically handles the details of capacity provisioning, load balancing, scaling, and application health monitoring.</p>
</blockquote>
<h3 id="heading-creating-elastic-beanstalk-environment">Creating Elastic Beanstalk environment</h3>
<p>Once you are signed in to your <a target="_blank" href="https://aws.amazon.com/">AWS account</a>, go to the search panel at the top and type "Elastic Beanstalk," and click create a new application on the top right.</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628414450268/6WYLLQolG.png" alt="9.png" /></p>
</blockquote>
<p>It will ask for your:</p>
<ul>
<li>Application name</li>
<li>Application tags(Not mandatory)</li>
<li>Platform</li>
<li>Application code</li>
</ul>
<p>Enter your application name and optionally you can add up to 50 tags for the resources of your Elastic Beanstalk applications.</p>
<p>For the platform, select "Java" from the dropdown and it will automatically fill the "platform branch" and "version" on its own.</p>
<p>For the application code, select <strong>Upload your code</strong> and then choose the JAR file built in a previous step.</p>
<p>Review the configuration and launch the environment. As the application is being launched, you’ll see something similar to this on the environment dashboard:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629213207438/Kl4fFE555.png" alt="image.png" /></p>
</blockquote>
<p>Once the application resources get deployed and the environment has been created, you’ll notice the health of the application remains <strong>Severe</strong>. This is because the Spring Boot application still needs some configuration:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628414938862/NyToPx8NN.png" alt="image.png" /></p>
</blockquote>
<p>Let's look at how to solve it in the next section.</p>
<h3 id="heading-configuring-spring-boot-through-environment-variables">Configuring Spring Boot Through Environment Variables</h3>
<p>By default, Spring Boot applications listen on port 8080 whereas Elastic Beanstalk expects the application to listen on port 5000. </p>
<p>There are two ways to fix this error, either you have to change the port Elastic Beanstalk is configured to use, or change the port the Spring Boot application listens on. For this tutorial, you will change the port the Spring Boot application listens on as it is easier.</p>
<p>For this, you have to define the <strong>SERVER_PORT</strong> environment variable in the Elastic Beanstalk's environment and set its value to 5000.</p>
<ul>
<li><p>Click on the <strong>Configuration</strong> from the sidebar menu on your environment page.</p>
</li>
<li><p>On the Configuration page, you'll have software configuration, click on <strong>Edit</strong>:</p>
</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629213774936/vtKTvlq_4.png" alt="12.png" /></p>
</blockquote>
<ul>
<li><p>Next, you’ll see that there are already some environment variables set. They are set automatically by Elastic Beanstalk when it is configured to use the Java platform.</p>
</li>
<li><p>To modify the port that Spring Boot listens on, as mentioned above you need to add a new environment variable by the name <code>SERVER_PORT</code> with its value 5000.</p>
</li>
</ul>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629213878670/6wk-xbdys.png" alt="13.png" /></p>
</blockquote>
<p>Click on Apply and the configuration change will make the application restart. </p>
<p>After it restarts, it will pick up the new configuration through the environment variables. In about a minute, you’ll get a healthy application instance up and running.</p>
<h3 id="heading-testing-the-application-in-the-cloud">Testing the Application in the Cloud</h3>
<p>Once deployed successfully, you will get your application base URL. You can also access the same from the sidebar:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629214172635/IX4-BOGnI.png" alt="14.png" /></p>
</blockquote>
<p>Now replace the <code>localhost:8080</code> with this new URL and try to access one of your API endpoints:</p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629214523523/3MIQWQ3KO.png" alt="image.png" /></p>
</blockquote>
<p>And you can get the correct response. This means that the application has been deployed successfully.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With this, you come to the end of this tutorial. The purpose of this tutorial was to use Spring Boot and HarperDB to create microservices. You also looked at the step-by-step process of how you can deploy the same application to AWS.</p>
<p>Both Spring Boot and AWS are used extensively in the industry but HarperDB might be new for you. The reason for choosing HarperDB is because of its easy integration with the Spring Boot app along with the notable features that I have mentioned at the beginning of this article.</p>
<p>I hope you learned something new. In case you get stuck somewhere, please feel free to shoot your doubts in the comments.</p>
<p>Also, the complete source code of the application used in this tutorial can be found in this <a target="_blank" href="https://github.com/ApoorvTyagi/Spring-Harper">GitHub Repository</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Javascript Clean Code Tips & Good Practices]]></title><description><![CDATA[Code should be written in such a way that is self-explanatory, easy to understand, and easy to modify or extend for the new features. Because code is read more than it is written that's why so much emphasis is given to clean code.
The more readable o...]]></description><link>https://apoorvtyagi.tech/javascript-clean-code-tips-and-good-practices</link><guid isPermaLink="true">https://apoorvtyagi.tech/javascript-clean-code-tips-and-good-practices</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[clean code]]></category><category><![CDATA[best practices]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 22 Aug 2021 10:07:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629471994011/PRsCMmJ0-.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code should be written in such a way that is self-explanatory, easy to understand, and easy to modify or extend for the new features. Because code is read more than it is written that's why so much emphasis is given to clean code.</p>
<p>The more readable our source code is:</p>
<ul>
<li>The easier it is to maintain</li>
<li>The less time required to understand an implementation for a new developer</li>
<li>The easier it is to discover what code can be reused</li>
</ul>
<p>In this blog post, I will share some general clean coding principles that I've adopted over time as well as some JavaScript-specific clean code practices.</p>
<h2 id="0-naming">0. Naming</h2>
<p>Don't turn naming into a riddle game. <strong>Name your variables and functions in a way that they reveal the intention behind why they were created in the first place</strong>.</p>
<p>This way they become searchable and easier to understand if let's say a new developer joins the team.</p>
<blockquote>
<p>Only go for Shortening and abbreviating names when you want the next developer working on your code to guess what you were thinking about 😉 </p>
</blockquote>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> x = <span class="hljs-number">10</span>;

<span class="hljs-keyword">let</span> y = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();

<span class="hljs-keyword">if</span> (x &gt; <span class="hljs-number">30</span>) {
    <span class="hljs-comment">//...</span>
}

<span class="hljs-keyword">if</span> (y - x &gt;<span class="hljs-number">1990</span>) {
    <span class="hljs-comment">//...</span>
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> userAge = <span class="hljs-number">30</span>;

<span class="hljs-keyword">let</span> currentYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();

<span class="hljs-keyword">if</span> (userAge &gt; <span class="hljs-number">30</span>) {
    <span class="hljs-comment">//...</span>
}

<span class="hljs-keyword">if</span> (currentYear - userAge &gt;<span class="hljs-number">1990</span>) {
    <span class="hljs-comment">//...</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629479918874/E6RbSRvkE.png" alt="image.png" /></p>
<p>Also, don’t add extra unnecessary letters to the variable or functions names.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> nameValue;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">theProduct</span>(<span class="hljs-params"></span>);</span>
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> name;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">product</span>(<span class="hljs-params"></span>);</span>
</code></pre>
<h2 id="1-conditionals">1. Conditionals</h2>
<p><strong>Avoid negative conditionals</strong>. Negatives are just a bit harder to understand than positives.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (!userExist(user)) {
  <span class="hljs-comment">//...</span>
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (userExist(user)) {
  <span class="hljs-comment">//...</span>
}
</code></pre>
<h2 id="2-functions-should-do-one-thing">2. Functions should do one thing</h2>
<p><strong>The function should not have more than an average of 30 lines (excluding spaces and comments)</strong>. The smaller the function the better it is to understand and refactor. Try making sure your function is either modifying or querying something but not both.</p>
<h2 id="3-use-default-arguments">3. Use default arguments</h2>
<p>Use default arguments instead of short-circuiting or conditionals.</p>
<p><strong>Default arguments are often cleaner than short-circuiting</strong>. Remember that if you use them, your function will only provide default values for undefined arguments. Other <em>falsy</em> values such as '', "", false, null, 0, and NaN, will not be replaced by a default value.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserData</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-keyword">const</span> userName = userName || <span class="hljs-string">"Patrick Collision"</span>;
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserData</span>(<span class="hljs-params">name = <span class="hljs-string">"Patrick Collision"</span></span>) </span>{
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<h2 id="4-single-level-of-abstractionsla">4. Single Level of Abstraction(SLA)</h2>
<p>While writing any function, <strong>if you have more than one level of abstraction, your function is usually doing more than one thing</strong>. Dividing a bigger function into multiple functions leads to reusability and easier testing.</p>
<blockquote>
<p>Functions should do one thing. They should do it well. They should do it only. — Robert C. Martin</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629479806409/qJ0VeLUxO.png" alt="image.png" /></p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkSomething</span>(<span class="hljs-params">statement</span>) </span>{
  <span class="hljs-keyword">const</span> REGEXES = [
    <span class="hljs-comment">// ...</span>
  ];

  <span class="hljs-keyword">const</span> statements = statement.split(<span class="hljs-string">" "</span>);
  <span class="hljs-keyword">const</span> tokens = [];
  REGEXES.forEach(<span class="hljs-function"><span class="hljs-params">REGEX</span> =&gt;</span> {
    statements.forEach(<span class="hljs-function"><span class="hljs-params">statement</span> =&gt;</span> {
      <span class="hljs-comment">// ...</span>
    });
  });

  <span class="hljs-keyword">const</span> names= [];
  tokens.forEach(<span class="hljs-function"><span class="hljs-params">token</span> =&gt;</span> {
    <span class="hljs-comment">// lex...</span>
  });

  names.forEach(<span class="hljs-function"><span class="hljs-params">node</span> =&gt;</span> {
    <span class="hljs-comment">// parse...</span>
  });
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkSomething</span>(<span class="hljs-params">statement</span>) </span>{
  <span class="hljs-keyword">const</span> tokens = tokenize(statement);
  <span class="hljs-keyword">const</span> syntaxTree = parse(tokens);
  syntaxTree.forEach(<span class="hljs-function"><span class="hljs-params">node</span> =&gt;</span> {
    <span class="hljs-comment">// parse...</span>
  });
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenize</span>(<span class="hljs-params">code</span>) </span>{
  <span class="hljs-keyword">const</span> REGEXES = [
    <span class="hljs-comment">// ...</span>
  ];

  <span class="hljs-keyword">const</span> statements = code.split(<span class="hljs-string">" "</span>);
  <span class="hljs-keyword">const</span> tokens = [];
  REGEXES.forEach(<span class="hljs-function"><span class="hljs-params">REGEX</span> =&gt;</span> {
    statements.forEach(<span class="hljs-function"><span class="hljs-params">statement</span> =&gt;</span> {
      tokens.push(<span class="hljs-comment">/* ... */</span>);
    });
  });

  <span class="hljs-keyword">return</span> tokens;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parse</span>(<span class="hljs-params">tokens</span>) </span>{
  <span class="hljs-keyword">const</span> syntaxTree = [];
  tokens.forEach(<span class="hljs-function"><span class="hljs-params">token</span> =&gt;</span> {
    syntaxTree.push(<span class="hljs-comment">/* ... */</span>);
  });

  <span class="hljs-keyword">return</span> syntaxTree;
}
</code></pre>
<h2 id="5-dont-ignore-caught-errors">5. Don't ignore caught errors</h2>
<p>Doing nothing with a caught error doesn't give you the ability to fix or react to that particular error. </p>
<p>Logging the error to the console (console.log) isn't much better as oftentimes it can get lost among other things printed to the console. </p>
<p>If you wrap any bit of code in a try/catch it means you think an error may occur there and therefore you should have a plan for when it occurs.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">try</span> {
  functionThatMightThrow();
} <span class="hljs-keyword">catch</span> (error) {
  <span class="hljs-built_in">console</span>.log(error);
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">try</span> {
  functionThatMightThrow();
} <span class="hljs-keyword">catch</span> (error) {
  notifyUserOfError(error);   
  reportErrorToService(error);   
}
</code></pre>
<h2 id="6-minimize-comments">6. Minimize Comments</h2>
<p><strong>Only comment the part of the code that has business logic complexity</strong>.
Comments are not a requirement. Good code mostly documents itself.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hashing</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-comment">// The hash</span>
  <span class="hljs-keyword">let</span> hash = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// Length of string</span>
  <span class="hljs-keyword">const</span> length = data.length;

  <span class="hljs-comment">// Loop through every character in data</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
    <span class="hljs-comment">// Get character code.</span>
    <span class="hljs-keyword">const</span> char = data.charCodeAt(i);
    <span class="hljs-comment">// Make the hash</span>
    hash = (hash &lt;&lt; <span class="hljs-number">5</span>) - hash + char;
    <span class="hljs-comment">// Convert to 32-bit integer</span>
    hash &amp;= hash;
  }
}
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hashing</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">let</span> hash = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">const</span> length = data.length;

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
    <span class="hljs-keyword">const</span> char = data.charCodeAt(i);
    hash = (hash &lt;&lt; <span class="hljs-number">5</span>) - hash + char;

    <span class="hljs-comment">// Convert to 32-bit integer</span>
    hash &amp;= hash;
  }
}
</code></pre>
<blockquote>
<p>“Redundant comments are just places to collect lies and misinformation.” ― Robert C. Martin</p>
</blockquote>
<h2 id="7-remove-commented-code">7. Remove commented code</h2>
<p><strong>Don't leave commented out code in your codebase</strong>, Version control exists for a reason. Leave old code in your history. If you ever need them back, pick them up from your git history.</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript">doSomething();
<span class="hljs-comment">// doOtherStuff();</span>
<span class="hljs-comment">// doSomeMoreStuff();</span>
<span class="hljs-comment">// doSoMuchStuff();</span>
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript">doSomething();
</code></pre>
<h2 id="8-import-only-what-you-need">8. Import only what you need</h2>
<p>Destructuring was introduced with ES6. It makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can use this for any kind of object or module.</p>
<p>For instance, if you only require to <code>add()</code> and <code>subtract()</code> function from another module:</p>
<p><strong>Bad 👎</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> calculate = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./calculations'</span>)

calculate.add(<span class="hljs-number">4</span>,<span class="hljs-number">2</span>);
calculate.subtract(<span class="hljs-number">4</span>,<span class="hljs-number">2</span>);
</code></pre>
<p><strong>Good 👍</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { add, subtract } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./calculations'</span>)

add(<span class="hljs-number">4</span>,<span class="hljs-number">2</span>);
subtract(<span class="hljs-number">4</span>,<span class="hljs-number">2</span>);
</code></pre>
<p>It makes sense to only import the functions you need to use in your file instead of the whole module, and then access the specific functions from it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629479831245/hf55o5gIi.png" alt="image.png" /></p>
<h2 id="9-keep-function-arguments-3-or-less-ideally">9. Keep Function arguments 3 or less (ideally)</h2>
<p>Limiting the number of function parameters is really important because it makes testing your function easier. Having more than three parameters leads you to test tons of different cases with each separate argument.</p>
<p>1-3 arguments are the ideal case, anything above that should be avoided if possible. </p>
<blockquote>
<p>Usually, if you have more than three arguments then your function is trying to do too much. Which ultimately leads to the violation of the SRP(Single Responsibility Principle).</p>
</blockquote>
<h2 id="10-use-array-spreads-to-copy-arrays">10. Use array spreads to copy arrays.</h2>
<p>Bad 👎</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> len = items.length;
<span class="hljs-keyword">const</span> itemsCopy = [];
<span class="hljs-keyword">let</span> i;

<span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; len; i += <span class="hljs-number">1</span>) {
  itemsCopy[i] = items[i];
}
</code></pre>
<p>Good 👍</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> itemsCopy = [...items];
</code></pre>
<h2 id="11-write-linear-code">11. Write linear code</h2>
<p>Nested code is hard to understand. <strong>Always write the linear code as much as possible</strong>. It makes our code simple, clean, easy to read, and maintain, thus making developer life easier.</p>
<p>For Example, <strong>Using promises over callbacks can increase readability multiple times</strong>.</p>
<h2 id="12-use-eslint-and-prettier">12. Use ESLint and Prettier</h2>
<p>Always <strong>use ESLint and Prettier to enforce common coding styles across teams and developers</strong>. </p>
<p>Also try and use JavaScript's latest features to write code, like destructuring, spread operator, async-await, template literals, optional chaining, and more.</p>
<h2 id="13-use-proper-parentheses">13. Use proper parentheses</h2>
<p>When working with operators, enclose them in parentheses. The only exception is the standard arithmetic operators: +, -, and <em>* since their precedence is broadly understood. It is highly recommended to enclose /, </em>, and % in parentheses because their precedence can be ambiguous when they are used together.</p>
<p>This improves readability and clarifies the developer’s intention.</p>
<p>Bad 👎</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> foo = a &amp;&amp; b &lt; <span class="hljs-number">0</span> || c &gt; <span class="hljs-number">0</span> || d + <span class="hljs-number">1</span> === <span class="hljs-number">0</span>;

<span class="hljs-keyword">if</span> (a || b &amp;&amp; c) {
  <span class="hljs-keyword">return</span> d;
}
</code></pre>
<p>Good 👍</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> foo = (a &amp;&amp; b &lt; <span class="hljs-number">0</span>) || c &gt; <span class="hljs-number">0</span> || (d + <span class="hljs-number">1</span> === <span class="hljs-number">0</span>);

<span class="hljs-keyword">if</span> (a || (b &amp;&amp; c)) {
  <span class="hljs-keyword">return</span> d;
}
</code></pre>
<p>Make sure your code doesn't lead to situations like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629615495694/1NR4N-cND.png" alt="Bad.png" /></p>
<h2 id="14-return-early-from-functions">14. Return early from functions</h2>
<p>To avoid deep nesting of if-statements, always return a function's value as early as possible.</p>
<p>Bad 👎</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPercentage</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">if</span> (val &gt;= <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">if</span> (val &lt; <span class="hljs-number">100</span>) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }
}
</code></pre>
<p>Good 👍</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPercentage</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">if</span> (val &lt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }

  <span class="hljs-keyword">if</span> (val &gt; <span class="hljs-number">100</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }

  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p>This particular example can even improve further:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPercentage</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">var</span> isInRange = (val &gt;= <span class="hljs-number">0</span> &amp;&amp; val &lt;= <span class="hljs-number">100</span>);
  <span class="hljs-keyword">return</span> isInRange;
}
</code></pre>
<p>Similarly, the same thing can be applied to Loops as well.</p>
<p>Looping over large cycles can surely consume a lot of time. That is why you should always try to break out of a loop as early as possible. </p>
<h2 id="conclusion">Conclusion</h2>
<p>There’s a saying in the development community that you should always write your code like the next developer that comes after you is a serial killer.</p>
<p>Following this rule, I have shared 15 tips here that can (probably) save you from your fellow developers when they will look into your code.</p>
<p>If you find any updates or corrections to improve these 15 tips or want to add one of your own that you think can be helpful, please feel free to share them in the comments.</p>
<p>For further reading I would highly suggest you go through these 3 resources:</p>
<ul>
<li><a target="_blank" href="https://github.com/airbnb/javascript">Airbnb JS style guide</a></li>
<li><a target="_blank" href="https://google.github.io/styleguide/jsguide.html">Google JS style guide</a></li>
<li><a target="_blank" href="https://github.com/ryanmcdermott/clean-code-javascript">Javascript Clean Code</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[NanoID - A URL Friendly Unique Identifier]]></title><description><![CDATA[Introduction
In every software system, we need unique Ids to distinguish between several objects from one another. 
Recently, I wrote about the unique Id generation for a large scale distributed environment. In that article, we touched a little on UU...]]></description><link>https://apoorvtyagi.tech/nanoid-url-friendly-unique-id</link><guid isPermaLink="true">https://apoorvtyagi.tech/nanoid-url-friendly-unique-id</guid><category><![CDATA[distributed system]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[software development]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Mon, 26 Jul 2021 06:46:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627204670432/lYFaYy30zg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In every software system, we need unique Ids to distinguish between several objects from one another. </p>
<p>Recently, I wrote about the <a target="_blank" href="https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment">unique Id generation for a large scale distributed environment</a>. In that article, we touched a little on UUIDs. </p>
<p>In this blog post, I will share an alternative to UUIDs that can help you fit the requirements that UUIDs fulfills and overcomes some of their shortcomings as well.</p>
<h2 id="heading-introducing-nano-id">Introducing Nano ID</h2>
<p>It is a tiny, secure, URL-friendly, unique string ID generator.</p>
<ul>
<li><p><strong>Nano ID  has smaller size as compared to UUID</strong>. This size reduction impacts a lot. Making use of NanoID is easier for transferring information and storage space. In a large-scale system, these numbers can make a lot of difference.</p>
</li>
<li><p><strong>NanoID uses a cryptographically strong API which is a lot safer</strong> compared to Math.Random() which are <a target="_blank" href="https://franklinta.com/2014/08/31/predicting-the-next-math-random-in-java/">insecure</a>. These API modules use unpredictable hardware generated random identifiers.</p>
</li>
</ul>
<ul>
<li><p><strong>NanoID utilizes its very own "uniform formula" throughout the application</strong> of the ID generator instead of making use of an arbitrary <code>% alphabet</code> which is a popular mistake to make when coding an ID generator (The spread will not be even in some cases).</p>
</li>
<li><p><strong>NanoID uses a larger alphabet</strong> resulting in short but unique identifiers.</p>
</li>
<li><p><strong>NanoID permits designers to utilize personalized alphabets</strong>. This is another additional function of Nano ID. You can alter the literals or the dimension of the id as shown below (Specifying personalized letter as '1234567890ABCDEF' &amp; dimension of the Id as 10):</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { alphabet } <span class="hljs-keyword">from</span> <span class="hljs-string">'nanoid'</span>;
<span class="hljs-keyword">const</span> nanoid = alphabet (<span class="hljs-string">'1234567890ABCDEF'</span>, <span class="hljs-number">10</span>);
model.id = nanoid();
</code></pre>
<ul>
<li><p><strong>NanoID doesn’t much rely on any kind of third-party dependencies</strong>, which means, it ends up being a lot more steady which is helpful to maximize the package scope over time as well as make it much less vulnerable to the issues that come along with dependencies.</p>
</li>
<li><p><strong>NanoID is available in various programs languages</strong>, which include - C#, C++, Dart &amp; Flutter, Go, Java, PHP, Python, Ruby, Rust, Swift, etc.</p>
</li>
</ul>
<h3 id="heading-benchmarkhttpsgithubcomainanoidbenchmark"><strong><a target="_blank" href="https://github.com/ai/nanoid#benchmark">Benchmark</a></strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627208590444/CnfnYxWt-.png" alt="image.png" /></p>
<h2 id="heading-example-usages">Example usages</h2>
<p>Generating both NanoID or UUID is pretty straightforward. In JavaScript, you have NPM packages that will help you to generate them. You can get NanoId from here =&gt; https://github.com/ai/nanoid</p>
<ul>
<li>The main module uses URL-friendly symbols (A-Za-z0-9_-) and returns an ID with 21 characters:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { nanoid } <span class="hljs-keyword">from</span> <span class="hljs-string">"nanoid"</span>;
model.id = nanoid() <span class="hljs-comment">// X2JaSYP7_Q2leGI9b-MyA</span>
</code></pre>
<ul>
<li>You can also specify the number of characters you want:</li>
</ul>
<pre><code class="lang-javascript">nanoid(<span class="hljs-number">9</span>); <span class="hljs-comment">// "wMeKBp6th"</span>
</code></pre>
<ul>
<li>You can also change the used alphabet for generating hashes to your own if you have specific requirements as seen above:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> alphabet = <span class="hljs-string">'0123456789ABCDEF'</span>;
generate(alphabet, <span class="hljs-number">9</span>); <span class="hljs-comment">// F65BF3050</span>
</code></pre>
<h2 id="heading-risk-of-collision">Risk of collision</h2>
<p>Even though it can generate over 2.2 million unique IDs per second with its default alphabet, there is still a chance of generating the same multiple Ids. </p>
<p>But what are the odds of that happening?</p>
<p>You can calculate that based on the given parameters easily <a target="_blank" href="https://zelark.github.io/nano-id-cc/">here</a> and <a target="_blank" href="https://alex7kom.github.io/nano-nanoid-cc/">here</a>.</p>
<p>You'll notice that this <strong>probability comes out to be extremely small.</strong></p>
<h2 id="heading-some-disadvantages">Some disadvantages</h2>
<ul>
<li><strong>Being non-human readable can be one of the disadvantages in some cases</strong></li>
</ul>
<p>Imagine that a customer calls and is asked to provide the identifier, having to spell a complete NanoID is not a pleasant experience. When compared to UUID, NanoID is way shorter and readable but still cannot be used in such cases where the end customer needs to use it.</p>
<ul>
<li><strong>It can't be used as primary key in any SQL Database tables</strong></li>
</ul>
<p>If you use NanoID as a table’s primary key, there will be problems if you use the same column as a clustered index. This is because <strong>NanoIDs are not sequential.</strong></p>
<p>This is because the nature of NanoID(or even UUID) is that it's random and a clustered index physically orders the records by the key, so for every insert if there are indexes on the table, the database must make sure the new entry is also found via these indexes and to keep the index order and tree balance.</p>
<p>For this SQL has to reorder the records on disk and therefore remove clustering from this index. But when you have something sequential like time - clustering is almost free and easy to do after inserting a new record.</p>
<hr />
<h3 id="heading-a-few-words-of-wisdom">A few words of wisdom</h3>
<p>Any approach in a Software World is always going to be subjective. It’s up to your requirements to weigh in the tradeoffs and choose the approach that works for you. No design is concrete enough to continue forever, so given the constraints, we have chosen a certain design, and depending on how it works for us we might evolve it further as well.</p>
<p>👋 Thanks for reading and Happy learning…</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Tips and Best Practices]]></title><description><![CDATA[In this article, I’ll share 10 of the JavaScript tips, tricks, and best practices that I follow and found useful.
1. Use Numeric Separators
This is one of the most used operators when I have to deal with large numbers. When using a separator (with ju...]]></description><link>https://apoorvtyagi.tech/javascript-tips-and-best-practices</link><guid isPermaLink="true">https://apoorvtyagi.tech/javascript-tips-and-best-practices</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 04 Jul 2021 09:18:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1625374062864/jTMofl5wH.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I’ll share 10 of the JavaScript tips, tricks, and best practices that I follow and found useful.</p>
<h2 id="heading-1-use-numeric-separators">1. Use Numeric Separators</h2>
<p>This is one of the most used operators when I have to deal with large numbers. When using a separator (with just an _) in number it looks better than an unseparated number.</p>
<p>For example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> number = <span class="hljs-number">98234567</span>
</code></pre>
<p>to ⬇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> number = <span class="hljs-number">98</span>_234_567
</code></pre>
<p>And it works for any other numeric base as well:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> binary = <span class="hljs-number">0b1000</span>_0101;
<span class="hljs-keyword">const</span> hex = <span class="hljs-number">0x12</span>_34_56_78;
</code></pre>
<p><strong>Few caveats</strong> :</p>
<ul>
<li><p>More than one underscore in a row is not allowed <code>let num= 100__00</code></p>
</li>
<li><p>Can not be used after leading 0 <code>let num= 0_1</code></p>
</li>
<li><p>Not allowed at the end of numeric literals <code>let num= 100_</code></p>
</li>
</ul>
<h2 id="heading-2-always-use-semicolons">2. Always Use Semicolons</h2>
<p>The use of semi-colons for line termination is a good practice. You won’t be warned if you forget it, because in most cases it will be inserted by the JavaScript parser but relying on Automatic Semicolon Insertion(ASI) is not encouraged.</p>
<p>This is even included in <a target="_blank" href="https://google.github.io/styleguide/jsguide.html#formatting-semicolons-are-required">Google’s</a>, <a target="_blank" href="https://github.com/airbnb/javascript#semicolons">Airbnb’s</a>, and <a target="_blank" href="https://contribute.jquery.org/style-guide/js/#semicolons">jQuery’s</a> Javascript style guides.</p>
<p>To know about what could happen if we rely too much on ASI, checkout the <a target="_blank" href="https://newsletter.apoorvtyagi.tech/issues/but-it-works-on-my-machine-407281">4th issue of my newsletter</a> I shared some months back. In the last section, I have explained it with an example.</p>
<h2 id="heading-3-dont-forget-var">3. Don’t forget "var"</h2>
<p>When you assign a variable’s value for the first time, always make sure you're not doing it to an undeclared variable.</p>
<p>Assignment to an undeclared variable automatically results in a global variable being created. <strong>Avoid global variables</strong> ❌</p>
<p>Global variables are easily overwritten by other scripts. For example, if two separate parts of an application define global variables with the same name but with different purposes, it can result in unpredicted errors and it will be a horrible experience to debug such a problem.</p>
<p>Generally, you should try to scope your code so that you need as little as possible in the global scope. The more global variables you use in your script, the less is the chance that you can use it alongside another script.</p>
<p>Normally variables in a function should be local so that they go away when you exit the function.</p>
<blockquote>
<p>"By reducing your global footprint to a single name, you significantly reduce the chance of bad interactions with other applications, widgets, or libraries." - Douglas Crockford</p>
</blockquote>
<h2 id="heading-4-delete-vs-splice">4. Delete vs Splice</h2>
<p>Use splice instead of using delete to remove an item from an array. Using delete will remove the object property, but will not reindex the array or update its length. This makes it appears as if it is undefined.</p>
<h3 id="heading-delete">Delete</h3>
<pre><code class="lang-javascript">&gt; myArray = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>, <span class="hljs-string">'d'</span>]
  [<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>, <span class="hljs-string">"d"</span>]
&gt; <span class="hljs-keyword">delete</span> myArray[<span class="hljs-number">0</span>]
  <span class="hljs-literal">true</span>
&gt; myArray[<span class="hljs-number">0</span>]
  <span class="hljs-literal">undefined</span>
</code></pre>
<blockquote>
<p>Note that it is not in fact set to the value undefined, rather the property is removed from the array, making it appear undefined. The Chrome dev tools make this distinction clear by printing empty when logging the array.</p>
</blockquote>
<h3 id="heading-splice">Splice</h3>
<p><code>Splice()</code> actually removes the element, reindexes the array, and changes its length.</p>
<pre><code class="lang-javascript">&gt; myArray = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>, <span class="hljs-string">'d'</span>]
  [<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>, <span class="hljs-string">"d"</span>]
&gt; myArray.splice(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
  [<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>]
&gt; myArray
  [<span class="hljs-string">"c"</span>, <span class="hljs-string">"d"</span>]
</code></pre>
<blockquote>
<p>The delete method should be used to delete an object property.</p>
</blockquote>
<h2 id="heading-5-map-vs-for-loop">5. map vs for loop</h2>
<p>Although there are various ways to loop through an array, use the <code>map()</code> function method whenever possible.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> squares = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>].map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{  
    <span class="hljs-keyword">return</span> val * val;  
}); 

<span class="hljs-comment">// squares will be equal to [1, 4, 9, 16]</span>
</code></pre>
<p><strong>Immutability </strong> —  The original array will be unaffected. This has potential benefits in cases where the original array is still needed elsewhere. <code>for</code> loops can also be written so as not to update the original array, but it requires more code and updating our new array as part of our loop operation. On the other hand map() keeps this cleaner since you only have to work in one scope to still maintain immutability</p>
<p><strong>Cleaner code</strong> — When doing identical things, map can almost always be written with less code than for. It can be clearly written on one line sometimes whereas for requires at least two or generally three with braces included. Also, scope isolation and a reduction in the number of variables you need alongside reduced size all make code objectively cleaner.</p>
<h2 id="heading-6-rounding-numbers">6. Rounding numbers</h2>
<p>The toFixed() method converts a number rounding to a specified number of decimals.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> pi =<span class="hljs-number">3.1415</span>;
pi = pi.toFixed(<span class="hljs-number">2</span>);  <span class="hljs-comment">// pi will be equal to 3.14</span>
</code></pre>
<blockquote>
<p>NOTE :  <code>toFixed()</code> returns a string and not a number.</p>
</blockquote>
<h2 id="heading-7-use-consoletable">7. Use console.table</h2>
<p>You can use <code>console.table</code> to show objects in tabular format:</p>
<pre><code class="lang-javascript">table=[{<span class="hljs-attr">state</span>: <span class="hljs-string">"Texas"</span>},{<span class="hljs-attr">state</span>: <span class="hljs-string">"New York"</span>},{<span class="hljs-attr">state</span>: <span class="hljs-string">"Chicago"</span>}]
<span class="hljs-built_in">console</span>.table(table)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625387936496/OFRRiiMdC.png" alt="Table.png" /></p>
<h2 id="heading-8-avoid-using-try-catch-inside-a-loop">8. Avoid using try-catch inside a loop</h2>
<p>The try-catch construct creates a new variable in the current scope at runtime each time the catch clause is executed where the caught exception object is assigned to a variable.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> object = [<span class="hljs-string">'foo'</span>, <span class="hljs-string">'bar'</span>], i;  
<span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>, len = object.length; i &lt;len; i++) {  
    <span class="hljs-keyword">try</span> {  
        <span class="hljs-comment">// do something that throws an exception </span>
    }  
    <span class="hljs-keyword">catch</span> (e) {   
        <span class="hljs-comment">// handle exception  </span>
    } 
}
</code></pre>
<p>to ⬇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> object = [<span class="hljs-string">'foo'</span>, <span class="hljs-string">'bar'</span>], i;  
<span class="hljs-keyword">try</span> { 
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>, len = object.length; i &lt;len; i++) {  
        <span class="hljs-comment">// do something that throws an exception </span>
    } 
} 
<span class="hljs-keyword">catch</span> (e) {   
    <span class="hljs-comment">// handle exception  </span>
}
</code></pre>
<p>When an error occurs, the first one lets you continue the loop while the second one exits the loop. <strong>The first one is suited if an exception thrown by your code is not severe enough to halt your entire program</strong>.</p>
<h2 id="heading-9-multiple-condition-checking">9. Multiple condition checking</h2>
<p>For multiple value matching, we can put all values in an array and use <code>indexOf()</code> or <code>includes()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (value === <span class="hljs-number">1</span> || value === <span class="hljs-string">'one'</span> || value === <span class="hljs-number">2</span> || value === <span class="hljs-string">'two'</span>) { 

}
</code></pre>
<p>to ⬇</p>
<h3 id="heading-indexof">indexOf():</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> ([<span class="hljs-number">1</span>, <span class="hljs-string">'one'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'two'</span>].indexOf(value) &gt;= <span class="hljs-number">0</span>) { 

}
</code></pre>
<h3 id="heading-includes">includes():</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> ([<span class="hljs-number">1</span>, <span class="hljs-string">'one'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'two'</span>].includes(value)) { 

}
</code></pre>
<h2 id="heading-10-double-not-bitwise-operator">10. Double NOT bitwise operator (~~)</h2>
<p>The double NOT bitwise operator is a substitute for Math.floor() method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> floor = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-number">6.8</span>); <span class="hljs-comment">// 6</span>
</code></pre>
<p>to ⬇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> floor = ~~<span class="hljs-number">6.8</span>; <span class="hljs-comment">// 6</span>
</code></pre>
<blockquote>
<p>The double NOT bitwise operator approach only works for 32-bit integers. So for any number higher than that, it is recommended to use Math.floor()</p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I know that there are many other tips, tricks, and best practices, so if you have any ones to add or if you have any feedback or corrections to the ones that I have shared, please feel free to add them in a comment below.</p>
<p>Also, You can never learn from just one article. Try Google concepts and read multiple articles, play around with the code by making projects and that's the only way you learn.</p>
<p>Here's my final tip — <strong>Don’t use a casual coding style. Enforce a standard</strong></p>
<p>You never know what to expect while reading the code that has a random coding style. The same coding style across the entire team and the application codebase is a requirement. It’s a boost for code readability.</p>
<hr />
<h3 id="heading-references">References</h3>
<ul>
<li><p>https://modernweb.com/45-javascript-tips-tricks-practices/</p>
</li>
<li><p>https://stackoverflow.com/questions/2485423/is-using-var-to-declare-variables-optional</p>
</li>
<li><p>https://stackoverflow.com/questions/32844818/why-i-need-to-avoid-using-try-catch-finally-inside-a-loop</p>
</li>
<li><p>http://rocha.la/JavaScript-bitwise-operators-in-practice</p>
</li>
<li><p>Cover Photo by <a target="_blank" href="https://unsplash.com/@juanjodev02">Juanjo Jaramillo</a> on Unsplash</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Five++ cool Python snippets (Part - 2)]]></title><description><![CDATA[Introduction 👋
Python is a beautifully designed high-level interpreted programming language that provides us with many features.
This is a gentle guide to some of those Python features that you probably might not be aware of or didn't know about tha...]]></description><link>https://apoorvtyagi.tech/five-cool-python-snippets-part-2</link><guid isPermaLink="true">https://apoorvtyagi.tech/five-cool-python-snippets-part-2</guid><category><![CDATA[Python]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Wed, 30 Jun 2021 05:16:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1624904150818/XlA1dK6cM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="introduction">Introduction 👋</h1>
<p><strong>Python</strong> is a beautifully designed high-level interpreted programming language that provides us with many features.</p>
<p>This is a gentle guide to some of those Python features that you probably might not be aware of or didn't know about that specific use-case which you'll see later in this blog.</p>
<p>So in continuation of my <a target="_blank" href="https://apoorvtyagi.tech/cool-python-snippets-that-will-blow-your-mind">previous article</a>, here I am sharing another 5++ tips and tricks to help you write an elegant Python code in your competitive programming journey or in general as well! 😉 </p>
<h2 id="1-lambda-function">1. Lambda Function</h2>
<p>A lambda function is a small anonymous function. <strong>You can use "lambda" expression to sort a nested array by the second element</strong></p>
<pre><code><span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">arr_list</span> <span class="hljs-string">=</span> [[<span class="hljs-number">1</span>, <span class="hljs-number">4</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">3</span>], [<span class="hljs-number">5</span>, <span class="hljs-number">7</span>]]
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">sorted_list</span> <span class="hljs-string">=</span> <span class="hljs-string">sorted(arr_list</span> <span class="hljs-string">,</span> <span class="hljs-string">key=lambda</span> <span class="hljs-attr">x:</span> <span class="hljs-string">x[1])</span>
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">sorted_list</span> 
[[<span class="hljs-number">3</span>, <span class="hljs-number">3</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">4</span>], [<span class="hljs-number">5</span>, <span class="hljs-number">7</span>]]
</code></pre><p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1356946442573725696">Link To Tweet</a></p>
<h2 id="2-counter">2. Counter</h2>
<p>Counter class is a special type of object data-set provided with the collections module in Python3.</p>
<p>Let's say we want an 𝐮𝐧𝐨𝐫𝐝𝐞𝐫𝐞𝐝 collection where elements are stored as 𝐝𝐢𝐜𝐭𝐢𝐨𝐧𝐚𝐫𝐲 𝐤𝐞𝐲𝐬 &amp; their counts are stored as 𝐝𝐢𝐜𝐭𝐢𝐨𝐧𝐚𝐫𝐲 𝐯𝐚𝐥𝐮𝐞𝐬</p>
<pre><code><span class="hljs-string">import</span> <span class="hljs-string">collections</span>

<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">A</span> <span class="hljs-string">=</span> <span class="hljs-string">collections.Counter([1,</span> <span class="hljs-number">1</span><span class="hljs-string">,</span> <span class="hljs-number">2</span><span class="hljs-string">,</span> <span class="hljs-number">2</span><span class="hljs-string">,</span> <span class="hljs-number">3</span><span class="hljs-string">,</span> <span class="hljs-number">3</span><span class="hljs-string">,</span> <span class="hljs-number">3</span><span class="hljs-string">,</span> <span class="hljs-number">3</span><span class="hljs-string">,</span> <span class="hljs-number">4</span><span class="hljs-string">,</span> <span class="hljs-number">5</span><span class="hljs-string">,</span> <span class="hljs-number">6</span><span class="hljs-string">,</span> <span class="hljs-number">7</span><span class="hljs-string">])</span>
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">A</span>
<span class="hljs-string">Counter({3:</span> <span class="hljs-number">4</span><span class="hljs-string">,</span> <span class="hljs-attr">1:</span> <span class="hljs-number">2</span><span class="hljs-string">,</span> <span class="hljs-attr">2:</span> <span class="hljs-number">2</span><span class="hljs-string">,</span> <span class="hljs-attr">4:</span> <span class="hljs-number">1</span><span class="hljs-string">,</span> <span class="hljs-attr">5:</span> <span class="hljs-number">1</span><span class="hljs-string">,</span> <span class="hljs-attr">6:</span> <span class="hljs-number">1</span><span class="hljs-string">,</span> <span class="hljs-attr">7:</span> <span class="hljs-number">1</span><span class="hljs-string">})</span>
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">A.most_common(1)</span>
[<span class="hljs-string">(3</span>, <span class="hljs-number">4</span><span class="hljs-string">)</span>]
<span class="hljs-string">&gt;&gt;A.most_common(3)</span>
[<span class="hljs-string">(3</span>,<span class="hljs-number">4</span><span class="hljs-string">)</span>, <span class="hljs-string">(1</span>, <span class="hljs-number">2</span><span class="hljs-string">)</span>, <span class="hljs-string">(2</span>, <span class="hljs-number">2</span><span class="hljs-string">)</span>]
</code></pre><p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1355167637660164097">Link To Tweet</a></p>
<h2 id="3-merge-2-dictionaries">3. Merge 2 Dictionaries</h2>
<p>Python 3.9 introduces <strong>Dictionary union (|)</strong></p>
<p>It will return a new dictionary consisting of the left operand merged with the right operand. If a key appears in both operands, the last-seen value (i.e., from the right-hand operand) is selected.</p>
<pre><code><span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">d1</span> <span class="hljs-string">=</span> {<span class="hljs-attr">'a':</span> <span class="hljs-number">10</span>, <span class="hljs-attr">'b':</span> <span class="hljs-number">5</span>, <span class="hljs-attr">'c':</span> <span class="hljs-number">3</span>}
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">d2</span> <span class="hljs-string">=</span> {<span class="hljs-string">'d'</span><span class="hljs-string">:6</span>, <span class="hljs-attr">'c':</span> <span class="hljs-number">4</span>, <span class="hljs-attr">'b':</span> <span class="hljs-number">8</span>}
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">d1</span> <span class="hljs-string">|</span> <span class="hljs-string">d2</span>
{<span class="hljs-attr">'a':</span> <span class="hljs-number">10</span>, <span class="hljs-attr">'b':</span> <span class="hljs-number">8</span>, <span class="hljs-attr">'c':</span> <span class="hljs-number">4</span>, <span class="hljs-attr">'d':</span> <span class="hljs-number">6</span>}
<span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">d2</span> <span class="hljs-string">|</span> <span class="hljs-string">d1</span>
{<span class="hljs-attr">'d':</span> <span class="hljs-number">6</span>, <span class="hljs-attr">'c':</span> <span class="hljs-number">3</span>, <span class="hljs-attr">'b':</span> <span class="hljs-number">5</span>, <span class="hljs-attr">'a':</span> <span class="hljs-number">10</span>}
</code></pre><p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1343177309323464705">Link To Tweet</a></p>
<h2 id="4-special-strip">4. Special Strip</h2>
<p>Can you guess what will be the output of the following python code -</p>
<pre><code><span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python"><span class="hljs-string">"three cool features in Python"</span>.strip(<span class="hljs-string">" Python"</span>)</span>
</code></pre><p>Well, strip() only remove the substring " Python" from the beginning or the end but the way it does it is quite peculiar</p>
<p><strong>It removes the individual characters " ", "P", "y", "t", "h", "o", "n" instead of checking the whole "Python" as a word</strong></p>
<blockquote>
<p>Note that it even considers spaces while removing characters and It is also <strong>case sensitive</strong></p>
</blockquote>
<p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1350057647672872961">Link To Tweet</a></p>
<h2 id="5-greater">5. [] + [] -&gt; {}</h2>
<p>Ever wanted to form a dictionary out of two lists??</p>
<p>In Python🐍 it is super easy</p>
<p><strong>There's a zip() function that takes several iterable objects and returns a list of tuples</strong></p>
<p>Each tuple groups the elements of the input objects by their positional index </p>
<pre><code><span class="hljs-meta">&gt;&gt;</span>&gt; x = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]
<span class="hljs-meta">&gt;&gt;</span>&gt; y = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-meta">&gt;&gt;</span>&gt; dict(zip(x, y))
{<span class="hljs-string">'a'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'b'</span>: <span class="hljs-number">2</span>, <span class="hljs-string">'c'</span>: <span class="hljs-number">3</span>}
</code></pre><p>You can even use it when you want to transpose a 2-D matrix, like this ⬇</p>
<pre><code><span class="hljs-string">&gt;&gt;&gt;</span> <span class="hljs-string">mat</span> <span class="hljs-string">=</span> [[<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>, <span class="hljs-number">6</span>]]
<span class="hljs-string">&gt;&gt;&gt;</span> <span class="hljs-string">list(zip(*mat))</span>
[<span class="hljs-string">(1</span>, <span class="hljs-number">4</span><span class="hljs-string">)</span>, <span class="hljs-string">(2</span>, <span class="hljs-number">5</span><span class="hljs-string">)</span>, <span class="hljs-string">(3</span>, <span class="hljs-number">6</span><span class="hljs-string">)</span>]
</code></pre><p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1323254708832628736">Link To Tweet</a></p>
<h2 id="5-sliding-window">5++.  Sliding Window</h2>
<p>When I was doing competitive programming, I saw a lot of questions involving the <a target="_blank" href="https://leetcode.com/tag/sliding-window/">sliding window problem</a></p>
<p>In C++ it was a little hectic, But in python, you can do it with just a few lines of code -</p>
<pre><code><span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python"><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> islice</span>
<span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">slide</span>(<span class="hljs-params">list_name, window_size</span>):</span></span>
<span class="hljs-meta">...</span> <span class="python">          z = [islice(list_name, i, <span class="hljs-literal">None</span>) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(window_size)]</span>
<span class="hljs-meta">...</span> <span class="python">          <span class="hljs-keyword">return</span> zip(*z)</span>
</code></pre><p>Here's the sample input and output response ⬇</p>
<pre><code><span class="hljs-string">&gt;&gt;&gt;</span> <span class="hljs-string">list(slide([1,</span> <span class="hljs-number">2</span><span class="hljs-string">,</span> <span class="hljs-number">3</span><span class="hljs-string">,</span> <span class="hljs-number">4</span><span class="hljs-string">,</span> <span class="hljs-number">5</span><span class="hljs-string">,</span> <span class="hljs-number">6</span><span class="hljs-string">,</span> <span class="hljs-number">7</span><span class="hljs-string">],</span> <span class="hljs-number">3</span><span class="hljs-string">))</span>
[<span class="hljs-string">(1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span><span class="hljs-string">)</span>, <span class="hljs-string">(2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span><span class="hljs-string">)</span>, <span class="hljs-string">(3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span><span class="hljs-string">)</span>, <span class="hljs-string">(4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span><span class="hljs-string">)</span>, <span class="hljs-string">(5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span><span class="hljs-string">)</span>]
</code></pre><p>🔗<a target="_blank" href="https://twitter.com/apoorv__tyagi/status/1334200547826573312">Link To Tweet</a></p>
<hr />
<h2 id="wrapping-up">Wrapping Up 🏁</h2>
<p>So those were the 5++ cool quirks of python. I hope you liked them and learned something new.</p>
<p>Also if you enjoyed it, consider buying me a coffee ☕ </p>
<p>(Seriously, I'd like some c̶o̶f̶f̶e̶e̶ support 😛)</p>
<p><a href="https://www.buymeacoffee.com/apoorvtyagi" target="_blank"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&amp;emoji=&amp;slug=apoorvtyagi&amp;button_colour=BD5FFF&amp;font_colour=ffffff&amp;font_family=Comic&amp;outline_colour=000000&amp;coffee_colour=FFDD00" /></a></p>
<h3 id="other-articles-you-might-like">Other articles you might like 😊</h3>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/metrics-to-evaluate-your-machine-learning-algorithm">Metrics to evaluate your Machine Learning algorithm</a> 📊 - Evaluation Metrics for your Machine Learning algorithm that every Data Scientist must know.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/why-you-cant-name-a-file-con-in-windows">Why you can't name a file 'CON' in Windows</a> ❓ - Learn why Windows doesn’t allow you to create files and folders named CON, PRN, AUX, and NUL.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/cool-python-snippets-that-will-blow-your-mind">Five++ cool Python snippets that will blow your mind (Part - 1)</a> 🤯 - Few clever yet useful Python tricks and tips that will surely make you think hard. This is Part-1 of this blog post series.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/useful-resources-to-learn-web-development-and-to-create-your-website">Useful Resources To Learn Web Development &amp; To Create Your Website</a> 💻 - Starting with web development? Here are some resources that helped me and will be useful for you as well.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Why You Can't Name a File 'CON' in Windows?]]></title><description><![CDATA[❓ Did you know you can’t name a file “Con” in Windows
If you’re running a Windows machine, try it right now. Go to File Explorer -> create a new folder -> name it "Con"
Did it work? Now try with "PRN", "AUX" or "NUL". What did you get?
Probably this ...]]></description><link>https://apoorvtyagi.tech/why-you-cant-name-a-file-con-in-windows</link><guid isPermaLink="true">https://apoorvtyagi.tech/why-you-cant-name-a-file-con-in-windows</guid><category><![CDATA[Windows]]></category><category><![CDATA[general]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Thu, 24 Jun 2021 07:34:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1624010122017/vmO7pe-yM.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>❓ Did you know you can’t name a file “Con” in Windows</p>
<p>If you’re running a Windows machine, try it right now. <strong>Go to File Explorer -&gt; create a new folder -&gt; name it "Con"</strong></p>
<p>Did it work? Now try with "PRN", "AUX" or "NUL". What did you get?</p>
<p>Probably this 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1624010275461/kIHbPV7Ij.png" alt="Invalid.png" /></p>
<p>The system will not let you do it.</p>
<p>Con is an English word, and there are a few human names like Connor who goes by the nickname 'Con'. So if you’re trying to save a photo of one of them using their nickname on Windows, you will not able to. </p>
<p>In fact, the system won't let you name a file or folder <code>CON</code>, <code>AUX</code>, <code>PRN</code>, <code>LST</code>, <code>COM0</code> to <code>COM9</code>, <code>LPT0</code> to <code>LPT9</code>, or <code>NUL</code>. </p>
<h1 id="heading-but-why-windows-doesnt-allow-this">But why Windows doesn’t allow this?</h1>
<p>The reason for that goes back to MS-DOS, one of the oldest command lines from the 80s. In MS-DOS, all those words that are mentioned above are the names of <strong>device files</strong>. </p>
<p>They were a quick and clever way of letting programs on a computer interact with other hardware like printers, keyboards, and basically anything that you can plug in. Rather than every program having to learn to communicate with every possible device, that job was given to a "device driver".</p>
<p>This was done so that programmers didn’t have to worry about how every single type of hardware device like printers worked. Instead, they could reuse code that they already had for reading and writing files from and to the printer. They would just have to save whatever they wanted to print to this "device file".</p>
<p>This means that even when a new printer came out with new features in it and if the manufacturer would bundle a new driver with it, all the old programs would still work, in the same way as they always did, and the driver would deal with the dirty stuff.</p>
<h2 id="heading-backward-compatibility">Backward Compatibility</h2>
<p>If you type "dir" in your windows terminal, you’d get a listing on the screen of whatever files were in the current directory or folder. Typing "dir", adding a redirect symbol(&gt;) after that, and mentioning a file name at last, would then save the listing on that file instead of the listing going to the screen. </p>
<p>But if you tried to save it to a file called "LPT1", the system would spot that file name, and instead of going to the hard disk, your list will be sent to the device driver for the parallel port, the one that was labeled LPT1 on the back of your computer. The place where you have a printer plugged in. So even knowing anything about how the parallel port or printer worked, you could just print stuffs. </p>
<p>Windows 10 probably don't use parallel port now but the reason why these reserved words still exist till now is because of <strong>backward compatibility</strong>. </p>
<p>Windows 10 retains code from the days of Windows 3.1, and Windows 3.1 was created with MS-DOS as basic, so was Windows 95. With Windows NT this did not happen, but still, Microsoft wanted it to be compatible with Windows 95, and Windows 10 is still partly based on Windows NT. So those were the reserved words in MS-DOS in the 80s and they still continue to be reserved words in Windows in 2021</p>
<p>Almost no one may use a parallel port to connect a printer anymore, but Microsoft chooses to continue to support extremely old software and devices to this day.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, we saw why you can't name a file or a folder "Con" in Windows.</p>
<p>In the early times of MS-DOS, computers were basically a black screen with text and nothing else. So everything worked by writing orders. For a program to interact with other things, such as a printer, a command had to be written using a text file or “device file” that would interact with a driver.</p>
<p>Depending on the device, it has a name reserved. For example, the parallel ports that printers used to connect to use LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. The serial ports has reserved COM from COM1 to COM9. "CON" represents the console etc.</p>
<p>To this day those device names are reserved so that you cannot create usable files or folders with them. If back then you tried to do something like creating a file called LPT1.txt, what you were going to do was send it to the printer or something like that and that’s why they were blocked.</p>
<p>Hope you learned something new today!</p>
<p>Thanks for reading :))</p>
<h2 id="heading-other-articles-you-might-like">Other articles you might like 😊</h2>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/metrics-to-evaluate-your-machine-learning-algorithm">Metrics to evaluate your Machine Learning algorithm</a> - Measure the quality of the statistical or machine learning model.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment">Generating unique IDs in a Large scale Distributed environment</a> - Learn how to create unique IDs for a distributed system at a large scale. Inspired from Twitter snowflake.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/useful-resources-to-learn-web-development-and-to-create-your-website">Useful Resources To Learn Web Development &amp; To Create Your Website</a> - Resources I found helpful in my web development journey</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Metrics to evaluate your Machine Learning algorithm]]></title><description><![CDATA[You made a machine learning or deep learning model. Amazing! 🥳
But how do you check its performance and robustness? Simply building a predictive model is not enough. You have to create a model which gives high accuracy on out-of-sample data.
That's ...]]></description><link>https://apoorvtyagi.tech/metrics-to-evaluate-your-machine-learning-algorithm</link><guid isPermaLink="true">https://apoorvtyagi.tech/metrics-to-evaluate-your-machine-learning-algorithm</guid><category><![CDATA[Machine Learning]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Python]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Fri, 18 Jun 2021 08:49:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997075350/vt_0YJcfN.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You made a machine learning or deep learning model. Amazing! 🥳</p>
<p>But how do you check its performance and robustness? Simply building a predictive model is not enough. You have to create a model which gives high accuracy on <strong>out-of-sample data</strong>.</p>
<p>That's where evaluation metrics come into the picture. They are used to measure the quality of the statistical or machine learning model, and this article will introduce you to the most common and yet important metrics to evaluate your machine learning algorithms.</p>
<p>If you're someone who just started out in the field of Data Science and Machine Learning, this is for you. We will discuss the following terms:</p>
<ul>
<li>Confusion matrix</li>
<li>Accuracy</li>
<li>Precision</li>
<li>Recall</li>
<li>F1 score</li>
<li>Mean Absolute Error</li>
<li>R Squared Score</li>
<li>Root Mean Squared Error</li>
<li>ROC (Receiver Operating Characteristics) curve</li>
</ul>
<p>So let’s dive into it to learn about them :</p>
<h1 id="heading-confusion-matrix">Confusion Matrix</h1>
<p>A confusion matrix is one of the simplest concepts in the field of machine learning, and yet so important when it comes to statistical classification problems. </p>
<p>A confusion matrix is an N X N matrix, where N is the number of classes being predicted. It is usually used to <strong>describe the performance of a classification model based on the true values known for a data set</strong>.</p>
<p>In simple words, it is a summary of the prediction result made by the classification model.</p>
<h3 id="heading-terms-associated-with-confusion-matrix">Terms Associated with Confusion Matrix</h3>
<p><strong>True Positive (TP):</strong> True positive means their actual class value is 1 and the predicted value is also 1.</p>
<p>For example, The case where the woman is actually pregnant and the model also classifies that she is pregnant.</p>
<p><strong>False Positive (FP):</strong> False positive means their actual class value is 0 and the predicted value is 1.</p>
<p>For example, The case where the woman is not pregnant and the model classifies that she is pregnant.</p>
<p><strong>True Negative (TN):</strong> True negative means their actual class value is 0 and the predicted value is also 0.</p>
<p>For example, The case where the woman is actually not pregnant and the model also classifies that she is not pregnant.</p>
<p><strong>False Negative (FN):</strong> False-negative means their actual class value is 1 and the predicted value is 0.</p>
<p>For example, The case where the woman is actually pregnant and the model also classifies that she is not pregnant.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623853513229/trs6eb65N.png" alt="confusion matrix.png" /></p>
<blockquote>
<p>The confusion matrix in itself is not a performance measure but all the performance metrics are dependent on the confusion matrix.</p>
</blockquote>
<h1 id="heading-accuracy">Accuracy</h1>
<p>Accuracy is the most common metric that you can see everywhere when you're evaluating your model. It is simply defined as the number of correct predictions made by your model.</p>
<p>In simple terms, <strong>accuracy is the ratio of all the correct predictions to the total number of predictions</strong>.</p>
<p>It can be calculated using a confusion matrix.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997989964/x6JODZUuU.png" alt="accuracy.png" /></p>
<h1 id="heading-precision">Precision</h1>
<p>Precision is defined as <strong>the total number of correctly classified positive examples by the total number of predicted positive examples</strong>.</p>
<p>In some cases, your classification model might classify based on the most frequent classes. Which in turn will bring a low accuracy because your model didn’t learn anything and just classified based on the top class.</p>
<p>Therefore, we need class-specific performance metrics to analyze. Precision is one of them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997831139/q5VbMq6zx.png" alt="precision.png" /></p>
<blockquote>
<p>It depicts how much the model is right when it says it is right.</p>
</blockquote>
<h1 id="heading-recall">Recall</h1>
<p>A recall (also known as <em>sensitivity</em>) refers to the percentage of total relevant results correctly classified by the classification model.</p>
<p>It is the <strong>the number of positive samples returned by the custom-trained model</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997843703/IhiNTM2Cn.png" alt="Recall.png" /></p>
<p>The relation between recall and precision -</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623900342363/t6_00UhjI.jpeg" alt="RecalVsPrecision.jpeg" /></p>
<h3 id="heading-high-recall-low-precision">High recall, low precision:</h3>
<p>This means, most of the positive examples are correctly recognized but there are a lot of false positives.</p>
<h3 id="heading-low-recall-high-precision">Low recall, high precision:</h3>
<p> This means that we missed a lot of positive examples but those we predicted as positive are indeed positive.</p>
<h1 id="heading-f1-score">F1 Score</h1>
<p>Based on the use case of the classification model, the priority is given either to precision or recall, but in some classification models, we need both of these metrics to be combined as a single one. </p>
<p><strong>F1-Score is a metric that combines both precision and recall</strong> and has an equal and relative contribution of both precision and recall.</p>
<p>It is the harmonic mean of precision and recall.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997858830/MVeG1-Ktb.png" alt="F1 score.png" /></p>
<blockquote>
<p>Remember that if your use case needs either recall or precision, one higher than the other then F1-score may not be the good metric for it. </p>
</blockquote>
<h1 id="heading-mean-absolute-error">Mean Absolute Error</h1>
<p>Mean absolute error(MAE) is defined as <strong>the average of all errors that are calculated based on values predicted by your model</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997877447/xhAb091-l.png" alt="MAE-2.png" /></p>
<p>It is intended to measure average model bias in a set of predictions, without considering their direction</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623856647925/sJPrbnngB.jpeg" alt="MAE-1.jpg" /></p>
<h1 id="heading-r-squared-score">R Squared Score</h1>
<p>R squared is a measure of how close the data are to the fitted regression line. It is also known as the coefficient of determination.</p>
<p>It defines the degree to which the variance in the dependent variable (or target) can be explained by the independent variable (features).</p>
<p>For example, if the R-squared value for our predictive model is 0.8. This means that 80% of the variation in the dependent variable is explained by the independent variables.</p>
<p>Therefore we can say that the <strong>higher the r-squared value is, the better is the model</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623986479517/HVNZgosBn.png" alt="rsqared.png" /></p>
<p>SSRES: the Residual sum of squared errors</p>
<p>SSTOT: the total sum of squared errors</p>
<h1 id="heading-root-mean-squared-error">Root Mean Squared Error</h1>
<p>RMSE is one of the most popular metrics used today for evaluating regression-based models. This is an important evaluation metric since it’s essential to find the average squared error between the predicted values.</p>
<p>RMSE <strong>measures the average magnitude of the error</strong>. It’s the square root of the average of squared differences between prediction and actual observation.</p>
<blockquote>
<p>RMSE is highly affected by outlier values. Hence, make sure you’ve removed outliers from your data set prior to using this metric.</p>
</blockquote>
<p>As compared to mean absolute error, RMSE gives higher weightage and punishes large errors</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623856974370/Mh1npqTAA.png" alt="rmse.png" /></p>
<p>here 'N' is total observations.</p>
<h3 id="heading-correlation-between-mae-and-rmse">Correlation between MAE and RMSE</h3>
<p>Both of these metrics express the average error of the machine learning models.
These two metrics can range from 0 to infinity and both of these metrics are negatively oriented scores, which means that a lower score defines better results.</p>
<h1 id="heading-roc-curve">ROC Curve</h1>
<p>ROC curve stands for “Receiver Operating Characteristic" Curve.</p>
<p>The ROC curve is a graph showing the performance of a classification model at all its cut-off thresholds.</p>
<p>In simple words, the ROC Curve is the one that <strong>tells how much your model is capable of differentiating among the different classes</strong>.</p>
<p>ROC is a probability curve. It is a representation of the performance of your model in a graphical manner.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621997941907/LeLyOIDtr.png" alt="ROC.png" /></p>
<p>This curve represents:</p>
<ol>
<li>True positive rate (recall/sensitivity)</li>
<li>False-positive rate (1- specificity): FPR = FP/ FP+TN</li>
</ol>
<p>The curve separates the space into two areas, one for good and the other for poor performance levels.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, you have seen some important metrics that are helpful for model evaluation and need to be understood by a data scientist or a machine learning engineer.</p>
<p>I hope you have found it useful. Also please feel free to suggest corrections and improvements.</p>
<p>And if you're looking for a good <a target="_blank" href="https://www.odinschool.com/datascience-bootcamp">Data Science course</a> for upskilling yourself, you might consider exploring the offerings of Odinschool.</p>
<p>Thanks for reading :))</p>
<h1 id="heading-related-articles-you-might-like">Related articles you might like 😊</h1>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/understanding-linear-regression">Understanding Linear Regression</a> - One of the most popular algorithms in machine learning that every data scientist should know.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/nlp-textblob">Having a go at common NLP tasks using TextBlob</a> - Learn some of the basic operations to do in Natural language processing using TextBlob.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment">Generating unique IDs in a Large-scale Distributed environment</a> - Learn how to create unique IDs for a distributed system at a large scale. Inspired by Twitter snowflake.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/useful-resources-to-learn-web-development-and-to-create-your-website">Useful Resources To Learn Web Development &amp; To Create Your Website</a> - Resources I found helpful in my web development journey</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Generating unique IDs in a Large scale Distributed environment]]></title><description><![CDATA[Introduction
Recently at work, We were looking for a way to generate unique IDs across a distributed system that could also be used as the primary keys in the MySQL tables.
We knew in a single MySQL database we can simply use an auto-increment ID as ...]]></description><link>https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment</link><guid isPermaLink="true">https://apoorvtyagi.tech/generating-unique-ids-in-a-large-scale-distributed-environment</guid><category><![CDATA[General Programming]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[Java]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 06 Jun 2021 10:20:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1621346062539/v0U2h3GAi.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Recently at work, We were looking for a way to generate unique IDs across a distributed system that could also be used as the primary keys in the MySQL tables.</p>
<p>We knew in a single MySQL database we can simply use an auto-increment ID as the primary key, But this won’t work in a sharded MySQL database.</p>
<p>So I looked at various existing solutions for this and finally learned about <a target="_blank" href="https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html">Twitter Snowflake</a> - a simple 64-bit unique ID generator.</p>
<h1 id="heading-why-dont-you-use-uuid">Why don't you use UUID? 🤔</h1>
<p>UUIDs are 128-bit hexadecimal numbers that are globally unique. The chances of the same UUID getting generated twice are negligible.</p>
<p>The problem with UUIDs is that they are very big in size and don’t index well. When your dataset increases, the index size increases as well and the query performance degrades.</p>
<p>Another problem with UUIDs is related to the user experience. Eventually, our users will be needed that unique identifiers. Imagine that a customer calls Customer Service and is asked to provide the identifier. Having to spell a complete UUID is not a pleasant experience.</p>
<h1 id="heading-twitter-snowflake">Twitter snowflake ❄</h1>
<p>Twitter snowflake is a dedicated service for generating 64-bit unique identifiers used in distributed computing for objects within Twitter such as Tweets, Direct Messages, Lists, etc.</p>
<p>These IDs are unique 64-bit unsigned integers, which are based on time. The full IDs are made up of the following components:</p>
<ul>
<li><p>Epoch timestamp in millisecond - 41 bits (gives us 69 years with respect to any custom epoch)</p>
</li>
<li><p>Configured machine/node/shard Id - 10 bits (gives us up to total of 2<sup>10</sup> i.e 1024 Ids)</p>
</li>
<li><p>Sequence number - 12 bits (A local counter per machine that sets to zero after every 4096 values)</p>
</li>
<li><p>The extra 1 reserved bit at the beginning which is set as 0 to make the overall number as positive.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621607903347/g1bih0ILA.png" alt="image.png" /></p>
<p>Since these use the timestamp as the first component, therefore, <strong>they are time sortable as well</strong>. Another benefit is its <strong>High Availability</strong>.</p>
<p>By default, 64-bit unsigned integers (long) will generate an Id whose length is 19, but sometimes it may be too long, our use case needed an Id whose length should not be greater than 10.</p>
<p>This article will share a simplified version of the unique ID generator that will work for any use-case of generating unique IDs in a distributed environment based on the concepts outlined in the Twitter snowflake service.</p>
<h1 id="heading-coding-time">Coding time ⌚</h1>
<p>In our case, the full ID will be composed of a 20-bit timestamp, 5-bit worker number, and 6-bit sequence number.</p>
<p>The remaining 1-bit is the signed bit and it is always set to 0 to make the final value positive.</p>
<p>Our microservices can use this Random number generator to generate IDs independently. This is efficient and fits in the size of a <code>int</code> (4 Bytes or 32 bits).</p>
<p>Here is the complete code in Java (<a target="_blank" href="https://github.com/twitter/snowflake/tree/snowflake-2010"><em>Inspired by Twitter snowflake</em></a><em>,</em> <a target="_blank" href="https://github.com/callicoder/java-snowflake"><em>code credits</em></a>) -</p>
<p><strong>Step 1 - We initialize the number of bits that each component will require</strong> :</p>
<pre><code class="lang-plaintext">public class Snowflake {

    // Sign bit, Unused (always set to 0)
    private static final int UNUSED_BITS = 1; 

    private static final int EPOCH_BITS = 20;
    private static final int NODE_ID_BITS = 5;
    private static final int SEQUENCE_BITS = 6;

    private static final int maxNodeId = (int)(Math.pow(2, NODE_ID_BITS) - 1);
    private static final int maxSequence = (int)(Math.pow(2, SEQUENCE_BITS) - 1);

    // Custom Epoch (Fri, 21 May 2021 03:00:20 GMT)
    private static final int DEFAULT_CUSTOM_EPOCH = 1621566020;

    private volatile int lastTimestamp = -1;
    private volatile int sequence = 0;

    // Class Constructor
    public Snowflake() {
        this.nodeId = createNodeId();
        this.customEpoch = DEFAULT_CUSTOM_EPOCH;
    }
</code></pre>
<blockquote>
<p>Here, we are taking custom epoch as of Fri, 21 May 2021 03:00:20 GMT.</p>
</blockquote>
<p><code>EPOCH_BITS</code> will be 20 bits and is filled with a current timestamp in seconds (You can also use millisecond if there is a possibility of multiple numbers of requests per second).</p>
<p><code>NODE_ID_BITS</code> will be 5 bits and is filled using the Mac address.</p>
<p><code>SEQUENCE_BITS</code> will be 6 bits and will act as a local counter which will start from 0, goes till 63, and then resets back to 0.</p>
<p><strong>Step 2 - Creating a</strong> <code>synchronized</code> function to generate the IDs :</p>
<pre><code class="lang-plaintext"> public synchronized int nextId() {
        int currentTimestamp = (int) (Instant.now().getEpochSecond() - customEpoch);

        if(currentTimestamp &lt; lastTimestamp) {
            throw new IllegalStateException("Invalid System Clock!");
        }

        lastTimestamp = currentTimestamp;

        return currentTimestamp &lt;&lt; (NODE_ID_BITS + SEQUENCE_BITS) | (nodeId &lt;&lt; SEQUENCE_BITS) | sequence;
    }
</code></pre>
<h4 id="heading-wait-why-are-we-doing-these-left-shifts-andamp-logical-or-operations">Wait, why are we doing these <code>Left Shifts</code> &amp; <code>Logical OR</code> operations?</h4>
<p>This is because Integer is represented by 32 bits and initially all are set to 0. To fill these bits we have to take each component separately, so first we took the epoch timestamp and shift it to 5 + 6 i.e 11 bits to left. Doing this has filled the first 21 bits with the first component (remember the first bit is always set to zero to make the overall number positive). The remaining 11 bits are still 0 and hence again we repeat the same thing with logical OR &amp; the other two components as well thereby filling all the 32 bits and forming the complete number.</p>
<p><strong>Step 3 - Utility function to generate the node id using the system’s MAC address</strong>:</p>
<pre><code class="lang-plaintext">private int createNodeId() {
        int nodeId;
        try {
            StringBuilder sb = new StringBuilder();
            Enumeration&lt;NetworkInterface&gt; networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                byte[] mac = networkInterface.getHardwareAddress();
                if (Objects.nonNull(mac))
                    for(byte macPort: mac)
                        sb.append(String.format("%02X", macPort));
            }
            nodeId = sb.toString().hashCode();
        } catch (Exception ex) {
            nodeId = (new SecureRandom().nextInt());
        }
        nodeId = nodeId &amp; maxNodeId;
        return nodeId;
    }
}
</code></pre>
<h3 id="heading-how-it-works">How it works? 💡</h3>
<p>Let’s now understand its working with an example -</p>
<p>Let’s say it’s Sun, 23 May 2021 00:00:00 GMT right now. The epoch timestamp for this particular time is 1621728000.</p>
<p>First of all, we adjust our timestamp with respect to the custom epoch-</p>
<p>currentTimestamp = 1621728000- 1621566020 = 161980(Adjust for custom epoch)</p>
<p>So to start our ID, the first 20 bits of the ID (after the signed bit) will be filled with the epoch timestamp. Let's this value with a left-shift :</p>
<p><code>id = currentTimestamp &lt;&lt; (NODE_ID_BITS + SEQUENCE_BITS )</code></p>
<p>Next, we take the configured node ID/shard ID and fill the next 10 bits with that</p>
<p><code>id = id | nodeId &lt;&lt; SEQUENCE_BITS</code></p>
<p>Finally, we take the next value of our auto-increment sequence and fill out the remaining 6 bits -</p>
<p><code>id = id | sequence // 6149376</code></p>
<p>That gives us our final ID 🎉</p>
<p>And that’s it! Primary keys that are unique across our application!</p>
<h2 id="heading-summary">Summary 📊</h2>
<p>This article showed you a simple solution of how to generate a snowflake id whose length is &gt;=7 and &lt;=10.</p>
<p>By the way, you can adjust the bit count of the 3 components to adapt to your work.</p>
<p>NOTE : We should keep the generator as a singleton, it means that we should only create the single instance of SequenceGenerator per node. If not, it may generate some duplicate Ids.</p>
<p>Not only did twitter used it, <strong>Discord</strong> also uses snowflakes, with their epoch set to the first second of the year 2015.</p>
<p><strong>Instagram</strong> uses a modified version of the format, with 41 bits for a timestamp, 13 bits for a shard ID, and 10 bits for a sequence number.</p>
<p>I hope this will help you! Thanks for reading :))</p>
<h2 id="heading-other-articles-you-might-like">Other Articles You Might Like 🙂</h2>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/useful-resources-to-learn-web-development-and-to-create-your-website">Useful Resources To Learn Web Development &amp; To Create Your Website</a> - Resources I found helpful in my web development journey.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/7-chrome-extensions-to-enhance-github-experience">Chrome extensions I use to enhance my GITHUB experience</a> - Here are 7 extensions I use to improve my Github experience.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/the-most-famous-coding-interview-question">The Most Famous Coding Interview Question</a> - Learn about what's the most asked coding interview question and how you can approach it in the best possible way.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/welcome-to-the-world-of-nft">Welcome to the world of "NFTs"</a> - Learn about what are NFTs and Why are they suddenly becoming the next big thing.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/creating-blockchain-python">What is Blockchain Technology? Learn by creating one</a> - Want to know how blockchain works? Learn here by creating one.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Dunning Kruger Effect and Imposter Syndrome]]></title><description><![CDATA[This article has been in my drafts for a long time but I never clicked that Publish button as I was skeptical whether people would connect with these kinds of topics on my blog or not. But because now this thought is constantly juggling in my head, S...]]></description><link>https://apoorvtyagi.tech/dunning-kruger-effect-and-imposter-syndrome</link><guid isPermaLink="true">https://apoorvtyagi.tech/dunning-kruger-effect-and-imposter-syndrome</guid><category><![CDATA[impostor syndrome]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[General Advice]]></category><category><![CDATA[DevLife]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Mon, 17 May 2021 04:20:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1621075101757/0RIiv6f3v.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article has been in my drafts for a long time but I never clicked that Publish button as I was skeptical whether people would connect with these kinds of topics on my blog or not. But because now this thought is constantly juggling in my head, So here it goes!</p>
<p>Software Development is one of those fields that is fast-paced, and always in flux. It’s what makes the field so challenging, interesting, and fun all at the same time. </p>
<p>But that also means that you will constantly keep coming across the stuff you don’t know. And even the stuff that you use to think you know but actually you don’t, which is why a lot of us face the situation like the imposter syndrome and the Dunning Kruger effect (a lot!).</p>
<h2 id="imposter-syndrome">Imposter Syndrome</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621075167452/fKsgeQHhM.png" alt="0_G6AwV-9UJkDNEQLz.png" /></p>
<p>For those unfamiliar with the term <em>imposter syndrome</em>, It is when a person starts to doubt their own capabilities &amp; accomplishments and believes that they are a fraud and have succeeded only through luck and soon people will realize they don't know what they are talking about. </p>
<p>It is when someone is being too hard on themselves and not giving themselves the credit for what they deserve and achieved. Instead, the achieving individuals believe that they have been only lucky in their achievements and they haven't done anything major to achieve it.</p>
<h3 id="is-it-good-or-bad">Is it good or bad?</h3>
<p>I think the imposter syndrome is both good and bad.</p>
<p>It's bad because this can become a cause of anxiety and unhappiness in someone's life, who by all means should be proud of their work and accomplishments.</p>
<p>Furthermore, I think why so many software developers face imposter syndrome is because -</p>
<ul>
<li><strong>Measuring all the work</strong></li>
</ul>
<p>Whatever solution you come up with, it’s very easy to measure the “efficiency” of that solutions. And no one would feel proud if another developer came in and improved the code by 500% in a just few days where you have spent perhaps weeks or months.</p>
<p>This leads to the thinking that they're not qualified enough and all that they have achieved is solely through luck.</p>
<ul>
<li><strong>Global Competition</strong></li>
</ul>
<p>From online coding contests to interviewing to raising PRs for open-source to full-fledged industry-level product development. The software industry is very big and growing very fast, so the competition is inevitable and global – it’s not limited by physical/geographic distance.</p>
<p>And that is just another reason to not feel comfortable at all times.</p>
<ul>
<li><strong>Forgetting the difficulty of things</strong></li>
</ul>
<p>In the process of comparing, or working alongside highly capable developers, it's very easy to lose track of the high quality of work that’s going around. But I think it's OK to feel mediocre as long as you know you’re learning, growing, and contributing back to the community.</p>
<p>At the same time why I feel it is good is because - </p>
<p>Here are some reasons why:</p>
<ul>
<li><p><strong>It Indicates you’re pushing yourself</strong></p>
</li>
<li><p><strong>It acts as a signal that you’re gaining expertise</strong></p>
</li>
</ul>
<h2 id="dunning-kruger-effect">Dunning-Kruger effect</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621075191288/a6iICpvu4.jpeg" alt="Dunning-Kruger.jpg" /></p>
<p>The Dunning-Kruger effect is a cognitive bias stating the relationship between an individual’s perceived knowledge of the subject matter and its ACTUAL knowledge.</p>
<p>In 1999, Dunning and Kruger conducted a study: <em>Unskilled and Unaware of It: How difficulties in Recognizing One's Incompetence Lead to Inflated Self-Assessments</em></p>
<blockquote>
<p>The result of their study found that those who are incompetent tend to overestimate their abilities, while those who are competent underestimate them</p>
</blockquote>
<p>If you observe the above graph you’ll see that beginners or less experienced devs are mostly under the impression that they are familiar with all that exists in their field and they're Pro.</p>
<p>In the simpler way of interpreting the graph, we can say, <strong>The inexperienced do not know what they do not know.</strong></p>
<h3 id="but-why-does-it-happen">But WHY does it happen?</h3>
<p>It happens because the experienced developers, or those on the track to becoming experienced, know how vast the field of software development is. They know what they don’t understand.</p>
<p>Can you see how this can cause an imposter syndrome to come up?</p>
<p>By knowing this effect in addition to being aware of imposter syndrome, we can handle imposter syndrome better.</p>
<h2 id="managing-imposter-syndrome">Managing Imposter Syndrome</h2>
<p>In general, I believe the following tips help to handle imposter syndrome while understanding the Dunning Kruger Effect:</p>
<ul>
<li><p><strong>Make a list of your accomplishments</strong>
Track your achievements. All of them. It doesn't matter how big or small it is. When something good happens, just make a note of it with a description of the effort you took to achieve it.</p>
</li>
<li><p><strong>Understand the bell curve</strong>
The bell curves depict that most of us are indeed average, so by learning a bit more each day or week you gradually move towards the right part of the graph. And that's what we should aim for as well. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621075731288/LW2G0RVSI.jpeg" alt="bell.jpg" /></p>
</li>
<li><p><strong>Peer Pairing</strong> 
Making a  “peer pair” with someone who is going through the same situation as what you’re going through. It can be helpful as you'll be able to discuss both your success and failures with them. There’s a lot of fellow beginners out there in the developer community and everyone is a newbie in something. So, you can easily find someone with whom you can share your learnings.</p>
</li>
</ul>
<p>Apart from these suggestions, I also <strong>believe the most important part in preventing imposter syndrome comes from focusing on becoming a life-long learner</strong>. Take some time to yourself each day to read about new developments in your field, train on a technology you haven't yet used.</p>
<p><strong>Pick something and practice it, regularly.</strong></p>
<p>The Dunning Kruger Effect shows that the more you know, the more you feel like you don't - accept and prosper from this. If you ever feel like you don't know anything, just remember <strong>It actually means progress, It means growth, It means you still have areas where you can grow and learn</strong></p>
<p>Thanks for reading :)</p>
<h2 id="other-articles-you-might-like">Other Articles You Might Like 🙂</h2>
<ul>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/useful-resources-to-learn-web-development-and-to-create-your-website">Useful Resources To Learn Web Development &amp; To Create Your Website</a> - Resources I found helpful in my web development journey.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/7-chrome-extensions-to-enhance-github-experience">Chrome extensions I use to enhance my GITHUB experience</a> - Here are 7 extensions I use to improve my Github experience.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/the-most-famous-coding-interview-question">The Most Famous Coding Interview Question</a> - What's the most asked coding interview question? And how to approach it.</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/welcome-to-the-world-of-nft">Welcome to the world of "NFTs"</a> - What are NFTs? And why are they suddenly becoming the next big thing?</p>
</li>
<li><p><a target="_blank" href="https://apoorvtyagi.tech/creating-blockchain-python">What is Blockchain Technology? Learn by creating one</a> - What is a blockchain? How do they work? Learn by creating one.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Chrome extensions to enhance your GITHUB experience]]></title><description><![CDATA[As a developer, we use GitHub every day and it is already a great tool, but what if we can make it even better with some chrome extensions!
Let's have a look at some of them 🔽
1. Octotree
It enhances GitHub code review and exploration with features ...]]></description><link>https://apoorvtyagi.tech/7-chrome-extensions-to-enhance-github-experience</link><guid isPermaLink="true">https://apoorvtyagi.tech/7-chrome-extensions-to-enhance-github-experience</guid><category><![CDATA[General Programming]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[General Advice]]></category><category><![CDATA[chrome extension]]></category><dc:creator><![CDATA[Apoorv Tyagi]]></dc:creator><pubDate>Sun, 02 May 2021 10:19:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619288242152/-H_0wbSve.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer, we use GitHub every day and it is already a great tool, but what if we can make it even better with some chrome extensions!</p>
<p>Let's have a look at some of them 🔽</p>
<h2 id="1-octotree">1. Octotree</h2>
<p>It enhances GitHub code review and exploration with features like:</p>
<ul>
<li>IDE-like code tree</li>
<li>Folder and file search</li>
<li>Issues and Pull Request bookmarking</li>
<li>Support for private repositories</li>
</ul>
<p>I like this extension very much! It lets you explore the files and folders of a repository with a tree like structure.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619203748632/kD31fMviz.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/ovity/octotree">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/octotree-github-code-tree/bkhaagjahfmjljalopjnoealnfndnagc">Chrome Extension</a></p>
<h2 id="2-open-in-vs-code">2. Open in VS Code</h2>
<p>It Opens links to source code for any github repository in VSCode. Also works with Gitlab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619204674095/vKQMVm6Zt.png" alt="image.png" /></p>
<p>💡 <strong>Tip</strong>: In case you want to open the whole repository in GitHub directly with VSCode view rather than a single file, <strong>Just add 1s after github</strong>. Example: github.com/user/somerepository -&gt; github1s.com/user/somerepository.</p>
<p>⭐ <a target="_blank" href="https://github.com/aberonni/open-in-vscode/">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/open-in-vscode/pfakkjlkpobjeghlgipljkjmbgcanpji">Chrome Extension</a></p>
<h2 id="3-refined-github">3. Refined GitHub</h2>
<p>It simplifies the GitHub interface and adds useful features too, for instance:</p>
<ul>
<li>Adds reaction avatars showing who reacted to a comment</li>
<li>Adds one-click merge conflict fixers</li>
<li>Adds a button to revert all the changes to a file in a PR</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619204002705/pehwPzs5-.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/sindresorhus/refined-github">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/refined-github/hlepfoohegkhhmjieoechaddaejaokhf">Chrome Extension</a></p>
<h2 id="4-do-not-merge-wip">4. Do-not-merge-WIP</h2>
<p>Disables "Merge pull request" button while ANY of the following is true:</p>
<ul>
<li>Title contains "[wip]" (case insensitive)</li>
<li>Any tasks remain incomplete</li>
<li>Any commit messages remain prefixed with "squash!" or "fixup!"</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619204166496/2k9ZduLBDx.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/sanemat/do-not-merge-wip-for-github">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/do-not-merge-wip-for-gith/nimelepbpejjlbmoobocpfnjhihnpked">Chrome Extension</a></p>
<h2 id="5-enhanced-github">5. Enhanced GitHub</h2>
<p>It provides useful features on top of GitHub Website:</p>
<ul>
<li>Displays repo size</li>
<li>Displays each file size for every active branch</li>
<li>Show download link for each file</li>
<li>Copy file's contents directly to Clipboard</li>
<li>Download file while viewing its contents.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619203340677/k84mGK11Q.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/softvar/enhanced-github">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/enhanced-github/anlikcnbgdeidpacdbdljnabclhahhmd">Chrome Extension</a></p>
<h2 id="6-githunt">6. Githunt</h2>
<p>It lets you hunt the most starred projects on GitHub on any date. Very useful when you want to explore the most trending repo of the week/month/year.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619204391854/7pKgBRAr0.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/kamranahmedse/githunt">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/githunt/khpcnaokfebphakjgdgpinmglconplhp">Chrome Extension</a></p>
<h2 id="7-codecopy">7. CodeCopy</h2>
<p>It lets you copy the text from any file on github to your clipboard. Apart from Github it also works on :</p>
<ul>
<li>Stack Overflow</li>
<li>MDN</li>
<li>Medium</li>
<li>npm</li>
<li>Gist</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619204917866/JSHkUVKV5.png" alt="image.png" /></p>
<p>⭐ <a target="_blank" href="https://github.com/zenorocha/codecopy">Github Repo</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/codecopy/fkbfebkcoelajmhanocgppanfoojcdmg">Chrome Extension</a></p>
<h1 id="wrapping-up">Wrapping Up 👋</h1>
<p>So with this, we come to the end of the list! In case you know another extension that I haven't included but you find it useful, please feel free to share those in the comments below😀</p>
<p>I hope you have enjoyed this article and found it helpful.</p>
<p>Thanks For Reading :)</p>
<hr />
<p><em>"Enjoyed what you read??"</em> You can show some support💙 by <strong>Buying me some coffee☕</strong> </p>
<p><a href="https://www.buymeacoffee.com/apoorvtyagi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-violet.png" alt="Buy Me A Coffee" /></a></p>
]]></content:encoded></item></channel></rss>