
Domina la Arquitectura Hexagonal y DDD: GuĂa Práctica para Diseñar Microservicios Escalables
En el mundo moderno del desarrollo de software, la arquitectura de microservicios se ha convertido en un estándar debido a sus ventajas en escalabilidad y mantenimiento. Un microservicio es una unidad pequeña y autĂłnoma de funcionalidad que interactĂşa con otros servicios a travĂ©s de APIs bien definidas. En esta guĂa, vamos a explorar la configuraciĂłn de un microservicio con mĂşltiples integraciones. Este ejemplo incluye servicios esenciales como Apache Kafka, MongoDB, ActiveMQ Artemis y HTTP
Además, este microservicio sigue el patrón de arquitectura hexagonal con el enfoque de diseño dirigido por dominio (DDD). Esto significa que la lógica de negocio se encuentra en el centro del diseño, y las dependencias externas están en los bordes, permitiendo una mejor modularización y prueba unitaria de la lógica de negocio.
IntroducciĂłn a la Arquitectura Hexagonal
La arquitectura hexagonal, también conocida como arquitectura de puertos y adaptadores, fue introducida por Alistair Cockburn con el objetivo de crear un diseño de software que sea más fácil de mantener y extender. Esta arquitectura busca separar la lógica de negocio del sistema de las dependencias externas, como bases de datos, interfaces de usuario y otros servicios.
src/main/java/com/kranio/
 ├── application
 │  ├── mappers
 │  │  └── UserMapper.java
 │  ├── services
 │  │  └── UserService.java
 ├── domain
 │  ├── classes
 │  │  └── User.java
 │  ├── repositories
 │  │  └── IUserRepository.java
 ├── infrastructure
 │  ├── amq/repositories
 │  │  └── AMQProducerRepository.java
 │  ├── mongodb/repositories
 │  │  └── MongoRepository.java
 ├── presenters
 │  ├── http
 │  │  └── UserController.java
 │  ├── kafka
 │  │  └── KafkaConsumer.java
ExplicaciĂłn de los Componentes
1. Application
• mappers
• UserMapper.java: Clase para mapear datos entre diferentes capas de la aplicación.
package com.kranio.application.mappers;
import jakarta.enterprise.context.ApplicationScoped;
import com.kranio.domain.classes.User;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import java.io.StringReader;
@ApplicationScoped
public class UserMapper {
 public User convertStringToUser(String xml) throws JAXBException {
  JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
  Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
  StringReader reader = new StringReader(xml);
  return (User) unmarshaller.unmarshal(reader);
 }
}
• services
• UserService.java: Implementación de la lógica de negocio del servicio de usuario.
package com.kranio.application.services;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import com.kranio.domain.repositories.IUserRepository;
import com.kranio.application.mappers.UserMapper;
import com.kranio.domain.classes.User;
@ApplicationScoped
public class UserService {
 @Inject
 private IUserRepository userRepository;
 @Inject
 private UserMapper userMapper;
 public void saveAndSendMessage(String message) {
  try {
   User user = userMapper.convertStringToUser(message);
   String response = userRepository.save(user);
   userRepository.sendMessage(response);
  } catch (Exception e) {
   System.err.println("Error saving User: " + e.getMessage());
  }
 }
 public void saveAndSendMessage(User user) {
  try {
   String response = userRepository.save(user);
   userRepository.sendMessage(response);
  } catch (Exception e) {
   System.err.println("Error saving User: " + e.getMessage());
  }
 }
}
Â
2. Domain
• classes
• User.java: Clase que representa el modelo de usuario.
package com.kranio.domain.classes;
import io.quarkus.mongodb.panache.PanacheMongoEntity;
import io.quarkus.mongodb.panache.PanacheMongoEntityBase;
import lombok.Data;
public class User extends PanacheMongoEntity {
  public String name;
  public String email;
}
• repositories
• IUserRepository.java: Interfaz que define las operaciones de persistencia de usuario.
package com.kranio.domain.repositories;
import com.kranio.domain.classes.User;
public interface IUserRepository {
 public void sendMessage(String message);
 public String save(User user);
}
Â
3. Infrastructure
• amq/repositories
• AMQProducerRepository.java: Implementación del puerto de salida para interactuar con ActiveMQ.
package com.kranio.infrastructure.amq.repositories;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSRuntimeException;
import jakarta.jms.Session;
import com.kranio.domain.classes.User;
import com.kranio.domain.repositories.IUserRepository;
import com.kranio.infrastructure.mongodb.repositories.MongoRepository;
@ApplicationScoped
public class AMQProducerRepository implements IUserRepository {
 @Inject
 private ConnectionFactory connectionFactory;
 @Inject
 private MongoRepository mongoRepository;
 public void sendMessage(String message) {
  try (JMSContext context = connectionFactory.createContext(Session.AUTO_ACKNOWLEDGE)) {
   context.createProducer().send(context.createQueue("TestQueue"), message);
   System.out.println("Message sent: " + message);
  } catch (JMSRuntimeException ex) {
   System.err.println("Error sending message: " + ex.getMessage());
  }
 }
 public String save(User user) {
  mongoRepository.persist(user);
  return "User saved";
 }
}
• mongodb/repositories
• MongoRepository.java: Implementación del puerto de salida para interactuar con MongoDB.
package com.kranio.infrastructure.mongodb.repositories;
import io.quarkus.mongodb.panache.PanacheMongoRepository;
import jakarta.enterprise.context.ApplicationScoped;
import com.kranio.domain.classes.User;
@ApplicationScoped
public class MongoRepository implements PanacheMongoRepository *User* {
}
4. Presenters
• http
• UserController.java: Controlador que maneja las solicitudes HTTP y las convierte en llamadas a la lógica de negocio a través del servicio de usuario.
package com.kranio.presenters.http;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import com.kranio.application.services.UserService;
import com.kranio.domain.classes.User;
@Path("/user")
public class UserController {
 @Inject
 private UserService userService;
 @POST
 public Response create(User newUser) {
  userService.saveAndSendMessage(newUser);
  return Response.status(Response.Status.CREATED).entity(newUser).build();
 }
}
• kafka
• KafkaConsumer.java: Consumidor de mensajes de Kafka que interactúa con la lógica de negocio.
package com.kranio.presenters.kafka;
import org.eclipse.microprofile.reactive.messaging.Incoming;
import io.vertx.mutiny.ext.auth.User;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import com.kranio.application.services.UserService;
@Singleton
public class KafkaConsumer {
 @Inject
 private UserService userService;
 @Incoming("consumer")
 public void consume(String message) {
  System.out.println("Consumiendo mensaje: " + message);
  userService.saveAndSendMessage(message);
 }
}
Esta estructura de proyecto basada en la arquitectura hexagonal permite una clara separaciĂłn de responsabilidades, donde el nĂşcleo de la aplicaciĂłn (dominio) permanece independiente de las tecnologĂas y frameworks utilizados en los adaptadores. Esto facilita el mantenimiento, la escalabilidad y las pruebas unitarias, asegurando que la lĂłgica de negocio se mantenga limpia y fácilmente adaptable a futuros cambios.
‍
Beneficios y Debilidades de la Arquitectura Hexagonal
Beneficios
1. Separación de Concerns: Facilita el mantenimiento al separar la lógica de negocio de las dependencias técnicas.
2. Flexibilidad y Extensibilidad: Permite agregar nuevas funcionalidades o cambiar tecnologĂas sin afectar la lĂłgica central.
3. Pruebas Unitarias: Facilita la creaciĂłn de pruebas unitarias al permitir el uso de mocks o stubs para las dependencias externas.
4. Independencia TecnolĂłgica: Hace más sencillo cambiar de tecnologĂas (bases de datos, sistemas de mensajerĂa, etc.) sin modificar la lĂłgica de negocio.
Debilidades
1. Complejidad Inicial: Requiere una mayor planificaciĂłn y definiciĂłn de puertos y adaptadores desde el inicio.
2. Sobrecarga de Abstracción: Puede introducir una sobrecarga innecesaria de abstracción en proyectos pequeños.
3. Curva de Aprendizaje: Puede ser más difĂcil de entender y aplicar correctamente para desarrolladores sin experiencia en esta arquitectura.
4. Rendimiento: La capa adicional de abstracciĂłn puede introducir una ligera disminuciĂłn en el rendimiento, aunque generalmente es insignificante comparado con los beneficios.
‍
Diseño Dirigido por el Dominio (DDD)
El Diseño Dirigido por el Dominio (DDD, por sus siglas en inglés) es un enfoque de desarrollo de software que pone un fuerte énfasis en el modelado del dominio de negocio central del software. Introducido por Eric Evans en su libro “Domain-Driven Design: Tackling Complexity in the Heart of Software”, DDD ofrece un conjunto de principios y patrones para crear sistemas de software que reflejan profundamente el dominio de negocio y las necesidades de los usuarios.
Conceptos Clave de DDD
1. Entidades: Objetos que tienen una identidad distintiva que atraviesa el tiempo y diferentes estados. Por ejemplo, un usuario con un ID Ăşnico.
2. Objetos de Valor: Objetos que se definen completamente por sus atributos. No tienen identidad propia. Por ejemplo, una direcciĂłn.
3. Agregados: Un grupo de entidades y objetos de valor que se tratan como una unidad. Tienen una entidad raĂz que controla el acceso.
4. Repositorios: Facilitan el acceso a los agregados. ActĂşan como una colecciĂłn en memoria de los agregados.
5. Servicios de Dominio: Operaciones que no pertenecen a ninguna entidad o objeto de valor en particular pero son parte del dominio.
6. MĂłdulos: Agrupan conceptos relacionados para organizar el cĂłdigo.
7. Fábricas: Encargadas de la creación de objetos complejos o agregados.
Beneficios de DDD
1. Modelo de Negocio Claro: DDD ayuda a crear un modelo de negocio claro y compartido entre los desarrolladores y los expertos en el dominio.
2. Código Más Comprensible: El código se vuelve más comprensible porque refleja directamente los términos y procesos del dominio del negocio.
3. ReducciĂłn de Complejidad: Al centrarse en el nĂşcleo del dominio y sus reglas, DDD ayuda a gestionar la complejidad inherente a los sistemas de software.
4. Mejora de la ComunicaciĂłn: Mejora la comunicaciĂłn entre desarrolladores y expertos en el dominio mediante un lenguaje ubicuo (Ubiquitous Language) comĂşn.
5. Flexibilidad y Mantenibilidad: La separaciĂłn clara de responsabilidades y la modularizaciĂłn facilitan la extensiĂłn y el mantenimiento del sistema.
‍
Debilidades de DDD
1. Curva de Aprendizaje Pronunciada: Requiere una buena comprensiĂłn de los conceptos de DDD y puede ser difĂcil de adoptar para los equipos sin experiencia.
2. Sobrecarga Inicial: El proceso de modelado puede ser intensivo y llevar más tiempo en las primeras fases del desarrollo.
3. Complejidad en Proyectos Pequeños: Puede introducir una complejidad innecesaria en proyectos pequeños o simples.
4. Necesidad de ColaboraciĂłn Constante: Requiere una colaboraciĂłn continua entre desarrolladores y expertos en el dominio, lo cual puede ser un desafĂo en algunos contextos.
5. Dificultad en la ImplementaciĂłn: La correcta identificaciĂłn de los lĂmites del contexto y la divisiĂłn del dominio puede ser desafiante y puede requerir varias iteraciones.
‍
Y asi se ve el microservicio que estará adjunto para que le des una mirada, lo clones y juegues un poco. lee el README.md para ver como se ejecuta y todas las consideraciones a tener en cuenta.
https://github.com/eljoesb/ddd-kranio-blog
ÂżListo para transformar la arquitectura de tus aplicaciones con enfoques modernos y eficientes?
En Kranio, contamos con un equipo de expertos en Arquitectura Hexagonal y Diseño Dirigido por el Dominio (DDD) que te ayudarán a implementar soluciones de microservicios escalables y mantenibles. Contáctanos y descubre cómo podemos impulsar la evolución tecnológica de tu empresa.
Entradas anteriores

Kranear también es proteger: el proceso detrás de nuestra certificación ISO 27001
A finales de 2025, Kranio obtuvo la certificaciĂłn ISO 27001 tras implementar su Sistema de GestiĂłn de Seguridad de la InformaciĂłn (SGSI). Este proceso no fue solo un ejercicio de cumplimiento, sino una decisiĂłn estratĂ©gica para fortalecer cĂłmo diseñamos, construimos y operamos sistemas digitales. En este artĂculo compartimos el proceso, los cambios internos que implicĂł y el impacto que tiene para nuestros clientes: mayor control, gestiĂłn estructurada de riesgos y una base más sĂłlida para escalar sistemas con confianza.

Estándares de desarrollo: el sistema operativo invisible que permite escalar sin quemar al equipo
Descubre cĂłmo los estándares de desarrollo reducen bugs, aceleran el onboarding y permiten escalar equipos de ingenierĂa sin generar fricciĂłn.
