<?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: Ximena Soto</title>
    <description>The latest articles on DEV Community by Ximena Soto (@xsoto).</description>
    <link>https://dev.to/xsoto</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%2F3024288%2F2720d5b4-f23b-4025-a581-31ab726cc134.jpg</url>
      <title>DEV Community: Ximena Soto</title>
      <link>https://dev.to/xsoto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xsoto"/>
    <language>en</language>
    <item>
      <title>Armando un Sistema de E-Commerce con DDD, Java y Algunos Tropiezos Épicos</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Thu, 17 Jul 2025 02:48:40 +0000</pubDate>
      <link>https://dev.to/xsoto/construyendo-un-sistema-de-e-commerce-con-ddd-428a</link>
      <guid>https://dev.to/xsoto/construyendo-un-sistema-de-e-commerce-con-ddd-428a</guid>
      <description>&lt;p&gt;Imagina esto: un desarrollador de Java, un teclado, y la loca idea de construir algo genial con &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt;. Esa soy yo, lanzándome de cabeza a &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;, un sistema de e-commerce que es mitad ambición, mitad cafeína, y un toque de “¿por qué no funciona esto?”. Este proyecto, alojado en &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;, es mi patio de juegos para dominar &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;Spring Boot&lt;/strong&gt; y microservicios, con un guiño a mis primeros pasos en &lt;strong&gt;DevOps&lt;/strong&gt; y mi aventura hacia &lt;strong&gt;AWS&lt;/strong&gt;. Prepárate, geeks tecnológicos, porque voy a contarte los aciertos, desaciertos y momentos de comedia de este viaje, con la esperanza de encender tu curiosidad y sacarte una sonrisa.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Gran Plan: Crear un Imperio de E-Commerce (Más o Menos)
&lt;/h2&gt;

&lt;p&gt;Quise construir &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;, un sistema basado en microservicios para gestionar pedidos e inventario en una tienda online imaginaria. Piensa en “Amazon, pero codedado por una soñadora en pijama que ama DDD”. El proyecto se divide en dos microservicios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;orders-service&lt;/strong&gt;: Maneja el caos de crear pedidos, confirmar pagos y cancelarlos cuando alguien pide 500 suéteres para gatos por error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inventory-service&lt;/strong&gt;: Controla el stock, porque vender laptops imaginarios no es buen negocio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada microservicio sigue una arquitectura limpia—&lt;strong&gt;Dominio&lt;/strong&gt;, &lt;strong&gt;Aplicación&lt;/strong&gt;, &lt;strong&gt;Infraestructura&lt;/strong&gt;—porque me gusta complicarme la vida con estilo. Está construido con &lt;strong&gt;Java 17&lt;/strong&gt;, &lt;strong&gt;Spring Boot 3.2.0&lt;/strong&gt;, y un toque de magia DDD para mantener todo en orden.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué Hay en la Caja?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Líos de Pedidos&lt;/strong&gt;: Crear pedidos, confirmar pagos y cancelarlos cuando el cliente se arrepiente de su obsesión por los suéteres felinos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magia de Inventario&lt;/strong&gt;: Reservar stock al confirmar pedidos, usando eventos de dominio para no vender cosas que no existen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger con Actitud&lt;/strong&gt;: Documentación interactiva de APIs en &lt;code&gt;/swagger-ui.html&lt;/code&gt;—porque presionar botones para probar endpoints es puro amor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruebas a Tope&lt;/strong&gt;: Tests unitarios con JUnit 5 para que mi código no se desmorone como galleta en café.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD con Estilo&lt;/strong&gt;: Un pipeline de GitHub Actions que compila y prueba como jefe, mostrando mis primeros coqueteos con DevOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  El Baile DDD: Pasos Bien Dados y Algún Pisotón
&lt;/h2&gt;

&lt;p&gt;DDD es como coreografiar un baile entre la lógica de negocio y el código, y yo aún estoy aprendiendo a no pisarme los pies. &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt; se divide en dos &lt;strong&gt;Bounded Contexts&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gestión de Pedidos&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protagonista&lt;/strong&gt;: El agregado &lt;code&gt;Pedido&lt;/code&gt;, haciendo malabares con &lt;code&gt;LineaDePedido&lt;/code&gt; (artículos) y &lt;code&gt;Direccion&lt;/code&gt; (dónde enviar esos suéteres para gatos).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frases Pegajosas&lt;/strong&gt;: “Confirmar pedido”, “cancelar pedido”—mi código habla el mismo idioma que el negocio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truco Estelar&lt;/strong&gt;: Lanza un &lt;code&gt;OrderConfirmedEvent&lt;/code&gt; para gritarle al servicio de inventario, “¡Oye, reserva stock!”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gestión de Inventario&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Estrella Principal&lt;/strong&gt;: El agregado &lt;code&gt;Producto&lt;/code&gt;, con su fiel compañero &lt;code&gt;Stock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Palabras Clave&lt;/strong&gt;: “Reservar stock”, “liberar stock”—porque un almacén vacío es pura tristeza.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modo Ninja&lt;/strong&gt;: Escucha el &lt;code&gt;OrderConfirmedEvent&lt;/code&gt; para actualizar el stock sin hacer ruido.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aquí tienes un vistazo al &lt;strong&gt;Bounded Context de Gestión de Pedidos&lt;/strong&gt;, dibujado en Mermaid porque soy así de extra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;classDiagram
    class Pedido {
        -UUID id
        -List~LineaDePedido~ lineas
        -Direccion direccionEnvio
        -EstadoPedido estado
        -Double montoPago
        +confirmarPago(monto: double)
        +cancelar()
        +getId(): UUID
    }
    class LineaDePedido {
        -UUID productoId
        -int cantidad
        -double precioUnitario
    }
    class Direccion {
        -String calle
        -String ciudad
        -String codigoPostal
    }
    class EstadoPedido {
        &amp;lt;&amp;lt;enumeration&amp;gt;&amp;gt;
        PENDIENTE
        CONFIRMADO
        ENVIADO
        CANCELADO
    }
    Pedido o--&amp;gt; "many" LineaDePedido
    Pedido --&amp;gt; "1" Direccion
    Pedido --&amp;gt; "1" EstadoPedido
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Los Detalles Techies: Donde Brillamos (y Tropezamos)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Java y Spring Boot: Mis Fieles Compinches
&lt;/h3&gt;

&lt;p&gt;Con &lt;strong&gt;Java 17&lt;/strong&gt; y &lt;strong&gt;Spring Boot 3.2.0&lt;/strong&gt;, construí un sistema robusto pero con personalidad. Algunos highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arquitectura Limpia&lt;/strong&gt;: Manteniendo la lógica de dominio pura, lejos del caos de la infraestructura.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base de Datos H2&lt;/strong&gt;: Una base en memoria porque aún no estoy listo para pelear con bases de datos de producción.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger con Drama&lt;/strong&gt;: Añadí Swagger para documentar APIs, sintiéndome un genio… hasta que no funcionó (sigue leyendo).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eventos de Dominio&lt;/strong&gt;: Usé &lt;code&gt;ApplicationEventPublisher&lt;/code&gt; de Spring para que los microservicios charlen sin ponerse pegajosos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DevOps a Media Máquina
&lt;/h3&gt;

&lt;p&gt;Soy un novato en &lt;strong&gt;DevOps&lt;/strong&gt;, pero configuré un pipeline de &lt;strong&gt;GitHub Actions&lt;/strong&gt; para compilar, probar y lucir mis habilidades CI/CD. Es como enseñarle a un robot a revisar mi tarea—bastante genial cuando funciona.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sueños con AWS
&lt;/h3&gt;

&lt;p&gt;El proyecto corre localmente, pero estoy estudiando para certificaciones &lt;strong&gt;AWS&lt;/strong&gt;. Pronto desplegaré esta bestia en la nube, tal vez en ECS o EKS, para demostrar que puedo jugar en las grandes ligas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los Momentos “Facepalm”: Aprendiendo a Puro Golpe
&lt;/h2&gt;

&lt;p&gt;El camino del coder es una mezcla de “¡Eureka!” y “¿Por qué, universo, por qué?”. Aquí van mis mejores tropiezos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swagger Rebelde&lt;/strong&gt;: Añadí Swagger con orgullo, solo para que me mirara con un “No operations defined in spec!”. Resulta que mis controladores jugaban al escondite con Springdoc. Un &lt;code&gt;@Tag&lt;/code&gt; y algo de logging &lt;code&gt;DEBUG&lt;/code&gt; los pusieron en su lugar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fiesta Vacía en H2&lt;/strong&gt;: Intenté reservar stock con &lt;code&gt;curl&lt;/code&gt; y me dio un “Producto no encontrado”. Mi base H2 estaba más vacía que mi taza de café a las 3 de la mañana. Un script &lt;code&gt;data.sql&lt;/code&gt; con productos dummy salvó el día.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DDD Sobrepensado&lt;/strong&gt;: Pasé horas debatiendo si &lt;code&gt;Stock&lt;/code&gt; debía ser una entidad o un value object. Spoiler: Es un value object, y me compliqué la vida por nada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos deslices me enseñaron a abrazar el caos, depurar como detective, y reírme cuando mi código decide tomarse un descanso.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¡Pruébalo, Coder Valiente!
&lt;/h2&gt;

&lt;p&gt;¿Listo para meterte en este lío? Explora &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt; en &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;. Aquí va cómo arrancar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clona el repo:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/xsoto-developer/DddEcommerceOrders.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Lanza los microservicios:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;orders-service
   mvn clean &lt;span class="nb"&gt;install
   &lt;/span&gt;mvn spring-boot:run
   &lt;span class="nb"&gt;cd&lt;/span&gt; ../inventory-service
   mvn clean &lt;span class="nb"&gt;install
   &lt;/span&gt;mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Juega con Swagger:

&lt;ul&gt;
&lt;li&gt;Pedidos: &lt;code&gt;http://localhost:8080/swagger-ui.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inventario: &lt;code&gt;http://localhost:8081/swagger-ui.html&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Espía en H2:

&lt;ul&gt;
&lt;li&gt;Ve a &lt;code&gt;http://localhost:8081/h2-console&lt;/code&gt; (JDBC URL: &lt;code&gt;jdbc:h2:mem:inventorydb&lt;/code&gt;, User: &lt;code&gt;sa&lt;/code&gt;, Password: vacío).&lt;/li&gt;
&lt;li&gt;Corre &lt;code&gt;SELECT * FROM PRODUCTO;&lt;/code&gt; para fisgonear el stock.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consejo pro: Si Swagger se pone rebelde, revisa los logs de &lt;code&gt;org.springdoc&lt;/code&gt; o dale un buen &lt;code&gt;mvn clean install&lt;/code&gt; para calmarlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué Sigue para Este Domador de Código?
&lt;/h2&gt;

&lt;p&gt;Estoy enganchado a programar y aprender, así que esto es lo que viene:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aventura AWS&lt;/strong&gt;: Desplegar este proyecto en AWS para mostrar que puedo domar la nube.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps a Fondo&lt;/strong&gt;: Más Docker, Kubernetes, y tal vez Terraform para darle sabor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Líos Open-Source&lt;/strong&gt;: Contribuir a proyectos para unirme a la fiesta global de coders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¡Hagamos Travesuras Tecnológicas!
&lt;/h2&gt;

&lt;p&gt;¿Tienes algo que decir sobre &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;? ¿Te gustó el diagrama UML? ¿Odias mi obsesión con suéteres para gatos? Pásate por &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;, pruébalo y comparte tu sabiduría. Si eres un techie o reclutador buscando un entusiasta de Java/DDD/DevOps con talento para aprender (y algún que otro facepalm), ¡charlemos—estoy listo para construir algo épico!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Gracias por acompañarme en esta montaña rusa de código. Sigue hackeando, sigue riendo, ¡y no pidas 500 suéteres para gatos!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Este artículo también está disponible en: &lt;a href="https://dev.to/xsoto/building-a-ddd-powered-e-commerce-4e3j"&gt;Inglés&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>ddd</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Hacking Together an E-Commerce System with DDD, Java, and a Few Facepalms</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Thu, 17 Jul 2025 02:28:33 +0000</pubDate>
      <link>https://dev.to/xsoto/building-a-ddd-powered-e-commerce-4e3j</link>
      <guid>https://dev.to/xsoto/building-a-ddd-powered-e-commerce-4e3j</guid>
      <description>&lt;p&gt;Picture this: a Java developer, a keyboard, and a dream of building something cool with &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt;. That’s me, diving headfirst into &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;, an e-commerce system that’s equal parts ambition, caffeine, and “why isn’t this working?!” moments. This project, hosted at &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;, is my playground for mastering &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;Spring Boot&lt;/strong&gt;, and microservices, with a sprinkle of &lt;strong&gt;DevOps&lt;/strong&gt; and a nod to my ongoing &lt;strong&gt;AWS&lt;/strong&gt; adventure. Buckle up, tech nerds, as I share the highs, lows, and hilarious missteps of building this beast, hoping to spark your curiosity and maybe a chuckle or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Grand Plan: Building an E-Commerce Empire (Sort Of)
&lt;/h2&gt;

&lt;p&gt;I set out to create &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;, a microservices-based system to manage orders and inventory for an imaginary e-commerce empire. Think “Amazon, but coded by one guy in pajamas with a love for DDD.” The project splits into two microservices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;orders-service&lt;/strong&gt;: Handles the chaos of order creation, payment confirmation, and cancellations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inventory-service&lt;/strong&gt;: Keeps track of stock, because nobody wants to sell 100 imaginary laptops that don’t exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each microservice follows a clean architecture—&lt;strong&gt;Domain&lt;/strong&gt;, &lt;strong&gt;Application&lt;/strong&gt;, &lt;strong&gt;Infrastructure&lt;/strong&gt;—because I’m fancy like that. It’s built with &lt;strong&gt;Java 17&lt;/strong&gt;, &lt;strong&gt;Spring Boot 3.2.0&lt;/strong&gt;, and a dash of DDD magic to keep things organized.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Inside the Box?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order Shenanigans&lt;/strong&gt;: Create orders, confirm payments, and cancel them when someone inevitably orders 500 cat sweaters by mistake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory Wizardry&lt;/strong&gt;: Reserve stock when orders are confirmed, using domain events to avoid awkward overselling situations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger Swagger&lt;/strong&gt;: Interactive API docs at &lt;code&gt;/swagger-ui.html&lt;/code&gt;—because who doesn’t love clicking buttons to test APIs?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests, Tests, Tests&lt;/strong&gt;: JUnit 5 unit tests to make sure my code doesn’t implode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD Coolness&lt;/strong&gt;: A GitHub Actions pipeline that builds and tests like a boss, proving I’m dipping my toes into DevOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The DDD Dance: Twirling Through Bounded Contexts
&lt;/h2&gt;

&lt;p&gt;DDD is like choreographing a dance between business logic and code, and I’m still learning the steps. &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt; splits into two &lt;strong&gt;Bounded Contexts&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Order Management&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Star of the Show&lt;/strong&gt;: The &lt;code&gt;Pedido&lt;/code&gt; aggregate, juggling &lt;code&gt;LineaDePedido&lt;/code&gt; (items) and &lt;code&gt;Direccion&lt;/code&gt; (where to ship those cat sweaters).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catchy Phrases&lt;/strong&gt;: “Confirm order,” “cancel order”—my code speaks the same language as the business.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Party Trick&lt;/strong&gt;: Fires an &lt;code&gt;OrderConfirmedEvent&lt;/code&gt; to tell the inventory service, “Yo, reserve some stock!”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory Management&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Main Character&lt;/strong&gt;: The &lt;code&gt;Producto&lt;/code&gt; aggregate, with its trusty sidekick &lt;code&gt;Stock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buzzwords&lt;/strong&gt;: “Reserve stock,” “release stock”—because nobody likes an empty warehouse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Listener Vibes&lt;/strong&gt;: Catches &lt;code&gt;OrderConfirmedEvent&lt;/code&gt; to update stock like a ninja.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s a peek at the &lt;strong&gt;Order Management&lt;/strong&gt; Bounded Context, drawn in Mermaid because I’m extra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;classDiagram
    class Pedido {
        -UUID id
        -List~LineaDePedido~ lineas
        -Direccion direccionEnvio
        -EstadoPedido estado
        -Double montoPago
        +confirmarPago(monto: double)
        +cancelar()
        +getId(): UUID
    }
    class LineaDePedido {
        -UUID productoId
        -int cantidad
        -double precioUnitario
    }
    class Direccion {
        -String calle
        -String ciudad
        -String codigoPostal
    }
    class EstadoPedido {
        &amp;lt;&amp;lt;enumeration&amp;gt;&amp;gt;
        PENDIENTE
        CONFIRMADO
        ENVIADO
        CANCELADO
    }
    Pedido o--&amp;gt; "many" LineaDePedido
    Pedido --&amp;gt; "1" Direccion
    Pedido --&amp;gt; "1" EstadoPedido
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Techy Bits: Where I Shined (and Tripped)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Java and Spring Boot: My Trusty Sidekicks
&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;Java 17&lt;/strong&gt; and &lt;strong&gt;Spring Boot 3.2.0&lt;/strong&gt;, I built a system that’s robust but not boring. Some highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clean Architecture&lt;/strong&gt;: Keeping domain logic pure, away from the messy infrastructure stuff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H2 Database&lt;/strong&gt;: An in-memory database because I’m not ready to wrestle with production-grade DBs just yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger Shenanigans&lt;/strong&gt;: Added Swagger for API docs, which made me feel like a rockstar… until it didn’t work (more on that later).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Events&lt;/strong&gt;: Used Spring’s &lt;code&gt;ApplicationEventPublisher&lt;/code&gt; to keep microservices chatty without them getting clingy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DevOps Dabbling
&lt;/h3&gt;

&lt;p&gt;I’m a newbie to &lt;strong&gt;DevOps&lt;/strong&gt;, but I set up a &lt;strong&gt;GitHub Actions&lt;/strong&gt; pipeline to build, test, and flex my CI/CD muscles. It’s like teaching a robot to check my homework—pretty cool when it works!&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Dreams
&lt;/h3&gt;

&lt;p&gt;The project runs locally, but I’m prepping for &lt;strong&gt;AWS&lt;/strong&gt; certifications. Soon, I’ll deploy this bad boy to the cloud, maybe on ECS or EKS, to show I can play in the big leagues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Facepalm Moments: Learning the Hard Way
&lt;/h2&gt;

&lt;p&gt;Every coder’s journey is a mix of “Eureka!” and “Why, universe, why?” Here are my top bloopers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swagger’s Silent Treatment&lt;/strong&gt;: I proudly added Swagger, only to see “No operations defined in spec!” staring back at me. Turns out, my controllers were playing hide-and-seek with Springdoc. A quick &lt;code&gt;@Tag&lt;/code&gt; and some &lt;code&gt;DEBUG&lt;/code&gt; logging later, they were back in the spotlight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H2’s Empty Party&lt;/strong&gt;: Tried reserving stock with &lt;code&gt;curl&lt;/code&gt;, got “Producto no encontrado.” Cue me realizing my H2 database was emptier than my coffee mug at 3 AM. A &lt;code&gt;data.sql&lt;/code&gt; script with some dummy products saved the day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DDD Overthinking&lt;/strong&gt;: I spent hours debating whether &lt;code&gt;Stock&lt;/code&gt; should be an entity or a value object. Spoiler: It’s a value object, and I overcomplicated it for no reason.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These missteps taught me to embrace the chaos, debug like a detective, and laugh when my code decides to take a coffee break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out, You Curious Coder!
&lt;/h2&gt;

&lt;p&gt;Ready to dive into the madness? Check out &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt; at &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;. Here’s how to get it running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/xsoto-developer/DddEcommerceOrders.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Fire up the microservices:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;orders-service
   mvn clean &lt;span class="nb"&gt;install
   &lt;/span&gt;mvn spring-boot:run
   &lt;span class="nb"&gt;cd&lt;/span&gt; ../inventory-service
   mvn clean &lt;span class="nb"&gt;install
   &lt;/span&gt;mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Play with Swagger:

&lt;ul&gt;
&lt;li&gt;Orders: &lt;code&gt;http://localhost:8080/swagger-ui.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inventory: &lt;code&gt;http://localhost:8081/swagger-ui.html&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Snoop around H2:

&lt;ul&gt;
&lt;li&gt;Hit &lt;code&gt;http://localhost:8081/h2-console&lt;/code&gt; (JDBC URL: &lt;code&gt;jdbc:h2:mem:inventorydb&lt;/code&gt;, User: &lt;code&gt;sa&lt;/code&gt;, Password: blank).&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;SELECT * FROM PRODUCTO;&lt;/code&gt; to spy on the stock.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pro tip: If Swagger gives you attitude, check the logs for &lt;code&gt;org.springdoc&lt;/code&gt; or give your server a good ol’ restart (&lt;code&gt;mvn clean install&lt;/code&gt; never hurts).&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next for This Code Wrangler?
&lt;/h2&gt;

&lt;p&gt;I’m hooked on coding and learning, so here’s what’s on my radar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Adventure&lt;/strong&gt;: Deploying this project to AWS to prove I can tame the cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps Deep Dive&lt;/strong&gt;: More Docker, Kubernetes, and maybe some Terraform to spice things up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-Source Shenanigans&lt;/strong&gt;: Contributing to projects to join the global coder party.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let’s Geek Out Together!
&lt;/h2&gt;

&lt;p&gt;Got thoughts on &lt;strong&gt;DddEcommerceOrders&lt;/strong&gt;? Loved the UML diagram? Hated my cat sweater obsession? Drop by &lt;a href="https://github.com/xsoto-developer/DddEcommerceOrders" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/DddEcommerceOrders&lt;/a&gt;, give it a spin, and share your wisdom. If you’re a fellow techie or a recruiter looking for a Java/DDD/DevOps enthusiast with a knack for learning (and occasional facepalms), let’s chat—I’m ready to build something epic!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for joining me on this coding rollercoaster. Keep hacking, keep laughing, and maybe don’t order 500 cat sweaters!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This article is also available in: &lt;a href="https://dev.to/xsoto/construyendo-un-sistema-de-e-commerce-con-ddd-428a"&gt;Spanish&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>ddd</category>
      <category>microservices</category>
    </item>
    <item>
      <title>From Monolith to Microservices</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Sun, 13 Apr 2025 16:18:49 +0000</pubDate>
      <link>https://dev.to/xsoto/from-monolith-to-microservices-418i</link>
      <guid>https://dev.to/xsoto/from-monolith-to-microservices-418i</guid>
      <description>&lt;h1&gt;
  
  
  Building a Resilient Hotel Booking System with Spring Boot and Resilience4j
&lt;/h1&gt;

&lt;p&gt;As a seasoned Java developer, I’ve always been fascinated by the challenge of building systems that are not just functional but also scalable, resilient, and maintainable. Over the years, I’ve worked on various projects, but none have been as transformative as my recent journey into microservices with the &lt;strong&gt;Hotel Reservation System&lt;/strong&gt;—a project that pushed me to embrace &lt;strong&gt;3 resilience patterns (Circuit Breaker + Retry) for hotel bookings, with polyglot persistence (PostgreSQL + MongoDB)&lt;/strong&gt;. In this article, I’ll share the technical and personal lessons learned while transitioning from a monolithic mindset to a microservices architecture, focusing on the challenges, triumphs, and practical insights for Java developers looking to make a similar leap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction: A Java Developer’s Quest for Resilience
&lt;/h2&gt;

&lt;p&gt;With experience in Java, I’ve built everything from enterprise monoliths to RESTful APIs. But as cloud-native architectures gained traction, I felt the urge to dive into microservices—not just to stay relevant but to explore how patterns like &lt;strong&gt;Circuit Breaker&lt;/strong&gt;, &lt;strong&gt;Retry&lt;/strong&gt;, and &lt;strong&gt;Specification&lt;/strong&gt; could elevate system design. My motivation was clear: create a &lt;strong&gt;hotel booking platform&lt;/strong&gt; that could handle real-world failures gracefully, using modern tools like &lt;strong&gt;Spring Boot 3.2.4&lt;/strong&gt;, &lt;strong&gt;Maven&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt;, and &lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Hotel Reservation System&lt;/strong&gt; became my playground—a set of three microservices (&lt;code&gt;hotel-rooms-service&lt;/code&gt;, &lt;code&gt;hotel-reservations-service&lt;/code&gt;, and &lt;code&gt;hotel-payments-service&lt;/code&gt;) designed to manage room availability, reservations, and payments. This project wasn’t just about coding; it was about mastering &lt;strong&gt;design patterns&lt;/strong&gt;, embracing &lt;strong&gt;polyglot persistence&lt;/strong&gt;, and deploying with &lt;strong&gt;Docker&lt;/strong&gt;. Along the way, I faced significant challenges, learned invaluable lessons, and even had a few humbling moments that reshaped my approach to development.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Challenges: Navigating the Microservices Maze
&lt;/h2&gt;

&lt;p&gt;Transitioning to microservices wasn’t a walk in the park. Here are the key obstacles I encountered and the lessons they taught me:&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 1: Understanding Microservices Boundaries
&lt;/h3&gt;

&lt;p&gt;Coming from a monolithic background, I initially struggled to define clear boundaries for each microservice. Should payments handle reservation validation? Should rooms manage availability checks? The complexity of distributed systems felt overwhelming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;: I adopted Domain-Driven Design (DDD) principles to carve out bounded contexts. For example, &lt;code&gt;hotel-rooms-service&lt;/code&gt; focused solely on room inventory and availability, using the &lt;strong&gt;Specification Pattern&lt;/strong&gt; to filter rooms dynamically:&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="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAvailableRooms&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;guestCount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;maxPrice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAvailable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasGuestCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guestCount&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasMaxPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxPrice&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;roomRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&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 pattern encapsulated filtering logic, making it reusable and testable—a cornerstone of clean code in microservices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 2: Resilience in a Distributed World
&lt;/h3&gt;

&lt;p&gt;Failures in microservices are inevitable—network glitches, database timeouts, or third-party service outages. My early attempts at payment processing were brittle, crashing on transient errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;: I embraced &lt;strong&gt;3 resilience patterns (Circuit Breaker + Retry) for hotel bookings&lt;/strong&gt; using &lt;strong&gt;Resilience4j&lt;/strong&gt;. The payment service became my proving ground:&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;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"paymentService"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"processPaymentFallback"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"paymentService"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"processPaymentFallback"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&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;"Processing payment for reservationId: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reservationId&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="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment service failed"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;payment&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;Payment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"COMPLETED"&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;paymentRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="nf"&gt;processPaymentFallback&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fallback triggered for reservationId: {} due to: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&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;Payment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PENDING"&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;CircuitBreaker&lt;/strong&gt;: Prevents cascading failures by opening the circuit after 5 failures (50% of 10 calls), redirecting to the fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry&lt;/strong&gt;: Attempts up to 3 retries with exponential backoff (500ms, 1000ms, 2000ms) before giving up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; (in &lt;code&gt;application.properties&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;  &lt;span class="py"&gt;resilience4j.circuitbreaker.instances.paymentService.slidingWindowSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.circuitbreaker.instances.paymentService.failureRateThreshold&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;50&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.maxAttempts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.waitDuration&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;500&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.enableExponentialBackoff&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This combination made the payment service robust, handling transient failures gracefully while maintaining user trust with a &lt;code&gt;"PENDING"&lt;/code&gt; status.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 3: Polyglot Persistence
&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;PostgreSQL&lt;/strong&gt; for rooms and reservations and &lt;strong&gt;MongoDB&lt;/strong&gt; for payments introduced complexity. I underestimated the differences in data modeling and connection management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;: &lt;strong&gt;Polyglot persistence&lt;/strong&gt; requires careful planning. For example, &lt;code&gt;hotel-rooms-service&lt;/code&gt; used JPA for structured room data:&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;@Entity&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;Room&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;guestCapacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile, &lt;code&gt;hotel-payments-service&lt;/code&gt; leveraged MongoDB’s flexibility:&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;@Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"payments"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I learned to align database choices with domain needs—PostgreSQL for relational integrity, MongoDB for high-write scenarios like payments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 4: Dockerizing a Multi-Module Project
&lt;/h3&gt;

&lt;p&gt;Deploying with &lt;strong&gt;Docker&lt;/strong&gt; revealed my naivety about multi-module Maven projects. My first &lt;code&gt;Dockerfile&lt;/code&gt; attempts failed spectacularly, with errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: failed to solve: maven:3.9.6-openjdk-17: not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[FATAL] Non-resolvable parent POM for org.xsoto.springcloud.msvc:hotel-payments-service:0.0.1-SNAPSHOT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;: Multi-stage Docker builds and proper context management are critical. Here’s the final &lt;code&gt;Dockerfile&lt;/code&gt; for &lt;code&gt;hotel-payments-service&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build the application&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;maven:3.9.6-eclipse-temurin-17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ../pom.xml ./pom.xml&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./pom.xml ./hotel-payments-service/pom.xml&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn dependency:go-offline &lt;span class="nt"&gt;-B&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src ./hotel-payments-service/src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn clean package &lt;span class="nt"&gt;-pl&lt;/span&gt; hotel-payments-service &lt;span class="nt"&gt;-am&lt;/span&gt; &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="c"&gt;# Stage 2: Create the runtime image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:17-jdk-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/hotel-payments-service/target/hotel-payments-service-1.0-SNAPSHOT.jar app.jar&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8083&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; SPRING_DATA_MONGODB_URI=mongodb://mongo:27017/payments_db&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key was including the parent &lt;code&gt;pom.xml&lt;/code&gt; and building from the root directory to resolve dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Personal Anecdote: The Docker Debacle
&lt;/h2&gt;

&lt;p&gt;Let me share a moment that humbled me. Early in the Dockerization process, I was confident I could whip up a &lt;code&gt;Dockerfile&lt;/code&gt; in minutes. I started with &lt;code&gt;maven:3.8.6-openjdk-17-slim&lt;/code&gt;, assuming it existed. Spoiler: it didn’t. The build failed with &lt;code&gt;image not found&lt;/code&gt;. Undeterred, I switched to &lt;code&gt;maven:3.9.6-openjdk-17&lt;/code&gt;—another dead end. Then came the real kicker: the &lt;code&gt;Non-resolvable parent POM&lt;/code&gt; error. I’d overlooked the multi-module structure, naively copying only the module’s &lt;code&gt;pom.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hours of debugging later, I realized my mistake: Docker’s build context needed the parent &lt;code&gt;pom.xml&lt;/code&gt;, and I had to verify image tags on Docker Hub. It was a classic case of overconfidence meeting reality. But that frustration led to a breakthrough—learning to use multi-stage builds, &lt;code&gt;.dockerignore&lt;/code&gt;, and &lt;code&gt;docker-compose&lt;/code&gt; effectively. That moment taught me to respect the nuances of containerization and double-check assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Experience: Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;Building the &lt;strong&gt;Hotel Reservation System&lt;/strong&gt; required integrating &lt;strong&gt;Spring Boot 3.2.4&lt;/strong&gt;, &lt;strong&gt;Maven&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt;, and &lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;. Here’s how it came together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Microservices Setup&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hotel-rooms-service&lt;/code&gt; (port 8081, PostgreSQL): Manages room inventory with the &lt;strong&gt;Specification Pattern&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hotel-reservations-service&lt;/code&gt; (port 8082, PostgreSQL): Handles bookings with a &lt;strong&gt;Factory Pattern&lt;/strong&gt; for object creation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hotel-payments-service&lt;/code&gt; (port 8083, MongoDB): Processes payments with &lt;strong&gt;CircuitBreaker + Retry&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
A single &lt;code&gt;docker-compose.yml&lt;/code&gt; orchestrated everything:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15-alpine&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:6&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27017:27017"&lt;/span&gt;
    &lt;span class="na"&gt;hotel-rooms-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-rooms-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8081:8081"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATASOURCE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://postgres:5432/rooms_db&lt;/span&gt;
    &lt;span class="na"&gt;hotel-reservations-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-reservations-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8082:8082"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATASOURCE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://postgres:5432/reservations_db&lt;/span&gt;
    &lt;span class="na"&gt;hotel-payments-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-payments-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8083:8083"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATA_MONGODB_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb://mongo:27017/payments_db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;:&lt;br&gt;
Each service exposed a Swagger UI (e.g., &lt;code&gt;http://localhost:8083/swagger-ui.html&lt;/code&gt;), making API testing a breeze.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt;:&lt;br&gt;
Comprehensive tests validated resilience patterns:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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;testProcessPayment_FallbackTriggered&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"res1"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;150.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;circuitBreaker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transitionToOpenState&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PENDING"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&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;
  
  
  Tips for Java Developers Transitioning to Microservices
&lt;/h2&gt;

&lt;p&gt;For fellow Java developers eyeing a similar transition, here are practical tips to make your journey smoother:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Master Design Patterns&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Study &lt;strong&gt;Circuit Breaker&lt;/strong&gt;, &lt;strong&gt;Retry&lt;/strong&gt;, and &lt;strong&gt;Specification&lt;/strong&gt;. They’re not just buzzwords—they solve real problems. Start with Resilience4j’s documentation for hands-on examples.&lt;/li&gt;
&lt;li&gt;Example: Tune Retry parameters carefully to avoid overwhelming downstream services.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Embrace Polyglot Persistence&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose databases based on domain needs. For our hotel system, &lt;strong&gt;PostgreSQL&lt;/strong&gt; ensured relational integrity for rooms, while &lt;strong&gt;MongoDB&lt;/strong&gt; handled high-write payment data.&lt;/li&gt;
&lt;li&gt;Tip: Use Spring Data’s abstractions to simplify repository code across databases.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Comfortable with Docker&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use multi-stage builds to keep images lean. Alpine-based images like &lt;code&gt;openjdk:17-jdk-alpine&lt;/code&gt; saved me ~200 MB per service.&lt;/li&gt;
&lt;li&gt;Always verify image tags on Docker Hub before building.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;.dockerignore&lt;/code&gt; is your friend:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; target/
 *.jar
 *.log
 .idea/
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test Relentlessly&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write tests for resilience patterns. Mock failures to ensure fallbacks work as expected.&lt;/li&gt;
&lt;li&gt;Use tools like JaCoCo for code coverage to impress potential employers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automate Early&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a CI/CD pipeline (e.g., GitHub Actions) to build and test Docker images automatically. This saves time and catches errors early.&lt;/li&gt;
&lt;li&gt;Example: A simple workflow to build and push images:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker Images&lt;/span&gt;
 &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
 &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
     &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
       &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Learn from Mistakes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t fear errors like &lt;code&gt;image not found&lt;/code&gt; or &lt;code&gt;non-resolvable POM&lt;/code&gt;. They’re opportunities to deepen your understanding.&lt;/li&gt;
&lt;li&gt;Keep a debugging log to track what worked and what didn’t.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion: A Journey Worth Taking
&lt;/h2&gt;

&lt;p&gt;Transitioning to microservices with the &lt;strong&gt;Hotel Reservation System&lt;/strong&gt; was a game-changer. It taught me to build resilient, scalable systems using &lt;strong&gt;3 resilience patterns (Circuit Breaker + Retry) for hotel bookings, with polyglot persistence (PostgreSQL + MongoDB)&lt;/strong&gt;. The challenges—defining boundaries, mastering resilience, and conquering Docker—were steep but rewarding. Each error, from missing image tags to POM resolution woes, sharpened my skills and mindset.&lt;/p&gt;

&lt;p&gt;To my fellow Java developers: dive into microservices and &lt;strong&gt;design patterns&lt;/strong&gt;. Experiment with &lt;strong&gt;Spring Boot&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt;, and &lt;strong&gt;Docker&lt;/strong&gt;. The road may be bumpy, but the ability to craft systems that thrive under pressure is worth every moment. Start small, test rigorously, and automate fearlessly. Your next project could be the one that defines your career.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔍 ¿Would you like to see the code in action?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Explore &lt;strong&gt;SpringResilientHotel&lt;/strong&gt; on GitHub:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/xsoto-developer/SpringResilientHotel" rel="noopener noreferrer"&gt;github.com/xsoto-developer/SpringResilientHotel&lt;/a&gt; &lt;/p&gt;




&lt;p&gt;&lt;em&gt;What’s your next microservices adventure? Share your thoughts in the comments or ping me on GitHub!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✨ Bonus: Feel free to leave a ⭐️ or open an issue with suggestions, I appreciate the feedback!&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This article is also available in: &lt;a href="https://dev.to/xsoto/de-monolitos-a-microservicios-4bef"&gt;Spanish&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

</description>
      <category>microservices</category>
      <category>resilience4j</category>
      <category>springboot</category>
      <category>docker</category>
    </item>
    <item>
      <title>De Monolitos a Microservicios</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Sun, 13 Apr 2025 15:50:30 +0000</pubDate>
      <link>https://dev.to/xsoto/de-monolitos-a-microservicios-4bef</link>
      <guid>https://dev.to/xsoto/de-monolitos-a-microservicios-4bef</guid>
      <description>&lt;h1&gt;
  
  
  Construyendo un Sistema de Reservas de Hotel Resiliente con Spring Boot y Resilience4j
&lt;/h1&gt;

&lt;p&gt;Como desarrollador Java, siempre me ha apasionado construir sistemas que no solo funcionen, sino que también sean escalables, resilientes y fáciles de mantener. He trabajado en proyectos de todo tipo, desde monolitos empresariales hasta APIs RESTful, pero ninguno ha sido tan transformador como mi incursión en microservicios con el &lt;strong&gt;Sistema de Reservas de Hotel&lt;/strong&gt;. Este proyecto me permitió dominar &lt;strong&gt;3 patrones de resiliencia (Circuit Breaker + Retry) para reservas hoteleras, con persistencia políglota (PostgreSQL + MongoDB)&lt;/strong&gt;. En este artículo, comparto los retos, aprendizajes y consejos prácticos para desarrolladores Java experimentados que quieran embarcarse en una transición similar hacia microservicios, con un enfoque en &lt;strong&gt;patrones de diseño&lt;/strong&gt; y resiliencia.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducción: La Búsqueda de Resiliencia de un Desarrollador Java
&lt;/h2&gt;

&lt;p&gt;Con algunos años de experiencia en Java, he construido sistemas robustos, pero el auge de las arquitecturas nativas en la nube me motivó a explorar los microservicios. Quería ir más allá de lo convencional y aprender cómo los &lt;strong&gt;patrones de diseño&lt;/strong&gt; como &lt;strong&gt;Circuit Breaker&lt;/strong&gt;, &lt;strong&gt;Retry&lt;/strong&gt; y &lt;strong&gt;Specification&lt;/strong&gt; podían elevar la calidad de mis aplicaciones. Mi objetivo fue ambicioso: desarrollar un &lt;strong&gt;sistema de reservas hoteleras&lt;/strong&gt; que manejara fallos del mundo real con elegancia, utilizando herramientas modernas como &lt;strong&gt;Spring Boot 3.2.4&lt;/strong&gt;, &lt;strong&gt;Maven&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt; y &lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;Sistema de Reservas de Hotel&lt;/strong&gt; se convirtió en mi laboratorio personal, compuesto por tres microservicios: &lt;code&gt;hotel-rooms-service&lt;/code&gt; (gestión de habitaciones), &lt;code&gt;hotel-reservations-service&lt;/code&gt; (reservas) y &lt;code&gt;hotel-payments-service&lt;/code&gt; (pagos). Este proyecto no solo se trató de programar, sino de adoptar una mentalidad distribuida, integrar &lt;strong&gt;persistencia políglota&lt;/strong&gt; y desplegar con &lt;strong&gt;Docker&lt;/strong&gt;. A lo largo del camino, enfrenté desafíos significativos, aprendí lecciones valiosas y viví momentos que me hicieron replantear mi enfoque como desarrollador.&lt;/p&gt;




&lt;h2&gt;
  
  
  Los Retos: Navegando por el Laberinto de los Microservicios
&lt;/h2&gt;

&lt;p&gt;La transición a microservicios no fue sencilla. Aquí detallo los principales obstáculos que encontré y las lecciones que me dejaron:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reto 1: Definir los Límites de los Microservicios
&lt;/h3&gt;

&lt;p&gt;Proveniente de un entorno monolítico, me costó delimitar las responsabilidades de cada microservicio. ¿Debería el servicio de pagos validar reservas? ¿El servicio de habitaciones debería gestionar la disponibilidad? La complejidad de los sistemas distribuidos me abrumó al principio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aprendizaje&lt;/strong&gt;: Adopté principios de &lt;strong&gt;Diseño Dirigido por el Dominio (DDD)&lt;/strong&gt; para establecer contextos acotados. Por ejemplo, &lt;code&gt;hotel-rooms-service&lt;/code&gt; se centró únicamente en el inventario de habitaciones, utilizando el &lt;strong&gt;Patrón Specification&lt;/strong&gt; para filtrar disponibilidad de forma dinámica:&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="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAvailableRooms&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;guestCount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;maxPrice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAvailable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasGuestCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guestCount&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoomSpecifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasMaxPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxPrice&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;roomRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&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;Este patrón encapsuló la lógica de filtrado, haciéndola reutilizable y fácil de probar, un pilar del código limpio en microservicios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reto 2: Resiliencia en un Mundo Distribuido
&lt;/h3&gt;

&lt;p&gt;Los fallos en microservicios son inevitables: problemas de red, tiempos de espera en bases de datos o caídas de servicios externos. Mis primeros intentos de procesar pagos eran frágiles, colapsando ante errores transitorios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aprendizaje&lt;/strong&gt;: Implementé &lt;strong&gt;patrones de resiliencia (Circuit Breaker + Retry) para reservas hoteleras&lt;/strong&gt; con &lt;strong&gt;Resilience4j&lt;/strong&gt;. El servicio de pagos fue mi campo de pruebas:&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;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"paymentService"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"processPaymentFallback"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"paymentService"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"processPaymentFallback"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&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;"Procesando pago para reservationId: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reservationId&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="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fallo en el servicio de pagos"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;payment&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;Payment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"COMPLETED"&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;paymentRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="nf"&gt;processPaymentFallback&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fallback activado para reservationId: {} debido a: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&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;Payment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PENDING"&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;CircuitBreaker&lt;/strong&gt;: Evita fallos en cascada al abrir el circuito tras 5 errores (50% de 10 llamadas), redirigiendo al fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry&lt;/strong&gt;: Reintenta hasta 3 veces con backoff exponencial (500ms, 1000ms, 2000ms) antes de rendirse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuración&lt;/strong&gt; (en &lt;code&gt;application.properties&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;  &lt;span class="py"&gt;resilience4j.circuitbreaker.instances.paymentService.slidingWindowSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.circuitbreaker.instances.paymentService.failureRateThreshold&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;50&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.maxAttempts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.waitDuration&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;500&lt;/span&gt;
  &lt;span class="py"&gt;resilience4j.retry.instances.paymentService.enableExponentialBackoff&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta combinación hizo que el servicio de pagos fuera robusto, manejando fallos transitorios sin comprometer la experiencia del usuario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reto 3: Persistencia Políglota
&lt;/h3&gt;

&lt;p&gt;Usar &lt;strong&gt;PostgreSQL&lt;/strong&gt; para habitaciones y reservas y &lt;strong&gt;MongoDB&lt;/strong&gt; para pagos añadió complejidad. Subestimé las diferencias en modelado de datos y gestión de conexiones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aprendizaje&lt;/strong&gt;: La &lt;strong&gt;persistencia políglota&lt;/strong&gt; requiere planificación. Por ejemplo, &lt;code&gt;hotel-rooms-service&lt;/code&gt; usó JPA para datos estructurados:&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;@Entity&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;Room&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;guestCapacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters y setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En cambio, &lt;code&gt;hotel-payments-service&lt;/code&gt; aprovechó la flexibilidad de MongoDB:&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;@Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"payments"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters y setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aprendí a alinear la elección de bases de datos con las necesidades del dominio: &lt;strong&gt;PostgreSQL&lt;/strong&gt; para integridad relacional, &lt;strong&gt;MongoDB&lt;/strong&gt; para escenarios de alta escritura como pagos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reto 4: Dockerizando un Proyecto Multi-Módulo
&lt;/h3&gt;

&lt;p&gt;Desplegar con &lt;strong&gt;Docker&lt;/strong&gt; expuso mi falta de experiencia con proyectos Maven multi-módulo. Mis primeros intentos fallaron estrepitosamente, con errores como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: failed to solve: maven:3.9.6-openjdk-17: not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;y más tarde:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[FATAL] Non-resolvable parent POM for org.xsoto.springcloud.msvc:hotel-payments-service:0.0.1-SNAPSHOT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Aprendizaje&lt;/strong&gt;: Los builds multi-stage y la gestión del contexto son cruciales. Este es el &lt;code&gt;Dockerfile&lt;/code&gt; final para &lt;code&gt;hotel-payments-service&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build the application&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;maven:3.9.6-eclipse-temurin-17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ../pom.xml ./pom.xml&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./pom.xml ./hotel-payments-service/pom.xml&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn dependency:go-offline &lt;span class="nt"&gt;-B&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src ./hotel-payments-service/src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn clean package &lt;span class="nt"&gt;-pl&lt;/span&gt; hotel-payments-service &lt;span class="nt"&gt;-am&lt;/span&gt; &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="c"&gt;# Stage 2: Create the runtime image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eclipse-temurin:17.0.10_7-jre-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/hotel-payments-service/target/hotel-payments-service-1.0-SNAPSHOT.jar app.jar&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8083&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; SPRING_DATA_MONGODB_URI=mongodb://mongo:27017/payments_db&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La clave fue incluir el &lt;code&gt;pom.xml&lt;/code&gt; padre y construir desde el directorio raíz para resolver dependencias.&lt;/p&gt;




&lt;h2&gt;
  
  
  Una Anécdota Personal: El Desastre con Docker
&lt;/h2&gt;

&lt;p&gt;Permíteme contarte un momento que me hizo más humilde. Al principio del proceso de dockerización, estaba convencido de que crear un &lt;code&gt;Dockerfile&lt;/code&gt; sería pan comido. Empecé con &lt;code&gt;maven:3.8.6-openjdk-17-slim&lt;/code&gt;, asumiendo que existía. No fue así—el build falló con &lt;code&gt;image not found&lt;/code&gt;. Cambié a &lt;code&gt;maven:3.9.6-openjdk-17&lt;/code&gt;, pero el error persistió. Luego, el golpe final: el temido &lt;code&gt;Non-resolvable parent POM&lt;/code&gt;. Había ignorado la estructura multi-módulo, copiando solo el &lt;code&gt;pom.xml&lt;/code&gt; del módulo.&lt;/p&gt;

&lt;p&gt;Tras horas de depuración, descubrí mi error: el contexto de Docker necesitaba el &lt;code&gt;pom.xml&lt;/code&gt; padre, y debía verificar los tags en Docker Hub. Fue un recordatorio doloroso de no dar nada por sentado. Pero esa frustración me llevó a dominar builds multi-stage, &lt;code&gt;.dockerignore&lt;/code&gt; y &lt;code&gt;docker-compose&lt;/code&gt;. Ese traspié me enseñó a valorar los detalles de la contenerización.&lt;/p&gt;




&lt;h2&gt;
  
  
  Experiencia Práctica: Uniendo las Piezas
&lt;/h2&gt;

&lt;p&gt;Construir el &lt;strong&gt;Sistema de Reservas de Hotel&lt;/strong&gt; requirió integrar &lt;strong&gt;Spring Boot 3.2.4&lt;/strong&gt;, &lt;strong&gt;Maven&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt; y &lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;. Así lo logré:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configuración de Microservicios&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hotel-rooms-service&lt;/code&gt; (puerto 8081, PostgreSQL): Gestiona inventario con &lt;strong&gt;Patrón Specification&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hotel-reservations-service&lt;/code&gt; (puerto 8082, PostgreSQL): Maneja reservas con &lt;strong&gt;Patrón Factory&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hotel-payments-service&lt;/code&gt; (puerto 8083, MongoDB): Procesa pagos con &lt;strong&gt;CircuitBreaker + Retry&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Un único &lt;code&gt;docker-compose.yml&lt;/code&gt; orquestó todo:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15-alpine&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:6&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27017:27017"&lt;/span&gt;
    &lt;span class="na"&gt;hotel-rooms-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-rooms-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8081:8081"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATASOURCE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://postgres:5432/rooms_db&lt;/span&gt;
    &lt;span class="na"&gt;hotel-reservations-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-reservations-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8082:8082"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATASOURCE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://postgres:5432/reservations_db&lt;/span&gt;
    &lt;span class="na"&gt;hotel-payments-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hotel-payments-service/Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8083:8083"&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SPRING_DATA_MONGODB_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb://mongo:27017/payments_db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Swagger/OpenAPI&lt;/strong&gt;:&lt;br&gt;
Cada servicio expuso una interfaz Swagger (por ejemplo, &lt;code&gt;http://localhost:8083/swagger-ui.html&lt;/code&gt;), facilitando pruebas de APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pruebas&lt;/strong&gt;:&lt;br&gt;
Tests exhaustivos validaron los patrones de resiliencia:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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;testProcessPayment_FallbackTriggered&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reservationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"res1"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;150.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;circuitBreaker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transitionToOpenState&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reservationId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PENDING"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&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;
  
  
  Consejos para Desarrolladores Java en Transición
&lt;/h2&gt;

&lt;p&gt;Para los desarrolladores Java que quieran dar el salto a microservicios, aquí van algunos consejos prácticos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Domina los Patrones de Diseño&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aprende &lt;strong&gt;Circuit Breaker&lt;/strong&gt;, &lt;strong&gt;Retry&lt;/strong&gt; y &lt;strong&gt;Specification&lt;/strong&gt;. No son solo teoría—resuelven problemas reales. Explora la documentación de Resilience4j para ejemplos prácticos.&lt;/li&gt;
&lt;li&gt;Consejo: Ajusta los parámetros de Retry con cuidado para no saturar servicios externos.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adopta la Persistencia Políglota&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elige bases de datos según el dominio. En nuestro sistema, &lt;strong&gt;PostgreSQL&lt;/strong&gt; aseguró integridad para habitaciones, mientras &lt;strong&gt;MongoDB&lt;/strong&gt; manejó datos de pagos de alta escritura.&lt;/li&gt;
&lt;li&gt;Usa abstracciones de Spring Data para simplificar el código de repositorios.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Familiarízate con Docker&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usa builds multi-stage para imágenes ligeras. Las imágenes Alpine como &lt;code&gt;eclipse-temurin:17.0.10_7-jre-alpine&lt;/code&gt; me ahorraron ~200 MB por servicio.&lt;/li&gt;
&lt;li&gt;Verifica siempre los tags en Docker Hub antes de construir.&lt;/li&gt;
&lt;li&gt;Ejemplo: Un &lt;code&gt;.dockerignore&lt;/code&gt; bien configurado:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; target/
 *.jar
 *.log
 .idea/
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prueba sin Descanso&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Escribe tests para patrones de resiliencia. Simula fallos para validar fallbacks.&lt;/li&gt;
&lt;li&gt;Usa herramientas como JaCoCo para medir cobertura y destacar tu trabajo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automatiza desde el Inicio&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configura un pipeline CI/CD (por ejemplo, GitHub Actions) para construir y probar imágenes Docker automáticamente.&lt;/li&gt;
&lt;li&gt;Ejemplo: Un flujo básico para construir imágenes:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker Images&lt;/span&gt;
 &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
 &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
     &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
       &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Aprende de los Errores&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No temas a errores como &lt;code&gt;image not found&lt;/code&gt; o &lt;code&gt;non-resolvable POM&lt;/code&gt;. Son oportunidades para crecer.&lt;/li&gt;
&lt;li&gt;Lleva un registro de depuración para documentar qué funcionó y qué no.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusión: Un Viaje que Vale la Pena
&lt;/h2&gt;

&lt;p&gt;La transición a microservicios con el &lt;strong&gt;Sistema de Reservas de Hotel&lt;/strong&gt; cambió mi perspectiva como desarrollador. Me enseñó a construir sistemas resilientes y escalables usando &lt;strong&gt;3 patrones de resiliencia (Circuit Breaker + Retry) para reservas hoteleras, con persistencia políglota (PostgreSQL + MongoDB)&lt;/strong&gt;. Los retos—definir límites, dominar resiliencia y superar Docker—fueron duros pero gratificantes. Cada error, desde tags de imágenes inexistentes hasta problemas con el POM, afinó mis habilidades y mentalidad.&lt;/p&gt;

&lt;p&gt;A mis colegas desarrolladoras y desarrolladores Java: sumérjanse en los microservicios y los &lt;strong&gt;patrones de diseño&lt;/strong&gt;. Experimenten con &lt;strong&gt;Spring Boot&lt;/strong&gt;, &lt;strong&gt;Resilience4j&lt;/strong&gt; y &lt;strong&gt;Docker&lt;/strong&gt;. El camino puede ser accidentado, pero la capacidad de crear sistemas que prosperen bajo presión vale cada esfuerzo. Empiecen pequeño, prueben rigurosamente y automaticen sin miedo. Su próximo proyecto podría definir su carrera.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔍 ¿Te gustaría ver el código en acción?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Explora &lt;strong&gt;SpringResilientHotel&lt;/strong&gt; en GitHub:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/xsoto-developer/SpringResilientHotel" rel="noopener noreferrer"&gt;github.com/xsoto-developer/SpringResilientHotel&lt;/a&gt;  &lt;/p&gt;




&lt;p&gt;&lt;em&gt;¿Cuál será tu próxima aventura en microservicios? ¡Comparte tus ideas en los comentarios o contáctame en GitHub!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✨ Bonus: Siéntete libre de dejar una ⭐️ o abrir un issue con sugerencias. ¡Aprecio el feedback!&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Este artículo también está disponible en: &lt;a href="https://dev.to/xsoto/from-monolith-to-microservices-418i"&gt;Inglés&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

</description>
      <category>microservices</category>
      <category>resilience4j</category>
      <category>springboot</category>
      <category>docker</category>
    </item>
    <item>
      <title>The Importance of Clean Code</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Sun, 13 Apr 2025 03:21:46 +0000</pubDate>
      <link>https://dev.to/xsoto/the-importance-of-clean-code-2ke1</link>
      <guid>https://dev.to/xsoto/the-importance-of-clean-code-2ke1</guid>
      <description>&lt;h2&gt;
  
  
  An Analysis of CleanTechAPI in Java and .NET
&lt;/h2&gt;

&lt;p&gt;Software development isn’t just about making things work—it’s about doing it right. &lt;strong&gt;Clean Code&lt;/strong&gt; is a philosophy that prioritizes readability, maintainability, and scalability. In one of my projects, &lt;strong&gt;CleanTechAPI&lt;/strong&gt;, I applied these principles to both Java (with Spring Boot) and C# (with .NET 8). Both are REST APIs for managing a catalog of futuristic gadgets, but they’re designed with distinct approaches: one for experienced developers and the other with a more intuitive focus. In this article, we’ll explore why clean code matters, how it’s reflected in the codebase, and the similarities and differences between these two technologies.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is Clean Code Important?
&lt;/h2&gt;

&lt;p&gt;Clean code isn’t a luxury—it’s a necessity. Well-written software reduces errors, eases collaboration, and saves time in the long run. For CleanTechAPI, I relied on principles like &lt;strong&gt;YAGNI&lt;/strong&gt; (You Aren’t Gonna Need It), &lt;strong&gt;KISS&lt;/strong&gt; (Keep It Simple, Stupid), &lt;strong&gt;DRY&lt;/strong&gt; (Don’t Repeat Yourself), and &lt;strong&gt;SOLID&lt;/strong&gt; to ensure the code is:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Readable&lt;/strong&gt;: Understandable at a glance.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainable&lt;/strong&gt;: Easy to modify without breaking everything.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable&lt;/strong&gt;: Ready to grow without becoming chaotic.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These principles not only make my life as a developer easier but are also standards valued by architects and tech leads in real-world projects.  &lt;/p&gt;

&lt;h2&gt;
  
  
  CleanTechAPI: Two Approaches, One Goal
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaCleanTechAPI (Spring Boot)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Demonstrate a professional-grade REST API with Spring Boot, targeting advanced developers and architects.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Uses Clean Architecture, Maven, an in-memory H2 database, and Swagger for documentation. Includes an engaging endpoint (&lt;code&gt;/products/trending&lt;/code&gt;) featuring futuristic gadgets like the "Quantum X Drone."
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AspCleanTechAPI (.NET 8)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Teach developers how to build a REST API with a more intuitive approach using C# and .NET 8, leveraging its integrated tooling and simplicity.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Implements Entity Framework Core (InMemory), Visual Studio as the IDE, and Newtonsoft.Json for streamlined serialization. Retains the same engaging endpoint but adapts it for accessibility.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both projects share a common core: applying clean code to solve a practical, interesting use case.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How Is Clean Code Reflected in These Projects?
&lt;/h2&gt;

&lt;p&gt;Clean code isn’t just theory—it’s visible in concrete decisions. Here are some examples:  &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Separation of Concerns (SOLID - SRP)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@RestController&lt;/span&gt;
  &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&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;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

      &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&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;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAll&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;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllProducts&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;ul&gt;
&lt;li&gt;
&lt;p&gt;The controller only handles HTTP requests, delegating logic to the service layer.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAllProducts&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Similar to Java, the controller is lightweight, with logic residing in &lt;code&gt;ProductService&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Descriptive, Self-Documenting Names (KISS)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Both use names like &lt;code&gt;Product&lt;/code&gt;, &lt;code&gt;ProductService&lt;/code&gt;, and &lt;code&gt;getAllProducts&lt;/code&gt;, which explain their purpose without redundant comments.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Avoiding Duplication (DRY)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;: Data access logic is centralized in &lt;code&gt;ProductRepository&lt;/code&gt; using Spring Data JPA.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;: &lt;code&gt;ProductService&lt;/code&gt; reuses EF Core’s context for all operations.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Simplicity (YAGNI)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Neither project includes unnecessary features like authentication, keeping the focus on the product catalog.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Similarities Between Java and .NET in CleanTechAPI
&lt;/h2&gt;

&lt;p&gt;Despite different languages and frameworks, both projects share:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structure&lt;/strong&gt;: Follow Clean Architecture with clear layers (models/domain, services/application, controllers/infrastructure).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Injection&lt;/strong&gt;: Decouples components seamlessly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt;: Use in-memory databases (H2 and EF Core InMemory) for simplicity.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Integrate Swagger for exploring endpoints like &lt;code&gt;/products&lt;/code&gt; and &lt;code&gt;/products/trending&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engaging Purpose&lt;/strong&gt;: Both feature a futuristic use case to capture attention.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Differences Between Java and .NET
&lt;/h2&gt;

&lt;p&gt;While the goal is the same, the implementations reflect each technology’s philosophy:  &lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Injection
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Boot (Java)&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;strong&gt;&lt;code&gt;@Autowired&lt;/code&gt;&lt;/strong&gt; for automatic dependency injection via Spring’s IoC container.
&lt;/li&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;More "magic" and flexible but requires understanding annotations.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core (C#)&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly registers services with &lt;strong&gt;&lt;code&gt;IServiceCollection&lt;/code&gt;&lt;/strong&gt; in &lt;code&gt;Program.cs&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;And in the controller:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;More transparent and direct, leveraging .NET’s native integration.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other Differences
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audience&lt;/strong&gt;: Java targets professionals; .NET offers a more intuitive approach.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Maven vs. .NET CLI; IntelliJ IDEA vs. Visual Studio.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialization&lt;/strong&gt;: Jackson (Java) is automatic; .NET requires tweaks (e.g., Newtonsoft.Json).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: Java is more verbose/configurable; .NET is more integrated/accessible.
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Clean code is the heart of CleanTechAPI, whether in Java or .NET. Both projects prove that principles like SOLID and DRY aren’t language-dependent—they’re about how we structure solutions. Java offers power and flexibility for complex projects, while .NET shines with its intuitive, streamlined approach. Ultimately, the goal is to write code that not only works but also inspires and is easy to maintain.  &lt;/p&gt;

&lt;p&gt;Want to see how it’s done? Check out the projects on GitHub:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaCleanTechAPI&lt;/strong&gt;: &lt;a href="https://github.com/xsoto-developer/spring-clean-tech-api" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/spring-clean-tech-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AspCleanTechAPI&lt;/strong&gt;: &lt;a href="https://github.com/xsoto-developer/asp-clean-tech-api" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/asp-clean-tech-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Explore, learn, and share your thoughts!  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This article is also available in: &lt;a href="https://dev.to/xsoto/la-importancia-del-codigo-limpio-un-analisis-de-cleantechapi-en-java-y-net-3ed3"&gt;Spanish&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>java</category>
      <category>springboot</category>
      <category>csharp</category>
    </item>
    <item>
      <title>La importancia del código limpio</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Wed, 09 Apr 2025 20:27:27 +0000</pubDate>
      <link>https://dev.to/xsoto/la-importancia-del-codigo-limpio-un-analisis-de-cleantechapi-en-java-y-net-3ed3</link>
      <guid>https://dev.to/xsoto/la-importancia-del-codigo-limpio-un-analisis-de-cleantechapi-en-java-y-net-3ed3</guid>
      <description>&lt;h2&gt;
  
  
  Un análisis de CleanTechAPI en Java y .NET
&lt;/h2&gt;

&lt;p&gt;El desarrollo de software no solo se trata de hacer que las cosas funcionen, sino de hacerlo bien. El &lt;strong&gt;código limpio&lt;/strong&gt; (Clean Code) es una filosofía que prioriza la legibilidad, mantenibilidad y escalabilidad del código, y en uno de mis proyectos, &lt;strong&gt;CleanTechAPI&lt;/strong&gt;, he aplicado estos principios tanto en Java con Spring Boot como en C# con .NET 8. Ambos son APIs REST para gestionar un catálogo de gadgets futuristas, pero están diseñados con enfoques distintos: uno para desarrolladores experimentados y otro con un enfoque más intuitivo. En este artículo, exploraremos por qué el código limpio importa, cómo se refleja en el código y las similitudes y diferencias entre estas dos tecnologías.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué el código limpio es importante?
&lt;/h2&gt;

&lt;p&gt;El código limpio no es un lujo, es una necesidad. Un software bien escrito reduce errores, facilita la colaboración y ahorra tiempo a largo plazo. En CleanTechAPI, me basé en principios como &lt;strong&gt;YAGNI&lt;/strong&gt; (You Aren’t Gonna Need It), &lt;strong&gt;KISS&lt;/strong&gt; (Keep It Simple, Stupid), &lt;strong&gt;DRY&lt;/strong&gt; (Don’t Repeat Yourself) y &lt;strong&gt;SOLID&lt;/strong&gt; para asegurar que el código sea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Legible&lt;/strong&gt;: Cualquiera puede entenderlo con un vistazo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mantenible&lt;/strong&gt;: Fácil de modificar sin romper todo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalable&lt;/strong&gt;: Preparado para crecer sin volverse un caos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos principios no solo hacen mi vida más fácil como desarrollador, sino que también son un estándar que los arquitectos y líderes técnicos valoran en proyectos reales.&lt;/p&gt;

&lt;h2&gt;
  
  
  CleanTechAPI: Dos enfoques, un mismo objetivo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaCleanTechAPI (Spring Boot)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Finalidad&lt;/strong&gt;: Mostrar un ejemplo profesional de una API REST con Spring Boot, dirigido a desarrolladores avanzados y arquitectos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Características&lt;/strong&gt;: Usa Clean Architecture, Maven, base de datos H2 en memoria y Swagger para documentación. Incluye un endpoint atractivo (&lt;code&gt;/products/trending&lt;/code&gt;) con gadgets futuristas como "Drone Quantum X".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AspCleanTechAPI (.NET 8)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Finalidad&lt;/strong&gt;: Enseñar a desarrolladores cómo construir una API REST con un enfoque más intuitivo en C# usando .NET 8, aprovechando su integración y simplicidad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Características&lt;/strong&gt;: Implementa Entity Framework Core con InMemory, Visual Studio como IDE y Newtonsoft.Json para facilitar la serialización. Mantiene el mismo endpoint atractivo adaptado a una experiencia accesible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ambos proyectos comparten un núcleo común: aplicar código limpio para resolver un caso de uso interesante y práctico.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Dónde se ve el código limpio en estos proyectos?
&lt;/h2&gt;

&lt;p&gt;El código limpio no es solo teoría; se refleja en decisiones concretas dentro del código. Aquí algunos ejemplos:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Separación de responsabilidades (Principio SOLID - SRP)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@RestController&lt;/span&gt;
  &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&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;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

      &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&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;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAll&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;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllProducts&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;ul&gt;
&lt;li&gt;
&lt;p&gt;El controlador solo maneja solicitudes HTTP, delegando la lógica al servicio.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAllProducts&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Similar al Java, el controlador es ligero y la lógica vive en &lt;code&gt;ProductService&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Nombres descriptivos y auto-documentados (KISS)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ambos usan nombres como &lt;code&gt;Product&lt;/code&gt;, &lt;code&gt;ProductService&lt;/code&gt; y &lt;code&gt;getAllProducts&lt;/code&gt;, que explican su propósito sin comentarios redundantes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Evitar duplicación (DRY)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;: La lógica de acceso a datos está centralizada en &lt;code&gt;ProductRepository&lt;/code&gt; con Spring Data JPA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;: &lt;code&gt;ProductService&lt;/code&gt; reutiliza el contexto de EF Core para todas las operaciones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Simplicidad (YAGNI)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ningún proyecto incluye autenticación o funcionalidades complejas innecesarias, manteniendo el foco en el catálogo de productos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Similitudes entre Java y .NET en CleanTechAPI
&lt;/h2&gt;

&lt;p&gt;A pesar de usar lenguajes y frameworks distintos, ambos proyectos comparten:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Estructura&lt;/strong&gt;: Siguen Clean Architecture con capas claras (modelos/dominio, servicios/aplicación, controladores/infraestructura).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inyección de dependencias&lt;/strong&gt;: Facilitan el desacoplamiento entre componentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistencia&lt;/strong&gt;: Usan bases de datos en memoria para simplicidad (H2 y EF Core InMemory).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación&lt;/strong&gt;: Integran Swagger para explorar endpoints como &lt;code&gt;/products&lt;/code&gt; y &lt;code&gt;/products/trending&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Propósito atractivo&lt;/strong&gt;: Ambos destacan con un caso de uso futurista que capta la atención.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Diferencias clave entre Java y .NET
&lt;/h2&gt;

&lt;p&gt;Aunque el objetivo es el mismo, las implementaciones reflejan las filosofías de cada tecnología:&lt;/p&gt;

&lt;h3&gt;
  
  
  Inyección de dependencias
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Boot (Java)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;@Autowired&lt;/code&gt;&lt;/strong&gt; para inyectar dependencias automáticamente mediante el contenedor IoC de Spring.&lt;/li&gt;
&lt;li&gt;Ejemplo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;Es más "mágico" y flexible, pero requiere entender las anotaciones.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Core (C#)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Registra servicios explícitamente con &lt;strong&gt;&lt;code&gt;IServiceCollection&lt;/code&gt;&lt;/strong&gt; en &lt;code&gt;Program.cs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ejemplo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Y en el controlador:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;Más transparente y directo, aprovechando la integración nativa de .NET.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Otras diferencias
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audiencia&lt;/strong&gt;: Java apunta a profesionales; .NET ofrece un enfoque más intuitivo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Herramientas&lt;/strong&gt;: Maven vs. .NET CLI; IntelliJ IDEA vs. Visual Studio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialización&lt;/strong&gt;: Jackson (Java) es automático; .NET requiere ajustes (como usar Newtonsoft.Json).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complejidad&lt;/strong&gt;: Java es más verboso y configurable; .NET es más integrado y accesible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El código limpio es el corazón de CleanTechAPI, ya sea en Java o .NET. Ambos proyectos demuestran que principios como SOLID y DRY no dependen del lenguaje, sino de cómo estructuramos nuestras soluciones. Java ofrece potencia y flexibilidad para proyectos complejos, mientras que .NET destaca por su enfoque intuitivo y su integración simplificada. Al final, lo importante es escribir código que no solo funcione, sino que inspire y sea fácil de mantener.&lt;/p&gt;

&lt;p&gt;¿Quieres ver cómo lo hice? Revisa los proyectos en GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaCleanTechAPI&lt;/strong&gt;: &lt;a href="https://github.com/xsoto-developer/spring-clean-tech-api" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/spring-clean-tech-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AspCleanTechAPI&lt;/strong&gt;: &lt;a href="https://github.com/xsoto-developer/asp-clean-tech-api" rel="noopener noreferrer"&gt;https://github.com/xsoto-developer/asp-clean-tech-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¡Explora, aprende y comparte tus pensamientos!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Este artículo también está disponible en: &lt;a href="https://dev.to/xsoto/the-importance-of-clean-code-2ke1"&gt;Inglés&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>java</category>
      <category>springboot</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Mi Viaje de Desarrollador Java a Ingeniero DevOps</title>
      <dc:creator>Ximena Soto</dc:creator>
      <pubDate>Mon, 07 Apr 2025 02:37:25 +0000</pubDate>
      <link>https://dev.to/xsoto/mi-viaje-de-desarrollador-java-a-ingeniero-devops-desafios-y-aprendizajes-clave-188c</link>
      <guid>https://dev.to/xsoto/mi-viaje-de-desarrollador-java-a-ingeniero-devops-desafios-y-aprendizajes-clave-188c</guid>
      <description>&lt;h1&gt;
  
  
  Desafíos y Aprendizajes Clave 🚀
&lt;/h1&gt;

&lt;p&gt;Después de años trabajando como desarrollador backend con Java y Spring Boot, decidí dar un paso adelante hacia el mundo de DevOps. En este artículo comparto los retos, errores, aprendizajes y herramientas que marcaron mi transición hacia esta nueva etapa profesional.&lt;/p&gt;

&lt;p&gt;🛠️ Desde conceptos básicos de CI/CD, Docker y Kubernetes hasta la integración con Jenkins, Helm y ArgoCD — todo contado desde mi experiencia real.&lt;/p&gt;

&lt;p&gt;📄 Puedes leer el artículo completo aquí 👉 &lt;a href="https://docs.google.com/document/d/1qRtaYXN6yNXNIxrx6yZiDY7PQQevU1L3duz0Fa4dvSM/edit?usp=sharing" rel="noopener noreferrer"&gt;Mi Viaje de Desarrollador Java a Ingeniero DevOps&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;👨‍💻 Si estás considerando dar el salto a DevOps, espero que este artículo te inspire y te ahorre algunos tropiezos.&lt;/p&gt;

&lt;p&gt;¡Gracias por leer! Me encantaría saber qué opinas en los comentarios 🙌&lt;/p&gt;

</description>
      <category>devops</category>
      <category>java</category>
      <category>cloud</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
