<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Apoorv Tyagi</title>
    <description>The latest articles on Forem by Apoorv Tyagi (@apoorvtyagi).</description>
    <link>https://forem.com/apoorvtyagi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F456124%2F7e37c7f6-c466-46eb-b2c6-459ce943fc6d.jpeg</url>
      <title>Forem: Apoorv Tyagi</title>
      <link>https://forem.com/apoorvtyagi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/apoorvtyagi"/>
    <language>en</language>
    <item>
      <title>Recently, I tried to inspect our Dockerfile to understand our container setup.

But there wasn’t one.

Instead, we were using Jib - a tool that builds optimized Java container images without Dockerfiles or even Docker.

Here’s a complete deep dive 👇</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Tue, 10 Mar 2026 14:39:22 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/recently-i-tried-to-inspect-our-dockerfile-to-understand-our-container-setup-but-there-wasnt-1fi0</link>
      <guid>https://forem.com/apoorvtyagi/recently-i-tried-to-inspect-our-dockerfile-to-understand-our-container-setup-but-there-wasnt-1fi0</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf" class="crayons-story__hidden-navigation-link"&gt;What is Jib? A Complete Guide to Java Containerization Without Dockerfiles&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/apoorvtyagi" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F456124%2F7e37c7f6-c466-46eb-b2c6-459ce943fc6d.jpeg" alt="apoorvtyagi profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/apoorvtyagi" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Apoorv Tyagi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Apoorv Tyagi
                
              
              &lt;div id="story-author-preview-content-3335320" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/apoorvtyagi" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F456124%2F7e37c7f6-c466-46eb-b2c6-459ce943fc6d.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Apoorv Tyagi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf" id="article-link-3335320"&gt;
          What is Jib? A Complete Guide to Java Containerization Without Dockerfiles
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/containers"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;containers&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>devops</category>
      <category>docker</category>
      <category>containers</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What is Jib? A Complete Guide to Java Containerization Without Dockerfiles</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Tue, 10 Mar 2026 14:33:30 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf</link>
      <guid>https://forem.com/apoorvtyagi/what-is-jib-a-complete-guide-to-java-containerization-without-dockerfiles-4dmf</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I joined PayPay, one of the first things I tried to understand was how our services were containerized.&lt;/p&gt;

&lt;p&gt;A common exercise when joining a new backend team is to look at the Dockerfiles used across services as they often reveal interesting patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Which base images are used&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Whether the builds are optimized&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If multi-stage builds are implemented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Opportunities for reducing image size or improving caching&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So naturally, I went looking for the Dockerfile.&lt;/p&gt;

&lt;p&gt;But to my surprise… I couldn't find one.&lt;/p&gt;

&lt;p&gt;After digging a bit deeper, I realized something interesting. &lt;strong&gt;The project wasn’t using a Dockerfile at all.&lt;/strong&gt; Instead, it was using &lt;a href="https://github.com/GoogleContainerTools/jib" rel="noopener noreferrer"&gt;Jib&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Enter Jib
&lt;/h2&gt;

&lt;p&gt;Imagine shipping a Java microservice where changing a single line of code doesn’t force your CI pipeline to rebuild a massive container image.&lt;/p&gt;

&lt;p&gt;That’s exactly what Jib enables.&lt;/p&gt;

&lt;p&gt;Jib is an open-source container image builder for Java applications that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eliminates the need for a Dockerfile&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Does not require a Docker daemon&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integrates directly with Maven and Gradle&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of packaging your application as a single fat layer, Jib understands Java project structure and splits your application into optimized layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Runtime (base image)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application classes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of this layered structure, when you change only your application code, only the top layer is rebuilt and pushed.&lt;/p&gt;

&lt;p&gt;The result?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;⚡ Faster builds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🧱 Better caching&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🚀 Simpler CI pipelines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔧 Less Dockerfile maintenance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we'll explore how Jib works, when to use it, and how it compares to traditional Dockerfiles.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What is Jib?
&lt;/h2&gt;

&lt;p&gt;If you build Java applications and ship containers, you’ve probably written Dockerfiles like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eclipse-temurin:17-jre&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; target/app.jar app.jar&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", "-jar", "app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;But it’s not optimized for Java.&lt;/p&gt;

&lt;p&gt;This is where Jib changes the game.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 The Problem With Traditional Docker Builds
&lt;/h2&gt;

&lt;p&gt;Before Jib, containerizing Java apps required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Writing and maintaining Dockerfiles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installing Docker everywhere (including CI)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Packaging fat JARs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rebuilding full images for small code changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manually optimizing layers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even a small code change could invalidate caching and rebuild everything.&lt;/p&gt;

&lt;p&gt;That’s inefficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 How Jib Works
&lt;/h2&gt;

&lt;p&gt;Jib builds container images by splitting your app into logical layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Base Image (JRE)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application classes&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If dependencies don’t change → layer reused&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If only code changes → only top layer rebuilt&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This drastically improves CI speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Getting Started with Jib
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Maven Setup
&lt;/h3&gt;

&lt;p&gt;Add this to your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.google.cloud.tools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jib-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;to&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;image&amp;gt;&lt;/span&gt;ghcr.io/yourorg/yourapp&lt;span class="nt"&gt;&amp;lt;/image&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/to&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build &amp;amp; push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn compile jib:build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Gradle Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.google.cloud.tools.jib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"3.4.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;jib&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ghcr.io/yourorg/yourapp"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew jib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚔️ Dockerfile vs Jib - Which Is Better?
&lt;/h2&gt;

&lt;p&gt;This is the real question.&lt;/p&gt;

&lt;p&gt;The answer depends on some of the use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ When Jib Is Better
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Standard Java Microservices
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spring Boot&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Micronaut&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quarkus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plain Maven/Gradle apps&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jib integrates directly with your build system.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Faster CI/CD Pipelines
&lt;/h4&gt;

&lt;p&gt;Jib:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Does not require a Docker daemon&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Builds incremental layers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pushes smaller diffs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Produces reproducible builds&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If CI time matters, Jib usually wins.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Developer Simplicity
&lt;/h4&gt;

&lt;p&gt;No Dockerfile. No manual layering. Less DevOps friction.&lt;/p&gt;




&lt;h3&gt;
  
  
  🏗️ When Dockerfile Is Better
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. OS-Level Customization
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;apt-get install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Native libraries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom shell scripts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jib does not support arbitrary RUN commands.&lt;/p&gt;

&lt;p&gt;Dockerfile wins here.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Polyglot Applications
&lt;/h4&gt;

&lt;p&gt;If your container includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Node + Java&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python + Java&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple build tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom entrypoints&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dockerfile provides full flexibility.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Complex Multi-Stage Builds
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Compile native binaries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build frontend assets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run security scans during build&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy artifacts between stages&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dockerfile is more powerful here.&lt;/p&gt;

&lt;h2&gt;
  
  
  📊 Side-by-Side Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Feature&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Jib&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Dockerfile&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Requires Docker daemon&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;❌ No&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ Yes&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Requires Dockerfile&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;❌ No&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ Yes&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;OS Customization&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;❌ Limited&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ Full&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Java Layer Optimization&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ Automatic&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;❌ Manual&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;CI/CD Simplicity&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ High&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;⚠️ Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Multi-language builds&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;❌ No&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;✅ Yes&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Learning Curve&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Low&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 Real-World Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario A: 20 Spring Boot Microservices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kubernetes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub Actions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CI cost matters&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Jib is usually the better choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario B: Enterprise App With Native Dependencies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Custom Alpine base image&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OS packages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hardening scripts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-stage builds&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Dockerfile is better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario C: Small Startup Team
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Java-only stack&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No DevOps team&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Want fast pipelines&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Jib simplifies everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔬 Performance Insight
&lt;/h2&gt;

&lt;p&gt;Because Jib separates dependencies and classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Code-only changes rebuild in seconds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker layer cache invalidation is minimized&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CI builds are more predictable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In large microservice ecosystems, this adds up significantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Jib is optimized for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Java developer productivity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dockerfile is optimized for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Infrastructure control.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you build modern Java microservices → Start with Jib.&lt;/p&gt;

&lt;p&gt;If you need deep OS-level control → Use Dockerfile.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>containers</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Kafka Consumer Container Restarts in Kubernetes: A Production Case Study</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Wed, 11 Feb 2026 14:22:39 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/kafka-consumer-container-restarts-in-kubernetes-a-production-case-study-1iid</link>
      <guid>https://forem.com/apoorvtyagi/kafka-consumer-container-restarts-in-kubernetes-a-production-case-study-1iid</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Incident: When Bursts Turn Into Crashes
&lt;/h2&gt;

&lt;p&gt;It started with a Kafka topic.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And that’s when things began to fall apart.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;OOMKill&lt;/strong&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Investigation
&lt;/h2&gt;

&lt;p&gt;When we looked at the consumer topology, the first red flag was almost too obvious to ignore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kafka partitions:&lt;/strong&gt; 6&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Active consumer pods:&lt;/strong&gt; 10&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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, &lt;strong&gt;4 pods were effectively idle&lt;/strong&gt;, waiting on the sidelines.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;That explained &lt;em&gt;where&lt;/em&gt; the pressure was landing, but not &lt;em&gt;why&lt;/em&gt; it was causing hard crashes.&lt;/p&gt;

&lt;p&gt;To answer that, we moved to the next step: capturing a heap &amp;amp; thread dump in our staging environment while simulating a &lt;strong&gt;5X production load&lt;/strong&gt;. And that’s where things started getting really interesting.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ZGC Struggle
&lt;/h3&gt;

&lt;p&gt;We were initially running the service on &lt;a href="https://wiki.openjdk.org/spaces/zgc/pages/34668579/Main" rel="noopener noreferrer"&gt;&lt;strong&gt;ZGC&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;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: &lt;strong&gt;ZGC needs a lot of breathing room&lt;/strong&gt;. It relies heavily on having heap memoryto keep allocation and reclamation in balance.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;But it simply couldn’t reclaim memory fast enough.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Substitute: G1GC
&lt;/h3&gt;

&lt;p&gt;At this point, we decided to switch strategies and flipped the JVM to &lt;a href="https://www.oracle.com/technical-resources/articles/java/g1gc.html" rel="noopener noreferrer"&gt;G1GC&lt;/a&gt;, then reran the same load test.&lt;/p&gt;

&lt;p&gt;The difference was immediate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory usage:&lt;/strong&gt; Stabilized under 1 GiB (previously went up all the way to 3 GiB)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pause times:&lt;/strong&gt; Increased slightly to around 35 ms, still comfortably within our SLAs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stability:&lt;/strong&gt; No crashes. No restarts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;G1GC traded a bit of pause time for predictable memory behavior&lt;/strong&gt;, which turned out to be exactly what this workload needed. In a burst-heavy system, consistency beats theoretical best-case latency every single time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Side-Quest: The Slack Notifier "Leak"
&lt;/h3&gt;

&lt;p&gt;While digging through the thread dumps, we found a "Red Herring." Our &lt;code&gt;SlackNotifier&lt;/code&gt; class, which is responsible for sending failure alerts, was instantiating a new &lt;code&gt;OkHttpClient&lt;/code&gt; for every single error notification.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;OkHttpClient&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The fix was straightforward: refactor the notifier to use a single, shared &lt;code&gt;OkHttpClient&lt;/code&gt; singleton, ensuring controlled resource usage and predictable behavior.&lt;/p&gt;

&lt;p&gt;Not the root cause, but a critical cleanup uncovered at exactly the right time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Fixes
&lt;/h2&gt;

&lt;p&gt;To stabilize Merchant Finance, we didn’t just tweak application code—we &lt;strong&gt;re-aligned the infrastructure to match the workload it was actually handling.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s what we changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Memory Alignment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We set &lt;code&gt;memory.request&lt;/code&gt; to match &lt;code&gt;memory.limit&lt;/code&gt; at &lt;strong&gt;3 GiB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This ensured the &lt;strong&gt;node reserved the full memory upfront&lt;/strong&gt;, eliminating eviction pressure during bursts and preventing Kubernetes from stepping in with an OOMKill when memory usage spiked. [&lt;a href="https://www.reddit.com/r/kubernetes/comments/182op5z/why_is_it_a_good_idea_to_set_pod_requests_equal/" rel="noopener noreferrer"&gt;A reddit thread worth exploring&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Partition Scaling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We scaled the Kafka topic from &lt;strong&gt;6 partitions to 10&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This change ensured that &lt;strong&gt;every merchant service pod became an active consumer&lt;/strong&gt;, 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The GC Switch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We officially moved this service to G1GC.&lt;/p&gt;

&lt;p&gt;For this workload profile, we chose &lt;strong&gt;predictable memory behavior over ultra-low pause times&lt;/strong&gt;. Slightly higher pauses were a small price to pay for stability under burst-heavy traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. CPU Buffering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We increased the CPU request from &lt;strong&gt;100 millicores to 500 millicores&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Fixing &lt;code&gt;SlackNotifier&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we refactored &lt;code&gt;SlackNotifier&lt;/code&gt; to use a single shared &lt;code&gt;OkHttpClient&lt;/code&gt; instance instead of creating a new one per notification.&lt;/p&gt;

&lt;p&gt;It wasn’t the root cause, but it removed a hidden risk that could have turned a future incident into something far worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;After applying the infrastructure and JVM changes, we reran the same burst-heavy load tests and monitored JVM, Kubernetes, and Kafka metrics.&lt;/p&gt;

&lt;p&gt;The difference wasn’t subtle 👇&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. JVM Behavior (ZGC v.s. G1GC)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GC pause &lt;strong&gt;frequency dropped significantly&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GC avg pause &lt;strong&gt;times increase&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The change is clearly visible around &lt;strong&gt;12:00–12:10&lt;/strong&gt;, which is when the GC and infrastructure updates were applied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nxhm4hsjrux7ss5i3ht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nxhm4hsjrux7ss5i3ht.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." width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. G1GC Under Load&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switching away from ZGC did increase pause times, but well within acceptable limits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Average GC pause:&lt;/strong&gt; ~30–40 ms&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Flat, predictable, no spikes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; No effect on SLAs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was an intentional trade-off. We gave up ultra-low pause times in exchange for a lower GC pause count and memory predictability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8vj3faybvhl6ynfw40r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8vj3faybvhl6ynfw40r.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." width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Kubernetes Pods Stopped Restarting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From a platform perspective, this was the most important outcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pod restarts:&lt;/strong&gt; 0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OOM events:&lt;/strong&gt; None&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory usage:&lt;/strong&gt; Stable across all pods&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU usage:&lt;/strong&gt; Predictable, with sufficient headroom during GC cycles&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Container-level metrics after the fixes - memory usage remains stable, CPU has sufficient headroom, and pod restarts drop to zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpc7hgs6iiz9ti33runvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpc7hgs6iiz9ti33runvi.png" alt="Kubernetes pod metrics after infrastructure fixes, showing stable memory usage, controlled CPU consumption, zero pod restarts, and no OOMKill events under load." width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Kafka Kept Up With Bursts Without Errors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we looked at the Kafka side of the system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumer lag:&lt;/strong&gt; Spiked briefly during bursts, then drained smoothly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumer latency (P95):&lt;/strong&gt; Stable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Errors:&lt;/strong&gt; None observed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Throughput:&lt;/strong&gt; Fully sustained during burst windows&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Increasing the partition count ensured every pod actively participated in consumption, preventing load concentration and smoothing out processing during spikes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxr8ftu09b19on2j35up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxr8ftu09b19on2j35up.png" alt="Kafka consumer metrics during burst traffic including throughput, consumer lag, and P95 latency, demonstrating stable consumption and zero consumer errors." width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kafka consumer metrics during burst traffic. Lag increases temporarily but recovers quickly, with no errors and stable latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Outcome
&lt;/h2&gt;

&lt;p&gt;After all fixes were applied:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ No pod restarts during burst traffic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ No OOMKills&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Predictable JVM behavior under load&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Kafka bursts handled without errors&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resilience isn’t just about handling errors after they happen, it’s about understanding how your system behaves under load.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Sometimes, the “latest and greatest” option isn’t the right fit for every workload. Stability often comes from choosing the tool that behaves &lt;em&gt;predictably&lt;/em&gt; under stress, not the one that looks best on paper.&lt;/p&gt;

&lt;p&gt;In production, boring and predictable almost always win.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>kafka</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>How we solved cache invalidation in Kubernetes with a headless service</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Mon, 29 Dec 2025 06:45:00 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/how-we-solved-cache-invalidation-in-kubernetes-with-a-headless-service-34dg</link>
      <guid>https://forem.com/apoorvtyagi/how-we-solved-cache-invalidation-in-kubernetes-with-a-headless-service-34dg</guid>
      <description>&lt;h2&gt;
  
  
  ⬅️ Background
&lt;/h2&gt;

&lt;p&gt;At my previous organization, we were building a health platform, and one of the most critical, high-traffic components was our &lt;a href="https://www.bajajfinservhealth.in/lab-tests" rel="noopener noreferrer"&gt;Lab test booking service&lt;/a&gt;. One of its core functions is to serve package details like inclusions, prices, and provider information for thousands of user requests daily.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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, “&lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#headless-services" rel="noopener noreferrer"&gt;&lt;strong&gt;The&lt;/strong&gt; &lt;strong&gt;Headless Service&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;”&lt;/strong&gt; to handle distributed cache invalidation flawlessly.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛑 The Problem: Fast Caching &amp;amp; Scalable Invalidation
&lt;/h2&gt;

&lt;p&gt;We decided on &lt;strong&gt;in-memory caching&lt;/strong&gt; using a library like &lt;code&gt;@nestjs/cache-manager&lt;/code&gt; 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: &lt;strong&gt;Cache Inconsistency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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*&lt;em&gt;.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;We needed a broadcasting mechanism.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Solution: The K8s Headless Service
&lt;/h2&gt;

&lt;p&gt;Our strategy was a hybrid approach: &lt;strong&gt;local caching for performance&lt;/strong&gt;, and a &lt;strong&gt;targeted internal HTTP broadcast for invalidation&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Headless Services for Pod Discovery
&lt;/h3&gt;

&lt;p&gt;This is the key to the whole solution. A standard Kubernetes service acts as a load balancer with a single Virtual IP. But a &lt;strong&gt;Headless Service&lt;/strong&gt; is different. By setting &lt;code&gt;clusterIP: None&lt;/code&gt; in the Service manifest (&lt;code&gt;.spec.clusterIP&lt;/code&gt;), Kubernetes skips the load balancer and, crucially, &lt;strong&gt;returns a list of individual DNS A records for every active pod’s IP address&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is the simple(yet powerful) Headless Service manifest we deployed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;booking-service-headless&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;             &lt;span class="c1"&gt;# THE TRICK: Makes it Headless&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;booking-service&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3000&lt;/span&gt;        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when we resolve &lt;code&gt;booking-service-headless.default.svc.cluster.local&lt;/code&gt;, we get an array of all current, healthy pod IPs.&lt;/p&gt;

&lt;p&gt;For visualization, here's a diagram of Headless Services in action:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Step 2 &amp;amp; 3: Broadcast Implementation
&lt;/h3&gt;

&lt;p&gt;In the next step, we added &lt;code&gt;kubectl&lt;/code&gt; into our Docker image for API queries. This gives the pod the power to query the Kubernetes API directly.  &lt;/p&gt;

&lt;p&gt;To implement this safely, we followed the &lt;strong&gt;Principle of Least Privilege&lt;/strong&gt;. We created a dedicated &lt;code&gt;ServiceAccount&lt;/code&gt; for our booking service and bound it to a specific &lt;code&gt;Role&lt;/code&gt; using RBAC (Role-Based Access Control). This Role was strictly limited: it only allowed the &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt; operations on the &lt;code&gt;endpoints&lt;/code&gt; resource within its own namespace. This ensures that even if a pod is compromised, an attacker cannot delete resources or view sensitive secrets.&lt;/p&gt;

&lt;p&gt;Second, we created a simple, internal &lt;code&gt;/invalidate-cache&lt;/code&gt; 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 &lt;code&gt;del()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;When an admin update happens, and the data is written to MySQL, the pod that handles the write executes a bash script using &lt;code&gt;kubectl&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;It uses &lt;code&gt;kubectl&lt;/code&gt; to get the list of IPs from the Headless Service endpoints, then sends a &lt;strong&gt;direct HTTP POST request&lt;/strong&gt; to the internal &lt;code&gt;/invalidate-cache&lt;/code&gt; endpoint on &lt;em&gt;each pod&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Executed&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;
&lt;span class="nx"&gt;pod_ips&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kubectl&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;endpoints&lt;/span&gt; &lt;span class="nx"&gt;listing&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{.subsets[0].addresses[*].ip}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;$pod_ips&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="nx"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//$ip:3000/v2/invalidate\&lt;/span&gt;
       &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;H&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type: application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"key": "package-123"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Clears&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;specific&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;
&lt;span class="nx"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the system is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dynamic:&lt;/strong&gt; The IP list is fresh at invalidation time, handling upscaling, downscaling and restarts seamlessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Targeted:&lt;/strong&gt; We clear only the stale package key, maximizing cache retention.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost-Effective:&lt;/strong&gt; Zero new service bills.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt;: Add curl retries and logging for failed broadcasts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For those looking to keep their Docker images clean, you can avoid installing &lt;code&gt;kubectl&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt; entirely by using the official &lt;code&gt;@kubernetes/client-node&lt;/code&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📈 Production Results and Takeaways
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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*&lt;em&gt;.&lt;/em&gt;* It’s about being smart with your infrastructure, not just throwing money at the problem.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>architecture</category>
      <category>kubernetes</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Going Vernacular: Engineering Our Way to Process Multilingual Names</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Mon, 04 Dec 2023 06:30:00 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/going-vernacular-engineering-our-way-to-process-multilingual-names-5mh</link>
      <guid>https://forem.com/apoorvtyagi/going-vernacular-engineering-our-way-to-process-multilingual-names-5mh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400" rel="noopener noreferrer"&gt;400 BAD REQUEST&lt;/a&gt; errors, and the root cause was traced back to a regex check.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Data Storage Strategy
&lt;/h3&gt;

&lt;p&gt;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 &lt;a href="https://www.mongodb.com/docs/manual/reference/collation/" rel="noopener noreferrer"&gt;simple collation&lt;/a&gt; method. The corresponding fields are appropriately indexed to optimize query performance.&lt;/p&gt;

&lt;p&gt;While the option to implement a &lt;a href="https://www.mongodb.com/docs/manual/reference/collation/" rel="noopener noreferrer"&gt;collation index&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. API Gateway Constraint
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;A multitude of APIs rely on this user-specific data in headers for their further processing.&lt;/p&gt;

&lt;p&gt;However, there's a restriction imposed by the gateway – it allows only &lt;a href="https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html" rel="noopener noreferrer"&gt;ASCII&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;Also, this process must remain fast, as any delay in authentication could lead to sluggish API performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. External Partners' Challenge with Vernacular Names
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutioning
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Therefore, we developed a dual-naming strategy. The original fields, &lt;code&gt;"firstName"&lt;/code&gt; and &lt;code&gt;"lastName"&lt;/code&gt; would retain the user-entered names in their entered language, while we introduced two additional fields, &lt;code&gt;"englishFirstName"&lt;/code&gt; and &lt;code&gt;"englishLastName"&lt;/code&gt; dedicated to storing the English counterparts of these names. These English names could then be shared with the API gateway and our payment partners.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;englishFirstName&lt;/code&gt; and &lt;code&gt;englishLastName&lt;/code&gt; at the time of any insert or update.&lt;/p&gt;

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

&lt;p&gt;This strategy provided the flexibility we needed to manage multilingual names seamlessly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Design Considerations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Unicode Optimization
&lt;/h4&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Transliteration vs. Translation
&lt;/h4&gt;

&lt;p&gt;Initially, our aim was transliteration, which requires converting names from one script to another while retaining their phonetic sound. For example, the Hindi word &lt;code&gt;"प्रतीक्षा"&lt;/code&gt; should be transformed to &lt;code&gt;"Partiksha"&lt;/code&gt; and not translated to its English equivalent i.e. &lt;code&gt;"Wait"&lt;/code&gt;. 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.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Contextual Enhancements
&lt;/h4&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;p&gt;Translating names normally led to their literal translation. For example "प्रतीक्षा" to "Wait" instead of "Pratiksha":&lt;/p&gt;

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

&lt;p&gt;Adding a prefix statement corrected it:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Initial Code
&lt;/h2&gt;

&lt;p&gt;After our first iteration, we developed the below code for transliteration. Here we are using the &lt;code&gt;@iamtraction/google-translate&lt;/code&gt; library which is a wrapper written over free Google translate API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@iamtraction/google-translate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getGoogleTranslateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    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.
  */&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`name: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`your name is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;translateNameToEnglish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z &lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the name is already in English just return&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getGoogleTranslateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translatedName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;translatedName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="c1"&gt;// In case of error, Return the Unicode string&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beta Release and Production Challenges
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Some names were incorrectly transliterated&lt;/strong&gt;. This occurrence could be attributed to our dependence on Google Translate, a general translation service, rather than a specialized transliteration service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Some names remained unaltered and were not transliterated&lt;/strong&gt;. 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.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Hence, we incorporated unidecode into our algorithm as part of our solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved Solution
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@iamtraction/google-translate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unidecode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unidecode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isAlmostEqualStrings&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./levenshtein&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/**
 *
 * @param {String} localName
 * @description Generates text for Google (shorter statement context for short names) based on localName length
 * @returns {String} returns text to translate
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getGoogleTranslateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    Adding an English sentence before name so that
    it doesn't get translated to its literal meaning.
    For eg परीक्षा to Exam instead of Pariksha.
  */&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`name: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`your name is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 *
 * @param {String} localName
 * @description Give an ALMOST transliterated name
 * @returns {String} returns a converted transliterated name from the local language
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;transliterate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;googleTranslatedName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodedName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;unidecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;decodedName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedName&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt;
      &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;googleTranslatedName&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAlmostEqualStrings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;googleTranslatedName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decodedName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;googleTranslatedName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 *
 * @param {String} Input non English string
 * @description translates non-english string to English
 * @returns {String} returns translated string
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;translateNameToEnglish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z &lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If name is already in English just return&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getGoogleTranslateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translatedName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transliterate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;translatedName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="c1"&gt;// In case of error, Return original string&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;localName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After obtaining the translated name, we feed it into the recently introduced &lt;code&gt;transliterate&lt;/code&gt; function. Inside this function, our initial step involves extracting the decoded string using the &lt;code&gt;Unidecode&lt;/code&gt; 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?&lt;/p&gt;

&lt;p&gt;To tackle this, we implemented &lt;a href="https://en.wikipedia.org/wiki/Levenshtein_distance" rel="noopener noreferrer"&gt;&lt;strong&gt;Levenshtein Distance&lt;/strong&gt;&lt;/a&gt;, an algorithm that calculates the similarity between two strings.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If it does match then we go for the Levenshtein Distance algorithm.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the implementation, we have a function &lt;code&gt;isAlmostEqualStrings&lt;/code&gt; 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&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This updated algorithm substantially reduced the above mentioned issues. Even though it's not 100% accurate it solved our 5% cases very well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The complete code for the above implementation along with the Levenshtein Distance algorithm can be found on &lt;a href="https://github.com/ApoorvTyagi/english-transliterate" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; (contributions/corrections are welcome).&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/apoorv__tyagi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/apoorvtyagi/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apoorvtyagi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy learning!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>node</category>
      <category>systemdesign</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>How to Keep Your Package Dependencies Up to Date on Azure DevOps</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Sun, 03 Dec 2023 13:30:00 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/how-to-keep-your-package-dependencies-up-to-date-on-azure-devops-4d0p</link>
      <guid>https://forem.com/apoorvtyagi/how-to-keep-your-package-dependencies-up-to-date-on-azure-devops-4d0p</guid>
      <description>&lt;p&gt;As a developer, how often have you seen a repository with packages that are out of date?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So to do this sort of housekeeping, I tried out &lt;a href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How Dependabot Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Dependabot goes through the dependency files of your project. For instance, it searches your &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;pom.xml&lt;/code&gt; files and inspects for any outdated or insecure dependencies. If it finds any, it opens individual pull requests to update each one of them.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If you go to &lt;a href="https://marketplace.visualstudio.com/azuredevops" rel="noopener noreferrer"&gt;Azure DevOps Extension Marketplace&lt;/a&gt; and search for "Dependabot", you will find an &lt;a href="https://marketplace.visualstudio.com/items?itemName=tingle-software.dependabot" rel="noopener noreferrer"&gt;extension&lt;/a&gt; by Tingle Software. Using this extension we can easily integrate Dependabot with our repos in Azure DevOps.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;Installed Extensions - Azure DevOps&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Create the Azure Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's now start with creating a new &lt;code&gt;YAML&lt;/code&gt; file for your Azure pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;none&lt;/span&gt;

&lt;span class="nx"&gt;stages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CheckDependencies&lt;/span&gt;
    &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Check Dependencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Dependabot&lt;/span&gt;
        &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Run Dependabot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nx"&gt;vmImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dependabot&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;1&lt;/span&gt;
            &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Run Dependabot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="nx"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
              &lt;span class="nx"&gt;packageManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
              &lt;span class="nx"&gt;targetBranch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;develop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
              &lt;span class="nx"&gt;openPullRequestsLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the task parameters, I have specified three params:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;packageManager&lt;/strong&gt;: It specifies the type of packages to check for dependency upgrades. Examples: &lt;code&gt;nuget&lt;/code&gt;, &lt;code&gt;maven&lt;/code&gt;, &lt;code&gt;gradle&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt;, and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;targetBranch&lt;/strong&gt;: It is an optional parameter that defines the branch to be targeted when creating pull requests. When not specified, Dependabot will pick the &lt;code&gt;default&lt;/code&gt; branch of the repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;openPullRequestsLimit&lt;/strong&gt;: 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.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can go through all the &lt;a href="https://github.com/tinglesoftware/dependabot-azure-devops/blob/main/src/extension/README.md#task-parameters" rel="noopener noreferrer"&gt;Task Parameters&lt;/a&gt; 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.&lt;/p&gt;

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

&lt;p&gt;Pipeline Configuration - Azure DevOps&lt;/p&gt;

&lt;p&gt;The next step is to give your repository's &lt;code&gt;Project Collection Build Service&lt;/code&gt; access so that Dependabot can create the pull request to your project's repositories.&lt;/p&gt;

&lt;p&gt;For that, go to your project settings. Here, you click on the repositories and search for the repo where you have integrated the pipeline.&lt;/p&gt;

&lt;p&gt;After you have selected that, click on the security tab and search for &lt;strong&gt;project collection build service&lt;/strong&gt;. You have to allow the following access to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Contribute&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contribute to pull request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Tag&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Force Push&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Access to raise PR in Repo&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;PR raised by Dependabot&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Schedule the Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Use the following syntax and add it to the very top of your &lt;code&gt;YAML&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;schedules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The branche*s’* &lt;code&gt;include&lt;/code&gt; parameter specifies which branches the schedule applies to.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;always&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;For this case, you set its value to &lt;strong&gt;true&lt;/strong&gt; as Dependabot updates are independent of any code changes.&lt;/p&gt;

&lt;p&gt;The time zone for cron schedules is UTC and cron syntax is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mm&lt;/span&gt; &lt;span class="nx"&gt;HH&lt;/span&gt; &lt;span class="nx"&gt;DD&lt;/span&gt; &lt;span class="nx"&gt;MM&lt;/span&gt; &lt;span class="nx"&gt;DW&lt;/span&gt;
 &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;__&lt;/span&gt; &lt;span class="nx"&gt;Days&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;week&lt;/span&gt;
  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;____&lt;/span&gt; &lt;span class="nx"&gt;Months&lt;/span&gt;
   &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;______&lt;/span&gt; &lt;span class="nx"&gt;Days&lt;/span&gt;
    &lt;span class="err"&gt;\&lt;/span&gt;  &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;________&lt;/span&gt; &lt;span class="nx"&gt;Hours&lt;/span&gt;
     &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;__________&lt;/span&gt; &lt;span class="nx"&gt;Minutes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you want to run your pipeline every week on Sunday at 12pm UTC, you would need to write - &lt;code&gt;cron: "0 12 * * 0"&lt;/code&gt; (update the cron to suit your needs).&lt;/p&gt;

&lt;p&gt;This is how your final &lt;code&gt;YAML&lt;/code&gt; should look like after adding a schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schedules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;12&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Weekly Dependency Updates&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CheckDependencies&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dependabot&lt;/span&gt;
        &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependabot'&lt;/span&gt;
        &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependabot@1&lt;/span&gt;
            &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependabot'&lt;/span&gt;
            &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;packageManager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
              &lt;span class="na"&gt;targetBranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;develop'&lt;/span&gt;
              &lt;span class="na"&gt;openPullRequestsLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pipeline does the following for you:&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Hopefully, this will help you to keep your project dependencies up to date in Azure DevOps!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/apoorv__tyagi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linkedin.com/in/apoorvtyagi/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/apoorvtyagi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy learning! 💻 😄&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Finding a Needle in Haystack: Fixing Mysterious Bad Gateway</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Sun, 12 Mar 2023 06:30:00 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/finding-a-needle-in-haystack-fixing-mysterious-bad-gateway-1571</link>
      <guid>https://forem.com/apoorvtyagi/finding-a-needle-in-haystack-fixing-mysterious-bad-gateway-1571</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;As soon as we made the alert system live, we started noticing a few HTTP 502 “Bad Gateway” errors occurring every day but intermittently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As per &lt;a href="https://tools.ietf.org/html/rfc7231#section-6.6.3" rel="noopener noreferrer"&gt;RFC7231&lt;/a&gt;, 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With very little known information, I began chasing down the RCA for these failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I observed the request despite coming from the API gateway, the response sent was 502, without even communicating with my application.&lt;/p&gt;

&lt;p&gt;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 &amp;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving in TCP Connection
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This mechanism is known as &lt;a href="https://en.wikipedia.org/wiki/HTTP_persistent_connection" rel="noopener noreferrer"&gt;HTTP keep-alive&lt;/a&gt;, 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.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging, further
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;FIN&lt;/code&gt; segment to the same socket. The proxy socket acknowledges the &lt;code&gt;FIN&lt;/code&gt; and starts a new handshake process.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;RST&lt;/code&gt; segment back to the proxy server. The proxy server then returns a 502 error to the user.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://nodejs.org/api/http.html#http_server_keepalivetimeout" rel="noopener noreferrer"&gt;5 seconds&lt;/a&gt;. 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 &lt;code&gt;FIN&lt;/code&gt;, it sends the request down the dead connection, receives nothing in response, and therefore throws a 502 error.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix
&lt;/h2&gt;

&lt;p&gt;A possible solution is to ensure that the upstream (application) idle connection timeout is longer than the downstream (proxy) connection timeout.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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. &lt;em&gt;Therefore, setting appropriate upstream and downstream timeouts is crucial for the smooth functioning of web applications&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The below example illustrates how to modify the default keep-alive timeout for an &lt;a href="https://expressjs.com/en/starter/hello-world.html" rel="noopener noreferrer"&gt;Express&lt;/a&gt; app:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keepAliveTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;76&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;// Time in ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Theoretically, this race condition can occur anytime when the connections are reused &amp;amp; if the upstream service drops connections before the downstream.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;ACK&lt;/code&gt; for the sent request, the proxy gets TCP &lt;code&gt;FIN&lt;/code&gt; (and eventually &lt;code&gt;RST&lt;/code&gt;) from the upstream.&lt;/p&gt;

&lt;p&gt;The proxy server then just gives up on such requests and responds immediately with HTTP 502 error to the client. &lt;strong&gt;And this is completely invisible on the application side!&lt;/strong&gt; That's why no application logs were visible to us.&lt;/p&gt;

&lt;p&gt;To mitigate this you can either make sure the upstream (application) idle connection timeout is longer than the downstream (proxy) connection timeout OR &lt;a href="https://dev.to/apoorvtyagi/building-resilient-systems-retry-pattern-in-microservices-1ngj"&gt;implement retries on HTTP 5xx errors&lt;/a&gt; from the API gateway.&lt;/p&gt;

&lt;p&gt;I hope you found it helpful. Comments or corrections are always welcome.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building Resilient Systems: Retry Pattern in Microservices</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Fri, 10 Mar 2023 04:10:00 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/building-resilient-systems-retry-pattern-in-microservices-1ngj</link>
      <guid>https://forem.com/apoorvtyagi/building-resilient-systems-retry-pattern-in-microservices-1ngj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Any application that communicates with other resources over a network has to be resilient to transient failures.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;Retries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Let’s start by first defining what we mean by failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a failure?
&lt;/h2&gt;

&lt;p&gt;Failures can be caused by numerous reasons while our services communicate with each other over a network. Some examples of types of failures are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A slow response / No response at all&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A response in the incorrect format&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A response containing incorrect data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In planning for failures, we should seek to handle each of these errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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 &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Idempotent" rel="noopener noreferrer"&gt;&lt;strong&gt;idempotent&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In REST APIs, &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;HEAD&lt;/code&gt; and &lt;code&gt;OPTIONS&lt;/code&gt; methods generally do not change the resource state on the server and hence are mostly retryable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  When should we retry a request?
&lt;/h3&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem with normal retries
&lt;/h2&gt;

&lt;p&gt;Consider what happens when we get 100,000 concurrent requests &amp;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://en.wikipedia.org/wiki/Thundering_herd_problem" rel="noopener noreferrer"&gt;Thundering Herd&lt;/a&gt; problem.&lt;/p&gt;

&lt;p&gt;To tackle this, we can introduce some delay in retrying a failed request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backoff
&lt;/h3&gt;

&lt;p&gt;The wait time between a request and its subsequent retry is called the backoff.&lt;/p&gt;

&lt;p&gt;With backoff, the amount of time between requests increases exponentially as the number of retry requests increases.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jitter
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Jitter is the process of breaking this synchronization by increasing or decreasing the backoff delay to further spread out the load.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Going through this &lt;a href="https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt; that goes deep into the exponential backoff algorithm, we have implemented our retry mechanism using &lt;a href="https://axios-http.com/docs/interceptors" rel="noopener noreferrer"&gt;Axios interceptor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example is written inside of a Nodejs application, but the process will be similar regardless of which JavaScript framework you’re using.&lt;/p&gt;

&lt;p&gt;In this, we expect the following settings:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total Retries&lt;/strong&gt; The number of maximum retries you want before returning a failed response to the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retry Status Codes&lt;/strong&gt; The HTTP status codes that you want to retry for. By default, we have kept it on for all status codes &amp;gt;=500.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backoff&lt;/strong&gt; This is the minimum time we have to wait while sending any subsequent retry request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalRetry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retryCount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryStatusCodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retryStatusCodes&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isRetryRequired&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;retryStatusCodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;totalRetry&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;){&lt;/span&gt;

      &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
          &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="c1"&gt;// Create a new promise with exponential backoff&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backOffWithJitterTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentRetryCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;backOffWithJitterTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="c1"&gt;// Return the promise in which recalls Axios to retry the request&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isRetryRequired&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;retryStatusCodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;totalRetry&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;){&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;retryStatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;currentRetryCount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;totalRetry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numRetries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waitTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;numRetries&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Multiply waitTime by a random number between 0 and 1.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;waitTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While making an Axios request you have to make sure to add the variables in the request configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xxx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;retryCount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;retryStatusCodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;408&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;429&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="na"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Pictorially this is how it will work:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;For Java based applications, the same can be done using &lt;a href="https://resilience4j.readme.io/docs/retry" rel="noopener noreferrer"&gt;resilience4j&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I hope you found it helpful. Comments or corrections are always welcome.&lt;/p&gt;

&lt;p&gt;GitHub Link for the above source code can be found &lt;a href="https://github.com/ApoorvTyagi/node-retry" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>architecture</category>
      <category>javascript</category>
      <category>microservices</category>
    </item>
    <item>
      <title>How to Choose The Right Database for Your Application</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Sun, 15 May 2022 11:57:02 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/how-to-choose-the-right-database-for-your-application-1dk3</link>
      <guid>https://forem.com/apoorvtyagi/how-to-choose-the-right-database-for-your-application-1dk3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Choosing which database to use is one of the most important decisions you can make when starting working on a new app or website.&lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;Taking time to make an informed choice of database technology upfront can be a valuable early decision for your application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(A bonus reason for why this is important is because understanding the different DBs and their properties &amp;amp; which one to choose over the other is quite commonly asked in job interviews)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In this article, we will go through the factors you should consider while choosing any database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The language determines the database
&lt;/h2&gt;

&lt;p&gt;First things first. The language or the technology you are going to use never determines the database ❌&lt;/p&gt;

&lt;p&gt;We’ve grown accustomed to technology stacks, such as MERN (MongoDB, Express, React, Node.js) &amp;amp; LAMP (Linux, Apache, MySQL, PHP).&lt;/p&gt;

&lt;p&gt;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;amp; not the language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Tradeoff
&lt;/h2&gt;

&lt;p&gt;Let's now understand the basic tradeoffs we need to deal with while making the DB decision.&lt;/p&gt;

&lt;p&gt;The reason that we have many database options available today is due to the CAP Theorem. CAP stands for &lt;strong&gt;Consistency&lt;/strong&gt;, &lt;strong&gt;Availability&lt;/strong&gt;, and &lt;strong&gt;Partition tolerance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency&lt;/strong&gt; means that any read request will return the most recent write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Availability&lt;/strong&gt; means all (non-failing) nodes are available for queries &amp;amp; must respond in a reasonable amount of time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partition Tolerance&lt;/strong&gt; means that the system will continue to work despite node failures.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of Data
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 (&lt;code&gt;Students&lt;/code&gt; and &lt;code&gt;Courses&lt;/code&gt;) where the value in the &lt;code&gt;Student ID&lt;/code&gt; column inside the &lt;code&gt;Courses&lt;/code&gt; table points to rows in the &lt;code&gt;Students&lt;/code&gt; table by the value of their &lt;code&gt;ID&lt;/code&gt; column.&lt;/p&gt;

&lt;p&gt;Apart from this if you want your DB to be &lt;a href="https://en.wikipedia.org/wiki/ACID" rel="noopener noreferrer"&gt;ACID&lt;/a&gt; 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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 the face of errors, technology failures, disastrous events, and more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the other hand, if your data requirements aren’t clear or if your data is unstructured, NoSQL may be your best choice.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Availability
&lt;/h4&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Soft state
&lt;/h4&gt;

&lt;p&gt;The state of the database can be changing over time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Eventual consistency
&lt;/h4&gt;

&lt;p&gt;The database will eventually become consistent, and data will propagate everywhere at some point in the future.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Patterns
&lt;/h2&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;Do you need retrieval by a single key, or by various other parameters? Do you also need a fuzzy search on the data?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;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).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;But in case your data is nicely structured and organized, it is very efficient to query your data with a SQL database.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;p&gt;Is strong consistency required (read after write) or eventual consistency is OK?&lt;/p&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance &amp;amp; Scaling
&lt;/h2&gt;

&lt;p&gt;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 comes into the picture.&lt;/p&gt;

&lt;p&gt;Performance depends on various factors but the overall performance depends to a very large degree on choosing the right implementation for your use case.&lt;/p&gt;

&lt;p&gt;SQL and NoSQL databases scale differently, so you’ll have to think about how your data set will grow in the future.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This uncomplicated horizontal scaling nature of non-relational databases makes them superior to relational databases as far as availability is concerned.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Here's a small summary of what all we have discussed above:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasons to use an SQL database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;When you need ACID support&lt;/li&gt;
&lt;li&gt;Your application requires high transactions&lt;/li&gt;
&lt;li&gt;Data integrity is essential&lt;/li&gt;
&lt;li&gt;You don’t anticipate a lot of changes in the schema&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reasons to use a NoSQL database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want to store large amounts of data with no structure&lt;/li&gt;
&lt;li&gt;You keep getting Unrelated, indeterminate, or evolving data requirements&lt;/li&gt;
&lt;li&gt;Speed and scalability are critical&lt;/li&gt;
&lt;li&gt;When data integrity is not your top goal and you are concerned about the availability (&amp;amp; eventual consistency will be good enough for your use case)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;h3&gt;
  
  
  Starting out in web development?? 💻
&lt;/h3&gt;

&lt;p&gt;Checkout ▶ &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;HTML To React: The Ultimate Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ebook is a comprehensive guide that teaches you &lt;strong&gt;everything you need to know to be a web developer through a ton of easy-to-understand examples and proven roadmaps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It contains 👇&lt;/p&gt;

&lt;p&gt;✅  Straight to the point explanations&lt;/p&gt;

&lt;p&gt;✅  Simple code examples&lt;/p&gt;

&lt;p&gt;✅  50+ Interesting project ideas&lt;/p&gt;

&lt;p&gt;✅  3 Checklists of secret resources&lt;/p&gt;

&lt;p&gt;✅  A Bonus Interview prep&lt;/p&gt;

&lt;p&gt;You can even check out &lt;a href="https://drive.google.com/drive/u/0/folders/1GJECqmBUbOwgg5eQvGlMwHcDShqxKISJ" rel="noopener noreferrer"&gt;a free sample from this book&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and here's the &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;link&lt;/a&gt; with 60% off on the original price on the complete book set ⬇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlnnvqurw71bl4i2w0ak.png" alt="eBook.png" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>computerscience</category>
      <category>architecture</category>
      <category>beginners</category>
    </item>
    <item>
      <title>SOLID Principles in Java</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Wed, 26 Jan 2022 06:14:11 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/solid-principles-in-java-18ag</link>
      <guid>https://forem.com/apoorvtyagi/solid-principles-in-java-18ag</guid>
      <description>&lt;p&gt;In software engineering, &lt;strong&gt;SOLID&lt;/strong&gt; is an acronym for 5 &lt;a href="https://principles.design/" rel="noopener noreferrer"&gt;design principles&lt;/a&gt; intended to make software designs more understandable, flexible, robust, and maintainable. Adopting these practices can contribute to avoiding code smells too.&lt;/p&gt;

&lt;p&gt;The 5 SOLID principles are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;S&lt;/strong&gt; - The single-responsibility principle&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;O&lt;/strong&gt; - The open-closed principle&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;L&lt;/strong&gt; - The Liskov substitution principle&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;I&lt;/strong&gt; - The interface segregation principle&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;D&lt;/strong&gt; - The dependency inversion principle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Responsibility Principle
&lt;/h2&gt;

&lt;p&gt;This principle states that “&lt;strong&gt;a class should have only one reason to change&lt;/strong&gt;” which means every class should have a single responsibility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;details&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addNewVehicle&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the class has multiple reasons to change because the &lt;code&gt;Vehicle&lt;/code&gt; class has three separate responsibilities: printing details, printing price, and adding a new vehicle to Database.&lt;/p&gt;

&lt;p&gt;To achieve the goal of the single responsibility principle, we should implement a separate class that performs a single functionality only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VehicleDetails&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;details&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculateVehiclePrice&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddVehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addNewVehicle&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Open-Closed Principle
&lt;/h2&gt;

&lt;p&gt;This principle states that “&lt;strong&gt;software entities (classes etc.) should be open for extension, but closed for modification&lt;/strong&gt;”. This means without modifying anything in a class, it should be extendable.&lt;/p&gt;

&lt;p&gt;Let's understand this principle with an example of a notification service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;You can create a new interface like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Email Notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailNotification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// write Logic using for sending email&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mobile Notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MobileNotification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// write Logic using for sending notification via mobile&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Liskov Substitution Principle
&lt;/h2&gt;

&lt;p&gt;This principle states that “&lt;strong&gt;derived classes must be able to substitute for their base classes&lt;/strong&gt;”. 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.&lt;/p&gt;

&lt;p&gt;Consider an example of a square class derived from Rectangle base class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setWidht&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setWidth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setWidth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setWidth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Rectangle&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface Segregation Principle
&lt;/h2&gt;

&lt;p&gt;This principle applies to Interfaces and it is similar to the single responsibility principle. It states that “** 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.**“.&lt;/p&gt;

&lt;p&gt;Let's understand this by the example of a vehicle interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refuel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openDoors&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's say we now create a &lt;code&gt;Bike&lt;/code&gt; class using this Vehicle interface&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bike&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refuel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;// Can not be implemented&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openDoors&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Bike doesn't have doors we can't implement the last function.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refuel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Doors&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openDoors&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating two classes - &lt;code&gt;Car&lt;/code&gt; and &lt;code&gt;Bike&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bike&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refuel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Door&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refuel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;openDoors&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dependency Inversion Principle
&lt;/h2&gt;

&lt;p&gt;The Dependency Inversion Principle (DIP) states that "&lt;strong&gt;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&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;Suppose there is a  book store that enables customers to put their favorite books on a particular shelf.&lt;/p&gt;

&lt;p&gt;In order to implement this functionality, we create a &lt;code&gt;Book&lt;/code&gt; class and a &lt;code&gt;Shelf&lt;/code&gt; 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,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;seeReviews&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shelf&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
     &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything looks fine, but as the high-level &lt;code&gt;Shelf&lt;/code&gt; class depends on the low-level &lt;code&gt;Book&lt;/code&gt;, 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 &lt;code&gt;UserReview&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserReview&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;seeReviews&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;seeReviews&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;seeReviews&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserReview&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;seeReviews&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shelf&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;customizeShelf&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Happy coding! 💻&lt;/p&gt;

&lt;p&gt;(If you find any doubts, updates, or corrections to improve this article, Feel free to share them in the comments) 😊&lt;/p&gt;




&lt;h3&gt;
  
  
  Starting out in web development?? 💻
&lt;/h3&gt;

&lt;p&gt;Checkout ▶ &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;HTML To React: The Ultimate Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ebook is a comprehensive guide that teaches you &lt;strong&gt;everything you need to know to be a web developer through a ton of easy-to-understand examples and proven roadmaps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It contains 👇&lt;/p&gt;

&lt;p&gt;✅  Straight to the point explanations&lt;/p&gt;

&lt;p&gt;✅  Simple code examples&lt;/p&gt;

&lt;p&gt;✅  50+ Interesting project ideas&lt;/p&gt;

&lt;p&gt;✅  3 Checklists of secret resources&lt;/p&gt;

&lt;p&gt;✅  A Bonus Interview prep&lt;/p&gt;

&lt;p&gt;You can even check out &lt;a href="https://drive.google.com/drive/u/0/folders/1GJECqmBUbOwgg5eQvGlMwHcDShqxKISJ" rel="noopener noreferrer"&gt;a free sample from this book&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and here's the &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;link&lt;/a&gt; with 60% off on the original price on the complete book set ⬇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlnnvqurw71bl4i2w0ak.png" alt="eBook.png" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>computerscience</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Introduction to Asynchronous Processing and Message Queues</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Fri, 31 Dec 2021 06:08:46 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/introduction-to-asynchronous-processing-and-message-queues-27od</link>
      <guid>https://forem.com/apoorvtyagi/introduction-to-asynchronous-processing-and-message-queues-27od</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a client-server architecture, the client can request a job to be done from the server by sending messages between each other.&lt;/p&gt;

&lt;p&gt;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 which the client demands.&lt;/p&gt;

&lt;p&gt;In this blog, we'll see one way to handle this intricacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Synchronous Processing?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This process is often referred to as a &lt;em&gt;blocking&lt;/em&gt; request as the client gets blocked from doing any other work until a response is received.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What is Asynchronous Processing?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This process is referred to as a &lt;em&gt;non-blocking&lt;/em&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous vs Asynchronous Processing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since we do not know much time the request will take, it is difficult to build responsive applications with synchronous processing. The more blocking operations, the slower system becomes. With asynchronous processing, response time is quick as the client does not have to wait on the request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  What are Message Queues?
&lt;/h2&gt;

&lt;p&gt;A message queue is a component that buffers requests from one service and broadcasts asynchronously to another service.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The two most common messaging queues are — &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt; and &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Kafka&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of Message Queues
&lt;/h2&gt;

&lt;p&gt;A message queue is primarily a broker of messages between message producers and message consumers.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The only contract between all entities is the messages for which the message queue facilitates the movement from producers to consumers.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Producers
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Producers communicate with message queues using the Advanced Message Queuing Protocol (AMQP).&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Brokers
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Message brokers are the actual decoupling elements in the setup, sitting between and managing the process of communication between producers and consumers.&lt;/p&gt;

&lt;p&gt;Because of their simplicity, brokers are optimized for high concurrency and throughput.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Consumers
&lt;/h3&gt;

&lt;p&gt;The main responsibility of consumers is to receive and process messages from the queue.&lt;/p&gt;

&lt;p&gt;Most consumers are API services that perform that actual asynchronous processing.&lt;/p&gt;

&lt;p&gt;Consumers can be implemented in different application languages or technologies and maintained independently from other components.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consumer Communication Strategies
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pull Model&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Push Model&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Subscription Model&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing Different Message Brokers
&lt;/h2&gt;

&lt;p&gt;As we have seen above, for asynchronous communication we usually need a message broker.&lt;/p&gt;

&lt;p&gt;Below are the few considerations you have to look at when choosing a broker for managing your asynchronous operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Scale&lt;/strong&gt;: The number of messages sent per second in the system&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Data Persistency&lt;/strong&gt;: The capability to recover messages&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Consumer Capability&lt;/strong&gt;:  The capability to manage one-to-one / one-to-many consumers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  RabbitMQ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Scale: Based on configuration and resources.&lt;/li&gt;
&lt;li&gt;  Persistency: Both persistent and transient messages are supported.&lt;/li&gt;
&lt;li&gt;  One-to-one vs One-to-many consumers: Both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RabbitMQ supports all major languages, including Python, Java, .NET, PHP, Ruby, JavaScript, Go, Swift, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kafka
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Scale: Can send up to a million messages per second.&lt;/li&gt;
&lt;li&gt;  Persistency: Yes.&lt;/li&gt;
&lt;li&gt;  One-to-one vs One-to-many consumers: Only one-to-many&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Scale: Can send up to a million messages per second.&lt;/li&gt;
&lt;li&gt;  Persistency: Not supported (it’s an in-memory database).&lt;/li&gt;
&lt;li&gt;  One-to-one vs One-to-many consumers: Both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;We also covered some basic characteristics of the most commonly used message brokers: Redis, Kafka, and RabbitMQ.&lt;/p&gt;

&lt;p&gt;Here's a bit more detailed instruction for selecting the right message broker to use according to different use cases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short-lived Messages: Redis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redis is good for short-lived messages where persistence isn’t required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Large Amounts of Data: Kafka&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  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.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Complex Routing: RabbitMQ&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  RabbitMQ is good for complex routing communication.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Happy coding! 💻&lt;/p&gt;

&lt;p&gt;(If you find any doubts, updates, or corrections to improve this article, Feel free to share them in the comments) 😊&lt;/p&gt;




&lt;h3&gt;
  
  
  Starting out in web development?? 💻
&lt;/h3&gt;

&lt;p&gt;Checkout ▶ &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;HTML To React: The Ultimate Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ebook is a comprehensive guide that teaches you &lt;strong&gt;everything you need to know to be a web developer through a ton of easy-to-understand examples and proven roadmaps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It contains 👇&lt;/p&gt;

&lt;p&gt;✅  Straight to the point explanations&lt;/p&gt;

&lt;p&gt;✅  Simple code examples&lt;/p&gt;

&lt;p&gt;✅  50+ Interesting project ideas&lt;/p&gt;

&lt;p&gt;✅  3 Checklists of secret resources&lt;/p&gt;

&lt;p&gt;✅  A Bonus Interview prep&lt;/p&gt;

&lt;p&gt;You can even check out &lt;a href="https://drive.google.com/drive/u/0/folders/1GJECqmBUbOwgg5eQvGlMwHcDShqxKISJ" rel="noopener noreferrer"&gt;a free sample from this book&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and here's the &lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;link&lt;/a&gt; with 60% off on the original price on the complete book set ⬇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gumroad.com/a/316675187" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlnnvqurw71bl4i2w0ak.png" alt="eBook.png" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>architecture</category>
      <category>codenewbie</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building Your Online Presence</title>
      <dc:creator>Apoorv Tyagi</dc:creator>
      <pubDate>Sun, 10 Oct 2021 15:23:36 +0000</pubDate>
      <link>https://forem.com/apoorvtyagi/building-your-online-presence-1fjf</link>
      <guid>https://forem.com/apoorvtyagi/building-your-online-presence-1fjf</guid>
      <description>&lt;p&gt;Back in October 2020 I realized the importance of having an online presence when I saw this tweet on Twitter:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1317296660700016640-379" src="https://platform.twitter.com/embed/Tweet.html?id=1317296660700016640"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1317296660700016640-379');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1317296660700016640&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;It was really astounding to me when I learned that Daniel Vassallo has made over $250,000 just by selling couple of his courses on Gumroad and more importantly by leveraging social media. &lt;/p&gt;

&lt;p&gt;It turns out that you can in fact replace your 9-5 job salary if you effectively use Twitter or any social media application for that matter as a marketing channel for your products.&lt;/p&gt;

&lt;p&gt;As a software developer, we spend so much of our time writing tech blogs, created websites and apps, building SAAS products, making YouTube videos, so why don't we monetize our side hustle?&lt;/p&gt;

&lt;p&gt;Having an online presence can definitely help us with that, it can provide you numerous of opportunities. It can give you the freedom to control your time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Controlling your time is the highest dividend money pays&lt;/strong&gt; - "The Psychology of Money"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article I'll share some of the points that I have learned in last one year that you need to focus on to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can't you succeed without having online presence?
&lt;/h2&gt;

&lt;p&gt;You definitely can. I wanted to make this thing clear before moving on. There are various ways of making money on the internet these days.&lt;/p&gt;

&lt;p&gt;But the problem is just having a profile, blog, product or YouTube channel might not be enough for you. Sure you can have great content and people might discover it on their own and it becomes a hit, but the probability of this happening is less when everyone is surrounded with what I call the "Internet noise". Your have to stand apart &amp;amp; to achieve it, one of the good ways is to build your credibility on the internet.&lt;/p&gt;

&lt;p&gt;You need to have a group of people who consume the content you're producing. You need subscribers to watch the videos you're creating, you need audience to read the articles you're writing. You need clients to get freelancing gigs.&lt;/p&gt;

&lt;p&gt;A strong online presence allows you to build your brand and credibility that you need to attract more consumers for your work. It provides a way for people to find your work easily. You don't want to have a killer product that provides so much value but you struggle to sell it.&lt;/p&gt;

&lt;p&gt;I started being active on twitter since July last year and I was tweeting about various topics related to software engineering. Seeing my work, many people have started to DM me on twitter offering freelance jobs just because I was providing value and they liked what I was posting. &lt;/p&gt;

&lt;p&gt;Even though I was not selling anything(except tweeting about my blogs) or trying to find a job, opportunities started coming my way. This is the power of building your credibility.&lt;/p&gt;

&lt;p&gt;To sell your content you should have true fans. A true fan is someone who is always ready to buy anything you create just because you've given them so much value from your work for free in the past.&lt;/p&gt;

&lt;p&gt;Think of this as an example, Imagine you have 100 true fans. If you create a product which provides 500$ - 1000$ worth of value per year, you can make 50k $ - 100k $ per year by selling it to your true fans. True fans also spread the word about your products voluntarily and there is no bigger marketing than word of mouth from your existing customers itself.&lt;/p&gt;

&lt;p&gt;In the beginning, do not worry about true fans in the beginning. Just focus on providing value to your audience. You'll eventually see them coming your way!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips to Build An Online Presence
&lt;/h2&gt;

&lt;p&gt;Honestly, building an online presence is very time consuming process and takes lot of effort, hard work and consistency.&lt;/p&gt;

&lt;p&gt;You need to build credibility by providing value through your content. You'll have to consistently post quality content and interact with others' content as well.&lt;/p&gt;

&lt;p&gt;Here are few tips that will help you get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pick a social media channel depending on the type of content you want to create. YouTube, Twitter, LinkedIn, Instagram etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick your niche. Topics which your love talking about, topics which you're currently exploring a lot or you're an expert at. For instance, I'm a software developer so I generally tweet about programming, algorithms etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Post quality content everyday. Interact with other players of your niche. Eventually big accounts will notice you and they will start interacting with your content. And that's how you start growing big. Remember, &lt;strong&gt;consistency is the key.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improve your BIO. When people hoover over your name in their timeline the first thing they see is your face &amp;amp; bio. YOUR bio is about what you bring THEM! Write about how you're helping your followers. What will they get if they decide to follow you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow big players in your niche Before you can talk you first have to listen. Follow the players who have 10x the number of followers you have. For example, if you have 100 followers follow someone who has 1k-10k followers in your niches and see what they&lt;br&gt;
talk about. Follow people with high engagement. Accounts that consistently get 10+ retweets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Comment on big players' timelines. The guys you followed in the previous step, use their base to grow yours. Whenever you follow&lt;br&gt;
someone you can turn on notifications. When they tweet you get a notification. Add value to their timeline as quickly as you&lt;br&gt;
can. Do this once a day per account max. This is going to be your best friend until you hit 5k followers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do this for several months consistently and see the response you get. Keep doing experiments along the way with respect to what kind of posts your audience likes or dislikes. Double down on the ones that you will your audience is enjoying a lot.&lt;/p&gt;

&lt;p&gt;But there's one caveat to this experiment. Sometimes people interact with something which is very controversial but do not provide any value at all. Make sure you do not double down on such things because it can harm your reputation in long run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The important thing is to provide value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This topic is so big that an investment in a detailed course can help you a lot in getting started better. &lt;em&gt;I have mentioned one of the good eBook that I bought and loved and can totally recommend who wants to start out&lt;/em&gt; (Link at the end of the article).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Not to Do While Building Online Presence?
&lt;/h2&gt;

&lt;p&gt;Initially it might get a little frustrating to keep posting content but not having anyone to see and engage with it. The truth is everyone goes through that. But believe me, if you're creating quality content, people will eventually start noticing you.&lt;/p&gt;

&lt;p&gt;In running this long term race, many people tend to make mistakes in order to gain some traction early, some of which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Copying other's content and posting it as your own without giving credit to the original author.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Asking follow for follow, likes, retweets etc. Yes people do such things just to increase those follower numbers. You will get the numbers but not the true fans.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not being consistent with posting their content. You have to grind every single day of the week&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Posting lot of content without any quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start selling your products, sharing links to your blogs/videos from day one. Remember that you have to give a lot first before asking for anything. These tweets might even result in loosing followers if you overdo it. Your audience decided to follow you for your valuable content, not for your advertising.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid making these mistakes and be authentic with your content. &lt;strong&gt;The &lt;a href="https://gumroad.com/a/752219251/XFFpt" rel="noopener noreferrer"&gt;eBook&lt;/a&gt; I mentioned below talk about these things in detail so if you're very serious around building your own brand, you should definitely consider buying it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and all the best for your journey :)&lt;/p&gt;




&lt;p&gt;If you're interested to learn more about building an online presence in detail, here's &lt;a href="https://gumroad.com/a/752219251/XFFpt" rel="noopener noreferrer"&gt;one eBook&lt;/a&gt; that I found extremely useful&lt;br&gt;
(It has a good rating as well):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gumroad.com/a/752219251/XFFpt" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75ju5gfcjva1hh1bl7yc.png" alt="Twitter Guide" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>twitter</category>
      <category>motivation</category>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
