<?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: Anuj Ashok Potdar</title>
    <description>The latest articles on Forem by Anuj Ashok Potdar (@anizmo).</description>
    <link>https://forem.com/anizmo</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%2F3085012%2F0959cc2b-9c36-4ddf-8f23-469fcaa9fed0.png</url>
      <title>Forem: Anuj Ashok Potdar</title>
      <link>https://forem.com/anizmo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/anizmo"/>
    <language>en</language>
    <item>
      <title>The "Hello World" Lie: Why Industry Java is a Different Beast</title>
      <dc:creator>Anuj Ashok Potdar</dc:creator>
      <pubDate>Sat, 18 Apr 2026 16:58:05 +0000</pubDate>
      <link>https://forem.com/anizmo/the-hello-world-lie-why-industry-java-is-a-different-beast-2p6f</link>
      <guid>https://forem.com/anizmo/the-hello-world-lie-why-industry-java-is-a-different-beast-2p6f</guid>
      <description>&lt;p&gt;We have all been there. You finished your CS degree, you know your way around &lt;code&gt;Collections.sort()&lt;/code&gt;, and you have mastered the art of the &lt;code&gt;HashMap&lt;/code&gt;. You walk into your first day at a tech firm thinking that it is just Java and you have been doing this for years. You wonder how different it could really be.&lt;/p&gt;

&lt;p&gt;Then you clone the repository.&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%2Fgh4z3z9cbczblddrkur9.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%2Fgh4z3z9cbczblddrkur9.png" alt="repository" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suddenly, your 500-line "Final Project" looks like a haiku compared to the 2-million-line epic poem you are now responsible for. You realize that while college taught you how to build a wooden stool, the industry expects you to maintain a skyscraper while it is being buffeted by a hurricane. &lt;/p&gt;

&lt;p&gt;If you are a student or a recent grad, here is a reality check on why professional Java feels like a completely different language.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Art of Reading (Not Writing)
&lt;/h2&gt;

&lt;p&gt;In college, 90% of your time is spent with a blinking cursor on a blank screen. You are the architect, the builder, and the sole occupant of your code. You know every variable because you named them all at 2 AM.&lt;/p&gt;

&lt;p&gt;In the industry, that ratio flips completely. You will spend nine hours reading code just to write ten lines. You are essentially a forensic investigator. You are not just looking at what the code does; you are trying to figure out why a developer named "Dave" wrote a specific &lt;code&gt;if&lt;/code&gt; statement in 2017 that seems to defy logic. &lt;/p&gt;

&lt;p&gt;You have to learn to navigate massive codebases using IDE shortcuts like a professional. If you are not using &lt;code&gt;Ctrl+Click&lt;/code&gt; to jump to definitions or "Find Usages" to see how a change might break a module three folders away, you are essentially wandering through a dark forest without a map. In industry, the "Search Everywhere" bar is your best friend.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The "Main" Method is a Myth
&lt;/h2&gt;

&lt;p&gt;In a classroom lab, every program has a clear beginning and end. You hit "Run," the &lt;code&gt;public static void main(String[] args)&lt;/code&gt; executes, your logic runs, and you are done. It is a linear path.&lt;/p&gt;

&lt;p&gt;In production, you might go months without ever seeing a &lt;code&gt;main&lt;/code&gt; method. Modern Java is an ecosystem of frameworks like Spring Boot or Micronaut. These frameworks are the drivers, and your code is just a passenger. You are not "running" a program; you are contributing a small gear to a massive, perpetually spinning machine. &lt;/p&gt;

&lt;p&gt;This introduces the concept of "Magic," specifically Dependency Injection. In school, you instantiate objects with &lt;code&gt;new MyService()&lt;/code&gt;. In industry, you see &lt;code&gt;@Autowired&lt;/code&gt; or &lt;code&gt;@Inject&lt;/code&gt; and you have to trust that the framework will magically provide the object at runtime. Debugging why a bean failed to initialize is a rite of passage that no textbook prepares you for. You spend more time looking at stack traces for bean creation errors than you do looking at actual logic errors.&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%2Fzo39dzt11119j8r1ijv6.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%2Fzo39dzt11119j8r1ijv6.png" alt="autowired" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Dependency Abyss
&lt;/h2&gt;

&lt;p&gt;University projects usually rely on the standard library. You use &lt;code&gt;java.util.*&lt;/code&gt; and &lt;code&gt;java.io.*&lt;/code&gt;. If you are feeling particularly adventurous, maybe you will import a JSON parser. &lt;/p&gt;

&lt;p&gt;In production, the code you actually wrote is usually less than 10% of the total binary. The rest is a precarious tower of external libraries managed by Maven or Gradle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Build Tool:&lt;/strong&gt; That &lt;code&gt;pom.xml&lt;/code&gt; file is not just a list of libraries; it is a delicate treaty. One wrong version of a logging library can trigger "Jar Hell," where two libraries want different versions of the same dependency and your app refuses to start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transitive Dependencies:&lt;/strong&gt; You imported Library A, which imported Library B, which has a security vulnerability in Library C. Suddenly, your manager is asking why your "simple" feature is flagged by a security scanner for a library you did not even know existed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Security Patch Cycle:&lt;/strong&gt; In school, you never update your libraries. In the industry, a major vulnerability means you might spend your entire week updating version numbers and testing for regressions across dozens of microservices.&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%2Fj4jqn6fpy57r5djww2a5.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%2Fj4jqn6fpy57r5djww2a5.png" alt="dependency" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Engineering for Failure
&lt;/h2&gt;

&lt;p&gt;College assignments assume a perfect world. The database is always up, the network never drops, and the disk is never full. You write code that works when everything goes right.&lt;/p&gt;

&lt;p&gt;Industry Java is the art of defensive pessimism. You learn very quickly that if something can fail, it will fail at 3 AM on a Sunday. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Circuit Breakers:&lt;/strong&gt; If the "Payments" service is slow, you do not want the "Checkout" service to hang and crash. You use patterns like Resilience4j to "trip the circuit" and return a friendly error message or a cached result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retries and Backoffs:&lt;/strong&gt; If a network call fails, you do not just give up. But you also do not hammer the server immediately. You wait 100ms, then 200ms, then 400ms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful Degradation:&lt;/strong&gt; Can the app still function (maybe without images or personalized recommendations) if a sub-system is down?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. The "Ilities": Observability and Scalability
&lt;/h2&gt;

&lt;p&gt;In a lab, if your code passes the test cases, you get an A. In the industry, "working code" is just the entry fee. The real complexity lies in how the system behaves under pressure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observability:&lt;/strong&gt; When a user says their "Add to Cart" button did not work, how do you find that specific error among millions of requests? You need logs that are actually useful. You learn to use SLF4J properly, distinguishing between &lt;code&gt;DEBUG&lt;/code&gt;, &lt;code&gt;INFO&lt;/code&gt;, and &lt;code&gt;ERROR&lt;/code&gt;. You use distributed tracing to follow a request as it hops across five different servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Your college project worked for one user on your laptop. Does it work for 100,000 concurrent users across multiple AWS regions? You start worrying about Garbage Collection (GC) tuning. You learn that "Stop-the-World" pauses can ruin a user's experience and that memory leaks in Java are very real, despite what the "Automatic Memory Management" brochures tell you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. The Database Reality Check
&lt;/h2&gt;

&lt;p&gt;In school, you write a few SQL queries against a local database. In the industry, the database is a living, breathing, and often grumpy beast. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Migrations:&lt;/strong&gt; You cannot just drop a table and start over. You use tools like Flyway or Liquibase to manage versioned changes to the schema. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection Pooling:&lt;/strong&gt; You learn that opening a database connection is expensive, so you use HikariCP to manage a pool of them. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;N+1 Select Problem:&lt;/strong&gt; You realize that a simple Hibernate mapping can accidentally trigger 1,001 database calls for a single web request, dragging your performance into the dirt. You spend hours looking at SQL logs to figure out why a "simple" page is taking five seconds to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Testing: The 1:10 Ratio
&lt;/h2&gt;

&lt;p&gt;In college, testing is often an afterthought. It is something you do manually for five minutes before submitting. &lt;/p&gt;

&lt;p&gt;In a professional environment, the test code is often larger than the feature code. You are not just writing &lt;code&gt;assertNotNull&lt;/code&gt;. You are doing things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mocking:&lt;/strong&gt; Using Mockito to simulate external services so you can test your logic in isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Testing:&lt;/strong&gt; Using Testcontainers to spin up a real Docker container of PostgreSQL just to run your suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Pipeline:&lt;/strong&gt; Your code is not "done" when it compiles. It is done when it passes a gauntlet of Unit Tests, Integration Tests, and Peer Reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. The AI Paradox: Speeding Up or Making a Mess Faster?
&lt;/h2&gt;

&lt;p&gt;In 2026, we cannot talk about industry Java without talking about AI. In college, you might use an LLM to explain a concept or write a quick utility function. In the industry, AI assistants are integrated into every step of the workflow. This is where things get truly complicated.&lt;/p&gt;

&lt;p&gt;AI is fantastic for "Boilerplate Drudgery." It can generate Spring DTOs, write repetitive unit tests, or help you convert an old XML configuration into modern Java config in seconds. It feels like a superpower that allows you to skip the boring stuff.&lt;/p&gt;

&lt;p&gt;However, industry Java is built on "Implicit Context" that AI often lacks. An LLM might suggest a perfectly valid Java snippet that works in a vacuum but completely breaks your specific production environment because it ignores your custom security filters or your specific database transaction management. &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%2F4y1acyszzwbf2jziczus.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%2F4y1acyszzwbf2jziczus.png" alt="artificial-intelligence" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are seeing a new type of technical debt: "AI Cargo Culting." This is when a developer uses an AI to generate a complex solution they do not fully understand. When that code fails in production at scale, the person who "wrote" it has no idea how to fix it because they never went through the mental exercise of building the logic themselves. In industry, you are now expected to be an orchestrator and a reviewer of AI code, which requires an even deeper understanding of the system than writing it manually ever did.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. The Human Factor: Code Reviews
&lt;/h2&gt;

&lt;p&gt;In school, the only person who sees your code is the TA. In the industry, your code is scrutinized by your peers. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; You learn that it does not matter if you prefer a certain style; you follow the team's style guide. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; You start to care about SOLID principles because you are tired of a "simple change" in one class breaking six unrelated modules. You realize that you are writing code for the person who has to fix it two years from now. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Takeaway
&lt;/h3&gt;

&lt;p&gt;If you are a student and this sounds overwhelming, that is the correct response. College teaches you how the engine works in a vacuum. The industry teaches you how to maintain the engine while the car is driving 80mph, the fuel is low, and the passenger is screaming. &lt;/p&gt;

&lt;p&gt;The complexity of Industry Java is not just in the syntax; it is in the ecosystem. It is about building things that last, things that fail gracefully, and things that other humans can understand. It is messy and frustrating, but it is significantly more rewarding once you see your "little gear" actually moving the world.&lt;/p&gt;

&lt;p&gt;What was the most surprising thing you found when you moved from academic code to production? Let's hear your war stories in the comments.&lt;/p&gt;

</description>
      <category>java</category>
      <category>career</category>
      <category>softwareengineering</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building Fault-Tolerant Order Processing with Paxos in a Distributed E-Commerce Store 🚀</title>
      <dc:creator>Anuj Ashok Potdar</dc:creator>
      <pubDate>Sun, 27 Apr 2025 20:49:06 +0000</pubDate>
      <link>https://forem.com/anizmo/building-fault-tolerant-order-processing-with-paxos-in-a-distributed-e-commerce-store-44a1</link>
      <guid>https://forem.com/anizmo/building-fault-tolerant-order-processing-with-paxos-in-a-distributed-e-commerce-store-44a1</guid>
      <description>&lt;p&gt;In a distributed e-commerce system, ensuring that each order is processed &lt;strong&gt;exactly once&lt;/strong&gt;—even when servers crash or messages get lost—is crucial. In this post, I’ll walk you through how the &lt;strong&gt;Paxos consensus algorithm&lt;/strong&gt; is used in my Spring Boot backend to coordinate order creation across multiple servers and guarantee fault tolerance.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency under failures&lt;/strong&gt;: Even if some nodes crash or the network is unreliable, Paxos ensures that a single, agreed-upon value (here, the “create order” operation) is chosen exactly once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No single point of failure&lt;/strong&gt;: Any node can propose an order, and the algorithm will still reach consensus as long as a majority of nodes are up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous &amp;amp; leaderless&lt;/strong&gt;: There’s no fixed leader; any node can initiate the consensus process.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  High-Level Flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Proposal&lt;/strong&gt;: A client sends an order request (wrapped in a &lt;code&gt;Proposal&lt;/code&gt;) to a set of Paxos servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promise&lt;/strong&gt;: Each server replies with a &lt;code&gt;Promise&lt;/code&gt; if it hasn’t promised a higher-numbered proposal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept&lt;/strong&gt;: Once the proposer gathers a majority of promises, it sends an &lt;code&gt;accept&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn&lt;/strong&gt;: After a majority of servers accept, they “learn” the chosen operation and execute it (create the order).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Key Interface
&lt;/h2&gt;

&lt;p&gt;All Paxos servers implement a simple interface (from &lt;code&gt;com.arm.coordinator.common.PaxosServer&amp;lt;T&amp;gt;&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;interface&lt;/span&gt; &lt;span class="nc"&gt;PaxosServer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Promise&lt;/span&gt; &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;learn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;userId&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;
  
  
  The Promise Phase
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;promise(...)&lt;/code&gt; method ensures that no server will accept proposals older than the one it has already promised. In your &lt;code&gt;PaxosOrderService&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="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt; &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;serverLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Receive a promise message"&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;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REJECTED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accepted&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If we’ve already accepted something, let the proposer know&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCEPTED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Proposal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accepted&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;accepted&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOperation&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Otherwise, promise not to accept lower proposals&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PROMISED&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proposal&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;(&lt;a href="https://github.com/anizmo/distributed-ecommerce-store/blob/main/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java" rel="noopener noreferrer"&gt;distributed-ecommerce-store/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java at main · anizmo/distributed-ecommerce-store · GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;maxId&lt;/code&gt; tracks the highest proposal ID seen so far. If the incoming proposal is newer, we record it and either report back the already-accepted proposal or promise to accept it later.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Accept Phase
&lt;/h2&gt;

&lt;p&gt;Once a proposer has a majority of &lt;code&gt;PROMISED&lt;/code&gt; responses, it issues an &lt;code&gt;accept&lt;/code&gt; request:&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="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;serverLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received an accept message"&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;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Only accept if this is the latest promised proposal&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Record that we’ve accepted this proposal&lt;/span&gt;
  &lt;span class="n"&gt;accepted&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;Proposal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOperation&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="n"&gt;serverLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Proposal successfully accepted"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;(&lt;a href="https://github.com/anizmo/distributed-ecommerce-store/blob/main/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java" rel="noopener noreferrer"&gt;distributed-ecommerce-store/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java at main · anizmo/distributed-ecommerce-store · GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;By checking &lt;code&gt;proposal.getId() == maxId&lt;/code&gt;, we ensure consistency: servers will only accept the proposal they most recently promised.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Learn Phase
&lt;/h2&gt;

&lt;p&gt;After a majority of servers accept, the operation is “learned” and executed exactly once:&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="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;learn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Proposal&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;serverLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received a learn message"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;OrderForm&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOperation&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOrderForm&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Validate products, create Order and OrderProducts atomically&lt;/span&gt;
  &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&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;Order&lt;/span&gt;&lt;span class="o"&gt;(...));&lt;/span&gt;
  &lt;span class="c1"&gt;// ... attach products, set status, etc.&lt;/span&gt;
  &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;result&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;Result&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ResultCodeEnum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALL_OKAY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Order created successful"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&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;(&lt;a href="https://github.com/anizmo/distributed-ecommerce-store/blob/main/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java" rel="noopener noreferrer"&gt;distributed-ecommerce-store/app/src/main/java/com/arm/ecommerce/service/PaxosOrderService.java at main · anizmo/distributed-ecommerce-store · GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This final step writes the order to the database only once, even if some servers already crashed after accepting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Solves Fault Tolerance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Majority Quorum&lt;/strong&gt;: As long as a majority of servers respond, the proposal moves forward. Crashed or slow nodes can catch up later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exactly-Once Semantics&lt;/strong&gt;: By separating promise, accept, and learn phases, you avoid double-creation even if messages are retried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovery&lt;/strong&gt;: New or recovering servers can learn the last accepted proposal and apply it to reach the same state.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Steps &amp;amp; Extensions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistent State&lt;/strong&gt;: Store &lt;code&gt;maxId&lt;/code&gt; and &lt;code&gt;accepted&lt;/code&gt; in durable storage so servers can recover after a full restart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leader Election&lt;/strong&gt;: Build a distinguished proposer to reduce round-trip latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batching&lt;/strong&gt;: Group multiple operations per consensus round for higher throughput.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;By weaving Paxos into your order service, you transform a vanilla Spring Boot app into a rock-solid, fault-tolerant distributed system. Feel free to explore the full code and fork it here:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/anizmo/distributed-ecommerce-store" rel="noopener noreferrer"&gt;github.com/anizmo/distributed-ecommerce-store&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>java</category>
      <category>blockchain</category>
      <category>distributedsystems</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Spring PetClinic Goes Global: Enhancing Accessibility with Multi-Language Support</title>
      <dc:creator>Anuj Ashok Potdar</dc:creator>
      <pubDate>Sun, 27 Apr 2025 19:05:22 +0000</pubDate>
      <link>https://forem.com/anizmo/spring-petclinic-goes-global-enhancing-accessibility-with-multi-language-support-15d5</link>
      <guid>https://forem.com/anizmo/spring-petclinic-goes-global-enhancing-accessibility-with-multi-language-support-15d5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The Spring PetClinic application is a flagship example of Spring Boot best practices, used by developers worldwide to learn enterprise patterns. Recently, my pull request (&lt;a href="https://github.com/spring-projects/spring-petclinic/commit/0c88f916db87a2a54c3cfa235d635248d400808b" rel="noopener noreferrer"&gt;#0c88f9&lt;/a&gt;) was merged, introducing a critical feature: &lt;strong&gt;full internationalization (i18n) support&lt;/strong&gt; using URL-based language switching. This update not only makes the application accessible to non-English speakers but also modernizes its architecture for scalability. Let’s explore why this matters.  &lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;The Problem: Limited Language Support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before this change, Spring PetClinic lacked robust support for multiple languages. While it included basic message properties, it didn’t fully leverage Spring’s i18n capabilities, making it difficult to:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Switch Languages Dynamically&lt;/strong&gt;: Users couldn’t change languages via the URL, a common requirement for global applications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintain Consistency&lt;/strong&gt;: Hardcoded text in HTML files made translations error-prone and fragmented.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale to New Languages&lt;/strong&gt;: Adding a new language required manual updates across HTML templates, violating the DRY (Don’t Repeat Yourself) principle.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a reference application like PetClinic, this was a missed opportunity to demonstrate scalable i18n practices.  &lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;The Solution: URL-Based Localization and Decoupled Text&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The commit introduces three key improvements:  &lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;1. Dynamic Language Switching via URL Parameters&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A new &lt;code&gt;WebConfiguration&lt;/code&gt; class configures Spring’s &lt;code&gt;LocaleResolver&lt;/code&gt; to read the &lt;code&gt;lang&lt;/code&gt; parameter from URLs (e.g., &lt;code&gt;?lang=es&lt;/code&gt;). This allows users to bookmark or share language-specific links, aligning with RESTful principles.&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="nd"&gt;@Configuration&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;WebConfiguration&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;WebMvcConfigurer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;  
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LocaleResolver&lt;/span&gt; &lt;span class="nf"&gt;localeResolver&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="nc"&gt;SessionLocaleResolver&lt;/span&gt; &lt;span class="n"&gt;slr&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;SessionLocaleResolver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  
        &lt;span class="n"&gt;slr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDefaultLocale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ENGLISH&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;slr&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;  
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LocaleChangeInterceptor&lt;/span&gt; &lt;span class="nf"&gt;localeChangeInterceptor&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="nc"&gt;LocaleChangeInterceptor&lt;/span&gt; &lt;span class="n"&gt;lci&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;LocaleChangeInterceptor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  
        &lt;span class="n"&gt;lci&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setParamName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lang"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lci&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Override&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;addInterceptors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterceptorRegistry&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInterceptor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localeChangeInterceptor&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;h4&gt;
  
  
  &lt;strong&gt;2. Centralized Message Properties&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;All UI text was moved to &lt;code&gt;messages.properties&lt;/code&gt; files (e.g., &lt;code&gt;messages_es.properties&lt;/code&gt;, &lt;code&gt;messages_fr.properties&lt;/code&gt;), decoupling content from presentation. This ensures translations are maintained in a single location.  &lt;/p&gt;

&lt;p&gt;Example (&lt;code&gt;messages_es.properties&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;welcome&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;¡Bienvenido a PetClinic!  &lt;/span&gt;
&lt;span class="py"&gt;owners&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Propietarios  &lt;/span&gt;
&lt;span class="py"&gt;find_owners&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Buscar Propietarios  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;3. HTML Template Cleanup&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Hardcoded text in Thymeleaf templates was replaced with Spring’s &lt;code&gt;#{...}&lt;/code&gt; expressions, enabling dynamic resolution based on the user’s locale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Before --&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Find Owners&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;  

&lt;span class="c"&gt;&amp;lt;!-- After --&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;th:text=&lt;/span&gt;&lt;span class="s"&gt;"#{find_owners}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Find Owners&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Architectural Impact: Why This Matters&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Scalability for Global Audiences&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;By supporting URL-driven language switching, PetClinic now serves as a blueprint for building globally accessible applications. Developers can easily add new languages by creating a &lt;code&gt;messages_xx.properties&lt;/code&gt; file—no code changes required.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Separation of Concerns&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Decoupling text from HTML templates follows the MVC pattern rigorously. Content editors can now manage translations without touching Java code or Thymeleaf markup.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Improved Maintainability&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Centralized message properties reduce duplication and make it easier to spot missing translations. For example, adding support for Japanese (&lt;code&gt;messages_ja.properties&lt;/code&gt;) becomes a trivial task.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Enhanced User Experience&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Users can now share language-specific URLs (e.g., &lt;code&gt;https://petclinic.com?lang=de&lt;/code&gt;), making the app more inclusive and user-friendly.  &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Lessons for Developers&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Design for Global Audiences Early&lt;/strong&gt;: Baking i18n into your architecture from day one avoids costly refactors later.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage Framework Features&lt;/strong&gt;: Spring’s &lt;code&gt;LocaleResolver&lt;/code&gt; and Thymeleaf’s i18n integration simplify what could otherwise be a complex task.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prioritize Clean Templates&lt;/strong&gt;: Keep text out of HTML/CSS/JS—it belongs in resource files.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Community Impact&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This commit closes issue &lt;a href="https://github.com/spring-projects/spring-petclinic/issues/1854" rel="noopener noreferrer"&gt;#1854&lt;/a&gt;, addressing a long-standing request from contributors. By merging this, PetClinic:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encourages participation from non-English speakers.
&lt;/li&gt;
&lt;li&gt;Demonstrates Spring’s i18n capabilities as a learning tool.
&lt;/li&gt;
&lt;li&gt;Sets a precedent for other open-source projects to prioritize accessibility.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Internationalization isn’t just about translating text—it’s about architecting applications to embrace diversity. This update ensures Spring PetClinic remains a modern, inclusive example for developers worldwide.  &lt;/p&gt;

&lt;p&gt;Check out the full commit &lt;a href="https://github.com/spring-projects/spring-petclinic/commit/0c88f916db87a2a54c3cfa235d635248d400808b" rel="noopener noreferrer"&gt;here&lt;/a&gt; and consider contributing your own translations!  &lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>opensource</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Building a Complex Dungeon Maze Game with Java Swing: An Architectural Deep Dive 🚀</title>
      <dc:creator>Anuj Ashok Potdar</dc:creator>
      <pubDate>Sun, 27 Apr 2025 18:26:20 +0000</pubDate>
      <link>https://forem.com/anizmo/building-a-complex-dungeon-maze-game-with-java-swing-an-architectural-deep-dive-15ol</link>
      <guid>https://forem.com/anizmo/building-a-complex-dungeon-maze-game-with-java-swing-an-architectural-deep-dive-15ol</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Java Swing is often overlooked for game development — but when used with good architecture patterns like &lt;strong&gt;MVC&lt;/strong&gt; and &lt;strong&gt;TDD&lt;/strong&gt;, it can be a powerful tool.  &lt;/p&gt;

&lt;p&gt;In this post, I’ll explain how I built a modular, extensible Dungeon Maze Game using pure Java Swing and share tips for designing maintainable, testable desktop applications.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Java Swing for a Game?
&lt;/h2&gt;

&lt;p&gt;Java Swing provides a robust and flexible UI toolkit.&lt;br&gt;&lt;br&gt;
However, it's &lt;em&gt;not&lt;/em&gt; a game engine — so to build games with Swing, you have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle &lt;strong&gt;game loops&lt;/strong&gt;, &lt;strong&gt;redraw cycles&lt;/strong&gt;, and &lt;strong&gt;user input&lt;/strong&gt; manually&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;clean separation&lt;/strong&gt; between game logic and UI rendering&lt;/li&gt;
&lt;li&gt;Solve challenges related to &lt;strong&gt;real-time responsiveness&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This made Swing an interesting challenge — and a perfect playground to apply &lt;strong&gt;software engineering principles&lt;/strong&gt; like &lt;strong&gt;MVC architecture&lt;/strong&gt; and &lt;strong&gt;Test-Driven Development&lt;/strong&gt;. Java being a language that I have been using for a while it is easy to learn and apply this framework.&lt;/p&gt;


&lt;h2&gt;
  
  
  About the Project: Java Swing Dungeon Maze Game
&lt;/h2&gt;

&lt;p&gt;The project is a &lt;strong&gt;grid-based&lt;/strong&gt; dungeon crawler where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The player navigates caves and tunnels&lt;/li&gt;
&lt;li&gt;Encounters obstacles&lt;/li&gt;
&lt;li&gt;Solves mazes generated randomly&lt;/li&gt;
&lt;li&gt;Moves using keyboard input (Arrow keys)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game architecture is designed to be &lt;strong&gt;extensible&lt;/strong&gt;, &lt;strong&gt;testable&lt;/strong&gt;, and &lt;strong&gt;easy to modify&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can find the full code here: &lt;a href="https://github.com/anizmo/JavaSwingDungeonGame" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Key Architectural Decisions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🧩 Model-View-Controller (MVC)
&lt;/h3&gt;

&lt;p&gt;Following MVC was critical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: Game logic — player movement, maze generation, obstacles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View&lt;/strong&gt;: The Swing &lt;code&gt;GamePanel&lt;/code&gt; — renders the maze, player, and tiles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controller&lt;/strong&gt;: Handles keyboard input and updates the model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Handling player movement through the &lt;code&gt;GameController&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="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;KeyEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VK_UP&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;movePlayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NORTH&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;KeyEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VK_DOWN&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;movePlayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SOUTH&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GamePanel&lt;/code&gt; listens to the controller and updates the visual state accordingly.&lt;/p&gt;

&lt;p&gt;One of the unique propositions of this application is that we are updating 2 major views, the top-down view and the first-person view. This concept can be used to create complex game elements like Heads-up-displays, Race Maps, etc.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Test-Driven Development (TDD)
&lt;/h3&gt;

&lt;p&gt;The project is equipped with &lt;strong&gt;JUnit 5&lt;/strong&gt; tests covering the core game logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Player movement&lt;/li&gt;
&lt;li&gt;Maze generation&lt;/li&gt;
&lt;li&gt;Tile obstacle placement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Testing if player movement respects walls:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testPlayerCannotWalkThroughWalls&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="n"&gt;player&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;Player&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startLocation&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Maze&lt;/span&gt; &lt;span class="n"&gt;maze&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;Maze&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;move&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NORTH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maze&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Assuming wall exists&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having tests made it easy to refactor or add new features without fear of breaking existing logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  🎲 Randomized Maze Generation
&lt;/h3&gt;

&lt;p&gt;One fun challenge was making the maze &lt;strong&gt;always connected&lt;/strong&gt; but still random. I have used &lt;strong&gt;Kruskal's algorithm&lt;/strong&gt; for the generation of the maze, which ensures generating unique mazes each time, and also that  each location is reachable from every location. &lt;/p&gt;

&lt;p&gt;To make the game more interesting, it is important to have a certain distance between the finish location and the player's spawn location. This is ensured by BFS, where the player is not "randomly" spawned but rather backtracked from the finish location and placed at &lt;code&gt;n&lt;/code&gt; steps away.&lt;/p&gt;

&lt;p&gt;I encapsulated random logic inside a dedicated 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;RandomGenerator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt; &lt;span class="n"&gt;random&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;Random&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;int&lt;/span&gt; &lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bound&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bound&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;This makes the randomness easily mockable for &lt;strong&gt;unit testing&lt;/strong&gt;!&lt;/p&gt;




&lt;h3&gt;
  
  
  🖼️ Swing Graphics Rendering
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;GamePanel&lt;/code&gt; is where the game world comes alive:&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="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;paintComponent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Graphics&lt;/span&gt; &lt;span class="n"&gt;g&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;paintComponent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;maze&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;draw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TILE_SIZE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;draw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TILE_SIZE&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;Each game tick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clears the panel&lt;/li&gt;
&lt;li&gt;Redraws the maze&lt;/li&gt;
&lt;li&gt;Redraws the player&lt;/li&gt;
&lt;li&gt;Redraws obstacles or items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This manual cycle makes sure the UI stays &lt;strong&gt;responsive&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Challenges Faced 💡
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Managing real-time updates without a game engine&lt;/li&gt;
&lt;li&gt;Designing reusable components while working within Swing's event-driven model&lt;/li&gt;
&lt;li&gt;Balancing &lt;strong&gt;testability&lt;/strong&gt; with &lt;strong&gt;performance&lt;/strong&gt; (e.g., avoiding unnecessary redraws)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each challenge forced me to think like a &lt;strong&gt;software engineer&lt;/strong&gt;, not just a game developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  How You Can Use This Template
&lt;/h2&gt;

&lt;p&gt;Because the project is built modularly, you can easily &lt;strong&gt;extend it&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add new enemy types&lt;/li&gt;
&lt;li&gt;Create different dungeon themes&lt;/li&gt;
&lt;li&gt;Add player inventory, health bars, and abilities&lt;/li&gt;
&lt;li&gt;Experiment with different maze generation algorithms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/anizmo/JavaSwingDungeonGame" rel="noopener noreferrer"&gt;repo&lt;/a&gt; if you want to fork and create your own dungeon adventure!&lt;/p&gt;




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

&lt;p&gt;Building a complex, polished game without a "game engine" using Java Swing was a rewarding experience.&lt;br&gt;&lt;br&gt;
It helped me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sharpen my understanding of MVC&lt;/li&gt;
&lt;li&gt;Deepen my appreciation for TDD&lt;/li&gt;
&lt;li&gt;Create a reusable framework for future Java-based games&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're looking to solidify your Java skills, I highly recommend trying a Swing-based project yourself!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feel free to fork &lt;a href="https://github.com/anizmo/JavaSwingDungeonGame" rel="noopener noreferrer"&gt;Java Swing Dungeon Game&lt;/a&gt; and build something amazing. 🚀&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Follow me&lt;/strong&gt; if you want more deep dives into Java development, architecture patterns, and game design! 🙌&lt;/p&gt;

</description>
      <category>java</category>
      <category>gamedev</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
