<?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>DEV Community: Samarth Gambhir</title>
    <description>The latest articles on DEV Community by Samarth Gambhir (@gambhirsamarth).</description>
    <link>https://dev.to/gambhirsamarth</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%2F955235%2F94de2174-4438-4a44-9886-bbd07066d229.png</url>
      <title>DEV Community: Samarth Gambhir</title>
      <link>https://dev.to/gambhirsamarth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gambhirsamarth"/>
    <language>en</language>
    <item>
      <title>Kubernetes Journey Part 1: Why Docker?</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Mon, 22 Dec 2025 12:57:15 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/kubernetes-journey-part-1-why-docker-419i</link>
      <guid>https://dev.to/gambhirsamarth/kubernetes-journey-part-1-why-docker-419i</guid>
      <description>&lt;p&gt;Welcome to the first post on learning Kubernetes! Before we dive into the complexities, we have to talk about the building block that made it all possible: Docker.&lt;/p&gt;

&lt;p&gt;If you’ve ever worked in software development, you’ve likely encountered the phrase: "But it works on my machine!"&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Docker?
&lt;/h2&gt;

&lt;p&gt;Imagine you’ve just finished a new feature and your code is merged into the Version Control System (VCS), and the build pipeline created an artifact which is deployed to the server.&lt;/p&gt;

&lt;p&gt;Dev Server: It works perfectly. ✅&lt;/p&gt;

&lt;p&gt;Test Server: Working as expected. ✅&lt;/p&gt;

&lt;p&gt;Production: You deploy, and the build fails. ❌&lt;/p&gt;

&lt;h3&gt;
  
  
  What happened?
&lt;/h3&gt;

&lt;p&gt;There could be multiple reasons for this, but most frequent reason is "Environment Misconfiguration" or due to missing dependencies which were there in dev and test environment but missing from production.&lt;/p&gt;

&lt;p&gt;Traditionally, you cannot ship the entire environment and dependencies with your code. You shipped the "artifact" to the servers. That's when containers come into picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Docker Solved this?
&lt;/h2&gt;

&lt;p&gt;With Docker, instead of shipping just your code, you package everything the code needs to run (libraries, dependencies, configurations, and even the base OS binaries) into one single unit. This makes chances of misconfigurations negligible.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Container?
&lt;/h3&gt;

&lt;p&gt;Container is an &lt;strong&gt;isolated lightweight sandbox environment&lt;/strong&gt; with all the application code, libraries and runtime dependencies. Everything required to run the application irrespective of host operating system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Key Distinction: Unlike a Virtual Machine (VM), a container does not package a full Operating System. It has bare minimum binaries and uses the host's OS kernel. This makes containers incredibly lightweight, fast and portable across any machine that has Docker installed.&lt;/p&gt;

&lt;p&gt;Definition: Docker is the platform that allows you to build, ship, and run these containers anywhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How It Works: Dockerfile to Runtime
&lt;/h2&gt;

&lt;p&gt;To containerize an application, we follow a specific workflow involving three main components: Dockerfiles, Images, and Containers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Dockerfile&lt;br&gt;
A Dockerfile is a simple text document containing a list of instructions. When you run &lt;code&gt;docker build&lt;/code&gt;, Docker reads these instructions to create an Image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Image&lt;br&gt;
A Docker image is a snapshot of your application. It contains everything your app needs to run. However, we cannot ship images to servers. So we need docker image to be stored in some registry same as a VCS. All environments pull the image from the same registry using the &lt;code&gt;docker pull&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Container&lt;br&gt;
When you want to run your app, you use the &lt;code&gt;docker run&lt;/code&gt; command which takes the image and turns it into a running instance. This instance is the container.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Docker Architecture
&lt;/h2&gt;

&lt;p&gt;Docker has majorly 3 components in its architecture: &lt;/p&gt;

&lt;p&gt;The Client: This is where you code (like your laptop).&lt;/p&gt;

&lt;p&gt;The Docker Daemon (dockerd): The "brain" of Docker that sits on the host machine. It listens for API requests from the client and manages images and containers.&lt;/p&gt;

&lt;p&gt;The Registry: The remote storage where images are hosted.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Lifecycle of a Docker Command:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;docker build&lt;/code&gt;: The Client tells the Daemon to create an image based on a Dockerfile which is stored locally.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push&lt;/code&gt;: The Daemon pushes your local image to a remote Registry so it can be used on the server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker pull&lt;/code&gt;: command is used on the environment to deploy. It asks the Daemon to download a specific image from the Registry.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run&lt;/code&gt;: The Daemon instructs the Container Runtime to spin up a container using that pulled image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By using Docker, we ensure that the environment in Dev is identical to the environment in Prod. If it works on your machine, it will work on the server, because you are shipping "your machine" (the container) along with the code.&lt;/p&gt;

&lt;p&gt;Now that we understand why we need containers, the next step in our series is learning how to manage multiple containers at once. That is where Kubernetes enters the story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for Part 2!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>architecture</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>CAP Theorem in Distributed Systems : Beyond the ‘Pick Two’ Myth</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Tue, 09 Sep 2025 11:29:57 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/cap-theorem-in-distributed-systems-beyond-the-pick-two-myth-38a</link>
      <guid>https://dev.to/gambhirsamarth/cap-theorem-in-distributed-systems-beyond-the-pick-two-myth-38a</guid>
      <description>&lt;p&gt;When most of us first encounter the CAP theorem, it’s introduced with a catchy phrase: &lt;em&gt;“Consistency, Availability, Partition Tolerance - pick two.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s a neat way to remember it, but like most neat sayings, it oversimplifies the reality. In truth, CAP is about understanding trade offs in distributed systems, and appreciating its nuances makes you a better engineer.&lt;br&gt;
In this post, we’ll go beyond the surface level explanation and see how it applies to the systems we work with, using a relatable example: &lt;strong&gt;Bank ATMs&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The ATM Analogy
&lt;/h2&gt;

&lt;p&gt;An ATM network is a real world example of a distributed system. Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The bank’s central server acts as the source of truth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each ATM machine is a node in the system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they form a distributed system where your account balance should remain consistent across all ATMs. Now, imagine you walk up to an ATM to deposit or withdraw cash. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the ideal case, the ATM successfully communicates with the bank’s server.&lt;/li&gt;
&lt;li&gt;Your transaction goes through, and the update is reflected across all ATMs in the network.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a scenario with no partition — the nodes (ATMs) are fully connected to the server, and both consistency and availability is naturally maintained.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CAP Theorem?
&lt;/h2&gt;

&lt;p&gt;The CAP theorem is a fundamental principle in distributed systems that tells us about the trade offs we must make when our system is &lt;code&gt;partitioned&lt;/code&gt;. To understand it properly, we need to start with the most important piece:&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Partition?
&lt;/h3&gt;

&lt;p&gt;Imagine you have multiple servers that should stay in sync. If a network failure prevents one server from talking to another, the system is said to be &lt;strong&gt;"partitioned"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is not a rare edge case because in large scale distributed systems, partitions are inevitable due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network failures&lt;/li&gt;
&lt;li&gt;Geographic distance&lt;/li&gt;
&lt;li&gt;Latency spike&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What it means in ATM terms?
&lt;/h4&gt;

&lt;p&gt;A partition happens when an ATM loses connection to the bank’s central server. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The ATM can no longer verify your latest account balance in real time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any deposits or withdrawals made at this ATM won’t immediately sync with the rest of the system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Effectively, this ATM is &lt;em&gt;"cut off"&lt;/em&gt; from the rest of the distributed network.&lt;/p&gt;

&lt;p&gt;Since partitions are unavoidable, we need our system to have &lt;strong&gt;"Partition Tolerance"&lt;/strong&gt;. So, the real world trade off is always between Consistency (C) and Availability (A).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Partition Tolerance means the system continues to operate despite partitioning due to network failures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  CP - Consistency &amp;amp; Partition Tolerance
&lt;/h3&gt;

&lt;p&gt;In a CP system, the design choice is to guarantee Consistency and Partition Tolerance even if it means sacrificing Availability during a partition.&lt;/p&gt;

&lt;h4&gt;
  
  
  ATM Analogy for CP
&lt;/h4&gt;

&lt;p&gt;Imagine you walk up to an ATM during a partition:&lt;/p&gt;

&lt;p&gt;The ATM tries to connect to the central bank server, but connection fails (partition), the ATM will refuse your transaction. Here, the ATM deliberately compromises &lt;em&gt;"Availability"&lt;/em&gt; for &lt;em&gt;"Consistency."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why? Because letting you withdraw without verifying your account risks double withdrawals or invalid balances.&lt;/p&gt;

&lt;h3&gt;
  
  
  AP - Availability &amp;amp; Partition Tolerance
&lt;/h3&gt;

&lt;p&gt;In an AP system, the design guarantees Availability and Partition Tolerance even if that means sacrificing Consistency during a partition.&lt;/p&gt;

&lt;h4&gt;
  
  
  ATM Analogy for AP
&lt;/h4&gt;

&lt;p&gt;Imagine you walk up to an ATM during a partition:&lt;/p&gt;

&lt;p&gt;The ATM tries to connect to the central bank server but the connection fails (partition). Instead of refusing your transaction, the ATM still lets you withdraw cash. Here, the ATM deliberately compromises &lt;em&gt;"Consistency"&lt;/em&gt; in order to preserve &lt;em&gt;"Availability".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why? Because the system chooses to stay operational, even if it means your withdrawal might not immediately reflect in your account balance risking temporary inconsistencies like negative balances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Simplistic “Pick Two” View
&lt;/h2&gt;

&lt;p&gt;The CAP theorem is often oversimplified to guarantee only two out of "Consistency, Availability, and Partition Tolerance".&lt;/p&gt;

&lt;p&gt;Real systems don’t just fall neatly into CP or AP categories. They often sit somewhere in between, offering &lt;em&gt;"partial consistency"&lt;/em&gt; or &lt;em&gt;"partial availability"&lt;/em&gt; depending on the situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Partial Consistency?
&lt;/h3&gt;

&lt;p&gt;Consistency doesn’t always mean perfectly up to date or completely wrong. Many systems aim for eventual consistency, where data may be temporarily stale but eventually converges across nodes when partition is resolved.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Partial Availability?
&lt;/h3&gt;

&lt;p&gt;Availability isn’t just about a system being fully online or completely offline. In many cases, systems aim for partial availability — they keep some features working while restricting others during a partition. This allows users to get at least something instead of facing a total outage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back to our ATM analogy:
&lt;/h3&gt;

&lt;p&gt;Even if the ATM is partitioned, it might still allow deposits. After a deposit, your balance may look incorrect for a short while, but it eventually gets updated once the connection is restored. In this case, the ATM is partially available because it continues to provide some functionality. At the same time, it is also partially consistent because it deliberately restricts withdrawals to avoid issues like negative balances.&lt;/p&gt;

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

&lt;p&gt;The CAP theorem isn’t about picking two properties and discarding the third. It’s about understanding how distributed systems behave under failure and making deliberate trade offs. In practice, systems rarely offer absolute consistency or availability. Instead, they operate in a combination of both — tolerating temporary inconsistency to preserve availability, while restricting risky operations during partitions to maintain safety.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>From Microservices to Fan-Out: Evolving Cross-Service Communication in Modern Systems</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Sun, 29 Jun 2025 16:45:21 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/from-microservices-to-fan-out-evolving-cross-service-communication-in-modern-systems-e9p</link>
      <guid>https://dev.to/gambhirsamarth/from-microservices-to-fan-out-evolving-cross-service-communication-in-modern-systems-e9p</guid>
      <description>&lt;p&gt;In modern backend development, microservices are everywhere, and for good reason.&lt;/p&gt;

&lt;p&gt;Instead of building a giant monolithic application, we break the system into smaller, focused services, each responsible for doing one thing well. This is the essence of microservice architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One service = One responsibility&lt;/li&gt;
&lt;li&gt;Each service = Independently deployable&lt;/li&gt;
&lt;li&gt;Services talk to each other = System communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in an e-commerce platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Service            | Responsibility                  |
| ------------------ | ------------------------------- |
| OrderService       | Accepts and creates new orders  |
| SMSService         | Sends SMS notifications         |
| EmailService       | Sends order confirmation emails |
| InventoryService   | Updates product stock           |

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

&lt;/div&gt;



&lt;p&gt;Each service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs independently&lt;/li&gt;
&lt;li&gt;Can be deployed separately&lt;/li&gt;
&lt;li&gt;Owns its own data (DB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But breaking a monolith into microservices is only the first step.&lt;/p&gt;

&lt;p&gt;What follows is much harder:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do these small, independent services talk to each other reliably, at scale, and without bringing the system down?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To understand this, let’s walk through a simple, relatable example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A user places an order in an e-commerce application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This one event will help us explore the evolution of communication patterns. When a user places an order, we want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send an order confirmation SMS&lt;/li&gt;
&lt;li&gt;Send an order confirmation Email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, how can we make this happen?&lt;/p&gt;

&lt;h2&gt;
  
  
  🛜 The Naive Approach - HTTP Call
&lt;/h2&gt;

&lt;p&gt;The first solution that comes to our mind is making a HTTP call from one service to another.&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%2F3vxff0mlz3zaopqy1tcr.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%2F3vxff0mlz3zaopqy1tcr.png" alt="HTTP Call" width="558" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  But what happens if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SMS or Email service is down?&lt;/li&gt;
&lt;li&gt;It’s slow to respond?&lt;/li&gt;
&lt;li&gt;The network drops?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a synchronous way as our Order service is blocked or fails too. That’s too fragile. We can use a simple Message Queue for handling this.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 What is a Message Queue?
&lt;/h2&gt;

&lt;p&gt;A message queue follows simple FIFO (First-In, First-Out) logic. It decouples events from consumers — meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The producer service doesn’t care when or how the message is processed.&lt;/li&gt;
&lt;li&gt;The consumer service pulls messages independently, processes them, and acknowledges success.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model allows both services to scale, fail, and recover independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ The Asynchronous Solution – Message Queue
&lt;/h2&gt;

&lt;p&gt;Message queues provide at-least-once delivery. That means a message might be processed more than once if retries happen. It’s the consumer's job to make message handling idempotent — i.e., safely repeatable. So, we introduce a Message Queue between our services:&lt;br&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%2Foah4bx2pz8rui9m8wl4x.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%2Foah4bx2pz8rui9m8wl4x.png" alt="Message Queues" width="645" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order service drops the message to queues and moves on.&lt;/li&gt;
&lt;li&gt;The queue stores it until their respective service processes it.&lt;/li&gt;
&lt;li&gt;If it fails, the message is pushed back to the queue for retry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚠️ Limitations
&lt;/h3&gt;

&lt;p&gt;If we continue using a message queue, only one service will receive the message. Others will miss it.&lt;/p&gt;

&lt;p&gt;We could try adding multiple separate queues, but that means the producer (OrderService) now needs to know all the consumers — tightly coupling everything again.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ The Solution - Pub/Sub Architecture
&lt;/h2&gt;

&lt;p&gt;In Pub/Sub systems like Kafka, you can group consumers by concern — and each consumer group gets its own copy of the message. But delivery guarantees depend heavily on the implementation. So, we switch to a Pub/Sub system:&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%2Ffufblh7oqv3v1ibxcdxy.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%2Ffufblh7oqv3v1ibxcdxy.png" alt="Pub/Sub Architecture" width="582" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OrderService just publishes an event.&lt;/li&gt;
&lt;li&gt;All interested services subscribe to it.&lt;/li&gt;
&lt;li&gt;Everyone receives the same message, independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚠️ Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Message loss possible if a service is offline during event publication.&lt;/li&gt;
&lt;li&gt;No per-service retries as the event can't be republished for retry.&lt;/li&gt;
&lt;li&gt;Consumers may race each other if not isolated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✅ Solution - Fan-Out Architecture
&lt;/h2&gt;

&lt;p&gt;Fan-Out is a hybrid of Pub/Sub + Queues.&lt;/p&gt;

&lt;p&gt;Instead of one message going to many services directly, we create a queue per subscriber, resulting in a fallback for retrying failed events.&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%2Fdmbnk97yqfwey1qlhnre.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%2Fdmbnk97yqfwey1qlhnre.png" alt="Fan Out Architecture" width="771" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, each service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gets its own durable message queue.&lt;/li&gt;
&lt;li&gt;Can retry failures independently.&lt;/li&gt;
&lt;li&gt;Is fully isolated from the others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧠 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Message Queues are great for decoupling a task from its processor, but not ideal where multiple services are involved.&lt;/li&gt;
&lt;li&gt;Pub/Sub lets you notify multiple systems from a single event, but do not provide a fallback.&lt;/li&gt;
&lt;li&gt;Fan-Out adds durability, reliability and a fallback point to the pub/sub pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single event — like an order being placed — may seem small. But behind the scenes, it may trigger multiple workflows, handled by independent services, and needing different levels of reliability. Understanding when to use which pattern can make or break the scalability and resilience of your system.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>learning</category>
      <category>design</category>
    </item>
    <item>
      <title>Docker or Virtual Machines: Your First Step Into Modern Software</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Thu, 12 Jun 2025 07:52:07 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/docker-or-virtual-machines-your-first-step-into-modern-software-4be</link>
      <guid>https://dev.to/gambhirsamarth/docker-or-virtual-machines-your-first-step-into-modern-software-4be</guid>
      <description>&lt;p&gt;Have you ever heard developers talking about "Docker" or "containers" and felt completely lost? Don't worry - you're not alone! This guide will explain everything from scratch, assuming you know nothing about Docker or Virtual Machines.&lt;br&gt;
By the end of this article, you'll understand what Docker is, why it's so popular, and how it compares to older technologies. Think of this as your starting point for learning Docker and modern software deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Problem Are We Trying to Solve?
&lt;/h2&gt;

&lt;p&gt;Before we dive into Docker and Virtual Machines, let's understand the problem they solve. Imagine you're a developer who just built a website. It works perfectly on your computer, but when you try to run it on your friend's computer or on a server, it breaks. Why? Because your computer has different software versions, settings, or missing pieces that your website needs.&lt;br&gt;
This is the classic "it works on my machine" problem that has frustrated developers for decades. Docker and Virtual Machines are two different solutions to this same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Machines: Creating Multiple Computers
&lt;/h2&gt;

&lt;p&gt;Virtual Machines solved this by creating fake computers inside your real computer. Think of it like having multiple laptops running inside one powerful desktop.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do VMs Work?
&lt;/h3&gt;

&lt;p&gt;A VM works like this: you have your physical server, then you install special software called a "hypervisor" (like VMware or VirtualBox). This hypervisor creates multiple virtual computers, each with its own operating system.&lt;br&gt;
So on one physical server, you might have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VM 1: Running Windows with your web application&lt;/li&gt;
&lt;li&gt;VM 2: Running Linux with your database&lt;/li&gt;
&lt;li&gt;VM 3: Running another Linux for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each VM thinks it's running on its own dedicated computer, but they're actually sharing the same physical hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  VM Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Complete separation between applications&lt;/li&gt;
&lt;li&gt;Can run different operating systems&lt;/li&gt;
&lt;li&gt;If one VM crashes, others keep running&lt;/li&gt;
&lt;li&gt;Easy to backup and move around&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  VM Problems
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each VM needs its own operating system, which uses lots of memory and storage&lt;/li&gt;
&lt;li&gt;Slow to start up (like booting a computer)&lt;/li&gt;
&lt;li&gt;Wastes resources because each OS takes up space even when doing nothing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docker: A Smarter Approach
&lt;/h2&gt;

&lt;p&gt;Docker took a different approach. Instead of creating fake computers, Docker creates isolated "containers" that share the same operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Docker Images?
&lt;/h3&gt;

&lt;p&gt;A Docker image is like a blueprint or recipe that contains everything needed to run your application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your application code&lt;/li&gt;
&lt;li&gt;The runtime environment (like Node.js or Python)&lt;/li&gt;
&lt;li&gt;System libraries and dependencies&lt;/li&gt;
&lt;li&gt;Configuration files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as a complete package that includes your app and everything it needs to run, but without a full operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Docker Containers?
&lt;/h3&gt;

&lt;p&gt;A container is what you get when you run an image. If an image is like a recipe, a container is the actual dish you cook from that recipe.&lt;br&gt;
Key points about containers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple containers can run from the same image&lt;/li&gt;
&lt;li&gt;Each container runs independently&lt;/li&gt;
&lt;li&gt;All containers share the host operating system's kernel (the core part of the OS)&lt;/li&gt;
&lt;li&gt;Containers have their own isolated space for processes and files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Big Comparison - Docker VS Virtual Machine
&lt;/h2&gt;

&lt;p&gt;Let's compare these technologies in simple terms:&lt;/p&gt;

&lt;h3&gt;
  
  
  Size and Speed
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Virtual Machines: Heavy and slow
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Takes 30+ seconds to start (full OS boot)&lt;/li&gt;
&lt;li&gt;More overhead due to hardware simulation&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Docker Containers: Light and Fast
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Starts in seconds (just launching the application)&lt;/li&gt;
&lt;li&gt;Near-native performance since no hardware simulation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Many Can You Run?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Virtual Machines: Fewer
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Maybe 10-20 VMs on one server&lt;/li&gt;
&lt;li&gt;Each VM needs its own operating system&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Docker Containers: Many more
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Hundreds of containers on the same server&lt;/li&gt;
&lt;li&gt;All containers share one operating system&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Virtual Machines: More Secure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Each VM has its own kernel and complete separation&lt;/li&gt;
&lt;li&gt;Like having separate locked rooms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Docker Containers: Less secure but still good
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Containers share the kernel but have separate processes&lt;/li&gt;
&lt;li&gt;Like having separate apartments in the same building&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When things go wrong
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Virtual Machines: problems stay contained
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;VM failures remain isolated since each runs its own independent kernel&lt;/li&gt;
&lt;li&gt;System crashes in one VM don't affect others running on the same host&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Docker Containers: Usually contained, but...
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Individual container failures typically don't impact other containers&lt;/li&gt;
&lt;li&gt;Host operating system issues can potentially affect all running containers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When Should You Use Each?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Use Virtual Machines When:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You need to run different operating systems (Windows and Linux together)&lt;/li&gt;
&lt;li&gt;Security is extremely important&lt;/li&gt;
&lt;li&gt;You're working with older applications that need specific setups&lt;/li&gt;
&lt;li&gt;You don't mind slower startup times&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use Docker when:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You want to deploy applications quickly&lt;/li&gt;
&lt;li&gt;You're building modern web applications&lt;/li&gt;
&lt;li&gt;You want to save money on server costs&lt;/li&gt;
&lt;li&gt;You need to scale up and down rapidly&lt;/li&gt;
&lt;li&gt;Your team needs consistent development environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;p&gt;Let's say you're running an online store:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With VMs&lt;/strong&gt;: You might have one VM for your website, another for your database, and another for handling payments. Each VM runs its own operating system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Docker&lt;/strong&gt;: You'd have containers for each service (website, database, payments) all sharing the same operating system but running independently.&lt;br&gt;
The Docker approach uses less resources and starts faster, while the VM approach provides stronger security boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Both technologies solve the same core problem - making software run consistently everywhere - but in different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machines&lt;/strong&gt; are like having multiple separate computers in one box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Containers&lt;/strong&gt; are like having multiple isolated applications sharing one computer&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>systemdesign</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Abstract Thinking: Java’s Structure vs Go’s Simplicity</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Wed, 21 May 2025 07:15:18 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/abstract-thinking-javas-structure-vs-gos-simplicity-kkd</link>
      <guid>https://dev.to/gambhirsamarth/abstract-thinking-javas-structure-vs-gos-simplicity-kkd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Interfaces are a core part of many programming languages, providing a way to define behavior without locking in the exact implementation. They promote flexibility, code reuse, and a cleaner design. However, the way interfaces work in Go and Java is quite different. In this blog, we’ll explore these differences and why they matter to developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interfaces in Java
&lt;/h2&gt;

&lt;p&gt;Java interfaces are a key part of its object-oriented design. They define a contract that a class must fulfill, ensuring that certain methods are present. Java interfaces are implemented explicitly using the &lt;code&gt;implements&lt;/code&gt; keyword, and the compiler checks that a class has provided all the required methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Printer {
    void printMessage(String message);
}

class ConsolePrinter implements Printer {
    @Override
    public void printMessage(String message) {
        System.out.println("Console: " + message);
    }
}

class FilePrinter implements Printer {
    @Override
    public void printMessage(String message) {
        System.out.println("File: " + message);
    }
}

public class Main {
    public static void main(String[] args) {
        Printer consolePrinter = new ConsolePrinter();
        consolePrinter.printMessage("Hello, World!");

        Printer filePrinter = new FilePrinter();
        filePrinter.printMessage("Hello, File!");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, both &lt;code&gt;ConsolePrinter&lt;/code&gt; and &lt;code&gt;FilePrinter&lt;/code&gt; explicitly declare that they implement the &lt;code&gt;Printer&lt;/code&gt; interface, ensuring they both have the &lt;code&gt;printMessage()&lt;/code&gt; method. This approach is typical in large, enterprise-grade systems where strict contracts are essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interfaces in Go
&lt;/h2&gt;

&lt;p&gt;Go takes a more relaxed approach to interfaces. It uses structural typing, which means a type satisfies an interface if it has the required methods, without any special keyword or declaration. This makes Go interfaces much simpler and more flexible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

type Printer interface {
    PrintMessage(message string)
}

type ConsolePrinter struct{}

type FilePrinter struct{}

func (cp ConsolePrinter) PrintMessage(message string) {
    fmt.Println("Console:", message)
}

func (fp FilePrinter) PrintMessage(message string) {
    fmt.Println("File:", message)
}

func main() {
    var printer Printer = ConsolePrinter{}
    printer.PrintMessage("Hello, World!")

    printer = FilePrinter{}
    printer.PrintMessage("Hello, File!")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, both &lt;code&gt;ConsolePrinter&lt;/code&gt; and &lt;code&gt;FilePrinter&lt;/code&gt; satisfy the &lt;code&gt;Printer&lt;/code&gt; interface just by having the right methods. No need for explicit declarations, which keeps the code cleaner and more flexible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Differences
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Explicit vs Implicit Implementation:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java: You must explicitly declare when a class implements an interface using the implements keyword. This creates a clear, enforced contract.&lt;/li&gt;
&lt;li&gt;Go: Interfaces are satisfied implicitly. If a type has all the required methods, it automatically satisfies the interface. This reduces boilerplate but can make code relationships less obvious.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Structural vs Nominal Typing:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java: Interfaces use nominal typing, meaning a class must explicitly declare which interfaces it implements. This adds clarity but requires more code.&lt;/li&gt;
&lt;li&gt;Go: Interfaces use structural typing, where the relationship is determined by the presence of methods, not explicit declarations. This allows for more flexible, reusable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Interface Satisfaction:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java: The compiler checks for exact matches at compile-time, ensuring that every implemented method is present and correctly typed.&lt;/li&gt;
&lt;li&gt;Go: Satisfaction is automatic based on method names and signatures. If a type has the methods the interface expects, it satisfies the interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multiple Inheritance and Composition:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java: Uses interfaces to simulate multiple inheritance, allowing a class to implement multiple interfaces.&lt;/li&gt;
&lt;li&gt;Go: Prefers composition, encouraging developers to build small, focused interfaces and combine them as needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Choose Which Approach
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choose Java Interfaces When:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need clear, strict contracts with enforced method signatures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are building large, enterprise-grade systems where consistency and predictability are critical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want to use design patterns like Dependency Injection (DI) and Inversion of Control (IoC) that benefit from explicit interfaces.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose Go Interfaces When:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You want more flexibility and less boilerplate code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are building microservices, APIs, or simple, fast services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want to take advantage of Go’s simple concurrency model without the overhead of explicit type declarations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You prefer composition over inheritance for code reuse and design simplicity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Both Java and Go have powerful, but very different approaches to interfaces. Java’s explicit interfaces provide clarity and structure, making them ideal for large, complex projects. Go’s implicit approach keeps things simple and flexible, making it a great choice for rapid development and microservices. Understanding these differences can help you write better, more maintainable code, no matter which language you choose.&lt;/p&gt;

</description>
      <category>go</category>
      <category>java</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Inside Out, Outside In: Our Topsy-Turvy Tech World</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Mon, 03 Mar 2025 07:08:23 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/inside-out-outside-in-our-topsy-turvy-tech-world-3aj0</link>
      <guid>https://dev.to/gambhirsamarth/inside-out-outside-in-our-topsy-turvy-tech-world-3aj0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://future.forem.com/challenges/writing-2025-02-26" rel="noopener noreferrer"&gt;Future Writing Challenge&lt;/a&gt;: How Technology Is Changing Things.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Prize Categories: Explain Like I'm Five
&lt;/h3&gt;

&lt;p&gt;Dear friend,&lt;/p&gt;

&lt;p&gt;It's like our world got turned upside-down and inside-out at the same time! Remember we used to put our pocket money in piggy banks and wallets stuffed with paper money? Those physical dollars have jumped inside our computers and phones! They've become invisible digital coins that zoom through the air like magic butterflies. Our money has become like the money we used to use in our video games! - except now grown-ups use it for real!&lt;/p&gt;

&lt;p&gt;That's not it, while our money decided to stay behind the screens of our phones, the computer people were crawling OUT of our screens! The AI friends who used to live trapped behind glass are now having real bodies and walking around in our world! It's exactly like in my favorite movie when the cartoon characters step out of the TV and start dancing in the living room!&lt;/p&gt;

&lt;p&gt;Isn't that just the silliest, most wonderful mix-up ever? The things we could touch (like quarters and dollar bills) turned into things we can only see (digital coins). And the things we could only see (like computer helpers) turned into things we can touch (like real robots)!&lt;/p&gt;

&lt;p&gt;Love and gigantic rainbow robot hugs,&lt;br&gt;
Sam&lt;/p&gt;

</description>
      <category>futurechallenge</category>
      <category>explainlikeimfive</category>
      <category>techtalks</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Upload Files to AWS S3 Using Java: A Step-by-Step Guide</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Tue, 22 Oct 2024 11:57:10 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/how-to-upload-files-to-aws-s3-using-java-a-step-by-step-guide-2p18</link>
      <guid>https://dev.to/gambhirsamarth/how-to-upload-files-to-aws-s3-using-java-a-step-by-step-guide-2p18</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Amazon Simple Storage Service (S3) is a powerful and scalable object storage service providing a reliable and cost-effective solution to store and retrieve any amount of data from anywhere on the web. In this article, we will explore how to interact with AWS S3 to upload files using Java and Spring Boot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS Account: Sign up for an account on the &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS Website&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Java Development Environment: Ensure you have Java installed on your machine along with a build tool like Maven or Gradle for dependency management.&lt;/li&gt;
&lt;li&gt;Basic Knowledge of Java: Familiarity with Java syntax and programming concepts will be helpful.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up AWS SDK for Java
&lt;/h2&gt;

&lt;p&gt;To interact with AWS S3 using Java, you'll need the AWS SDK for Java. Here's how to add it to your project:&lt;/p&gt;

&lt;p&gt;For Maven: Add the following dependency to your pom.xml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.amazonaws&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;aws-java-sdk-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.x.x&amp;lt;/version&amp;gt; &amp;lt;!-- Replace with the latest version --&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Gradle: Add the following line to your build.gradle file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;implementation 'com.amazonaws:aws-java-sdk-s3:1.x.x' // Replace with the latest version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring AWS Credentials
&lt;/h2&gt;

&lt;p&gt;To securely interact with AWS S3, you'll need to store your AWS credentials. In this tutorial, we'll use the &lt;code&gt;application.properties&lt;/code&gt; file to manage credentials.&lt;/p&gt;

&lt;p&gt;First, add the following lines to your &lt;code&gt;application.properties&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws.accessKeyId=your-access-key-id
aws.secretKey=your-secret-access-key
aws.region=your-region
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your Java application, you can load these properties and use them to configure the AWS S3 client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.amazonaws.auth.AWSCredentials;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;

@Component
public class S3ClientConfig {

    @Value("${aws.accessKeyId}")
    private String accessKeyId;

    @Value("${aws.secretKey}")
    private String secretKey;

    @Value("${aws.region}")
    private String region;

    public AmazonS3 initializeS3() {
        AWSCredentials credentials = new BasicAWSCredentials(accessKeyId, secretKey);
        return AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion(region).build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Uploading Files to S3
&lt;/h2&gt;

&lt;p&gt;Here is a sample method that demonstrates how to upload a file to AWS S3 using the AmazonS3 client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;

@Service
public class S3Service {

    private final AmazonS3 s3Client;

    @Autowired
    public S3Service(S3ClientConfig s3ClientConfig) {
        this.s3Client = s3ClientConfig.initializeS3();
    }

    public void uploadFile(String bucketName, String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            s3Client.putObject(new PutObjectRequest(bucketName, file.getName(), file));
            System.out.println("File uploaded successfully.");
        } else {
            System.out.println("File not found: " + filePath);
        }
    }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  uploadFile() Method Breakdown:
&lt;/h2&gt;

&lt;p&gt;Parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bucketName:&lt;/code&gt; The name of the S3 bucket to upload the file to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filePath:&lt;/code&gt; The local path to the file being uploaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;File Creation &amp;amp; Existence Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A File object is created from the provided &lt;code&gt;filePath&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The method checks if the &lt;code&gt;file&lt;/code&gt; exists using &lt;code&gt;file.exists()&lt;/code&gt; If the file doesn't exist, it logs an error message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uploading the File:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the file exists, it's uploaded to the S3 bucket using the &lt;code&gt;putObject()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Logs a success message if the upload completes successfully.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this article, we covered the process of uploading files to AWS S3 using Java. We explored how to configure AWS credentials, set up the S3 client using Spring Boot, and wrote a simple method to upload files to your S3 bucket. With this foundation, you can now integrate S3 file uploads into your Java applications seamlessly.&lt;/p&gt;

</description>
      <category>java</category>
      <category>cloud</category>
      <category>backend</category>
      <category>aws</category>
    </item>
    <item>
      <title>Why Java Doesn’t Support Multiple Inheritance: A Simplified Explanation</title>
      <dc:creator>Samarth Gambhir</dc:creator>
      <pubDate>Fri, 27 Sep 2024 07:21:07 +0000</pubDate>
      <link>https://dev.to/gambhirsamarth/why-java-doesnt-support-multiple-inheritance-a-simplified-explanation-6hl</link>
      <guid>https://dev.to/gambhirsamarth/why-java-doesnt-support-multiple-inheritance-a-simplified-explanation-6hl</guid>
      <description>&lt;h2&gt;
  
  
  Understanding Multiple Inheritance and the Diamond Problem in Java
&lt;/h2&gt;

&lt;p&gt;Multiple inheritance is a feature in Object Oriented Programming where a class can inherit attributes and methods from more than one parent class. It does sound beneficial but it can lead to ambiguity, especially when a method with same name and same signature is present in both the parent classes. In such cases, resolving which method to call can lead to errors and unintended behavior in the program. This ambiguity is termed as &lt;strong&gt;"The Diamond Problem"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yo479kiftra1oeqqkir.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%2F5yo479kiftra1oeqqkir.png" alt="Diagram showing diamond problem" width="674" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this diagram, Class A is the common ancestor with a &lt;code&gt;speak()&lt;/code&gt; method. Class B and Class C both inherit from Class A and override the &lt;code&gt;speak()&lt;/code&gt; method. Class D inherits from both Class B and Class C, inheriting two conflicting versions of the &lt;code&gt;speak()&lt;/code&gt; method.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Java Avoids Multiple Inheritance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Java was designed with a focus on simplicity and ease of understanding. By eliminating multiple inheritance, the language avoids complexities that can confuse developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;without multiple inheritance, the class hierarchy is easier to follow and maintain.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interfaces: A Safer Alternative
&lt;/h2&gt;

&lt;p&gt;A class can implement multiple interfaces, allowing it to inherit method signatures from various sources. Since interfaces only contain method declarations, any class implementing an interface must provide its own logic for the functions declared in that interface. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface InterfaceA {
    void speak();
}

interface InterfaceB {
    void speak();
}

class MyClass implements InterfaceA, InterfaceB {

    // Single implementation for the speak method
    public void speak() {
        System.out.println("Hello World !");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, even if a class implements two interfaces that contain methods with the exact same name and signature, it only needs to define the method once, &lt;strong&gt;eliminating any ambiguity&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;In conclusion, by avoiding multiple inheritance, Java does limit the developers to some extent but improves simplicity and reduces ambiguity. By utilizing interfaces, Java enables method reuse without the complications of conflicting methods, promoting cleaner and more maintainable code.&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>learning</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
