UNIVERSIDAD ESTATAL DE BOLÍVAR FACULTAD DE CIENCIAS ADMINISTRATIVAS, GESTIÓN EMPRESARIAL E INFORMÁTICA CARRERA DE SOFTWARE TRABAJO DE INTEGRACIÓN CURRICULAR PREVIO A LA OBTENCIÓN DEL TÍTULO DE INGENIEROS EN SOFTWARE FORMA: PROYECTO TECNOLÓGICO TEMA: DESARROLLO DE UN SISTEMA INFORMÁTICO PARA LA GESTIÓN Y VENTA DE BOLETOS EN LA COOPERATIVA DE TRANSPORTES “SAN PEDRITO” APLICANDO DOMAIN DRIVEN DESIGN (DDD) AUTORES: MESIAS EDUARDO BONILLA GUASTAY MELANIN VANESSA GANAN ILVAY DIRECTOR: ING. DANILO BARRENO GUARANDA – ECUADOR 2024 TEMA DEL PROYECTO DESARROLLO DE UN SISTEMA INFORMÁTICO PARA LA GESTIÓN Y VENTA DE BOLETOS EN LA COOPERATIVA DE TRANSPORTES “SAN PEDRITO” APLICANDO DOMAIN DRIVEN DESIGN (DDD) ii DEDICATORIA Este trabajo está dedicado a: A mi madre, cuyo amor y apoyo incondicional han sido mi luz en los momentos más oscuros. A mi familia y seres queridos, cuya presencia y aliento han sido el sostén en cada paso de este camino, incluso aquellos que ya no están físicamente con nosotros, pero cuyo legado y recuerdo siguen vivos en nuestros corazones. Este proyecto es el fruto de su influencia y dedicación, y lo dedico con gratitud y cariño a todos ustedes, quienes han sido mi inspiración constante y mi fuerza inquebrantable, incluso más allá de esta vida terrenal. Sin su apoyo, nada de esto habría sido posible. Gracias por ser parte de mi historia, incluso desde el otro lado. Eduardo Guastay Este trabajo está dedicado con amor y gratitud a dos pilares fundamentales en mi vida: mi familia y mi novio. A mis Padres Rogelio Ganan y Ana Ilvay, hermanos y abuelos, cuyo amor incondicional y apoyo constante han sido mi mayor fortaleza en este viaje académico. Gracias por estar siempre ahí, por alentarme, cuidarme, aconsejarme y guiarme para perseguir mis sueños y por ser mi refugio en los momentos difíciles. Su amor y apoyo han sido la luz que ha iluminado mi camino. Y a ti, mi amado Jefferson Criollo, quiero agradecerte por ser mi compañero de vida y mi mayor confidente. Tu amor, tu paciencia y tu constante aliento han sido mi inspiración para superar los desafíos y alcanzar mis metas. Gracias por compartir este viaje conmigo y por ser mi mayor motivación para dar lo mejor de mí en cada paso del camino. A ti ,mi precioso Hernan Ganan has sido mi mayor fuente de alegría, inspiración y orgullo. A través de cada desafío y cada logro, has sido mi compañero de aventuras, mi motivación para superarme y mi razón para seguir adelante. Esta tesis es un tributo a su amor incondicional. Les dedico este logro con todo mi corazón, su apoyo inquebrantable y su presencia constante en mi vida. Sin ustedes, este logro no habría sido posible, los amo. Melanin Ganan iii AGRADECIMIENTO Agradezco a Dios por la fortaleza y la sabiduría que me ha brindado para alcanzar este logro. También quiero expresar mi sincero agradecimiento a la Cooperativa de Transportes 'San Pedrito' por brindarme la oportunidad de trabajar en este proyecto. Además, quiero extender mi más sincero agradecimiento al Ing. Danilo Barren, mi director de tesis, por su guía experta, paciencia y compromiso durante todo el proceso. Agradezco también a mis pares, Ing. Galuth García e Ing. Henry Albán, por su valioso aporte, críticas constructivas y apoyo en el desarrollo de este proyecto. Asimismo, quiero agradecer al equipo de CODELY por su inspirador contenido relacionado con la programación y el desarrollo de software, el cual me ha brindado conocimientos adicionales y motivación en mi camino académico y profesional. Mi gratitud se extiende a la Universidad Estatal de Bolívar en general, por proporcionarme las herramientas y el entorno propicio para mi formación académica. Este logro es el resultado del esfuerzo conjunto de todas estas personas y entidades, a quienes dedico mi más profundo agradecimiento. Eduardo Guastay https://codely.com/ iv En este momento de gratitud, elevo mi corazón lleno de agradecimiento a Dios, quien ha sido mi luz y mi roca en cada paso de este viaje académico. A la distinguida Universidad Estatal de Bolívar, le agradezco profundamente por abrirme las puertas del conocimiento. Quiero expresar mi más sincero reconocimiento al Ing. Danilo Barreno, mi director de tesis, cuya presencia fue una guía luminosa en cada etapa de este proyecto. Su liderazgo visionario, apoyo incondicional y dedicación incansable fueron fundamentales para mi crecimiento académico y profesional durante todo este proceso. A mis pares, Ing. Galuth García e Ing. Henry Albán, les doy gracias desde lo más profundo de mi ser. Su sabiduría, paciencia y apoyo incondicional han sido el timón que ha guiado este barco de conocimiento. Finalmente, a mi familia y amigos, les debo todo. Su amor incondicional, aliento constante y comprensión infinita han sido mi mayor tesoro en los momentos de desafío y éxito. Sin ustedes a mi lado, este camino habría sido menos brillante y significativo. Melanin Ganan DERECHOS DE AUTOR Nosotros BONILLA GUASTAY MESÍAS EDUARDO y GANAN ILVAY MELANIN VANESSA portadores de la Cédula de Identidad No 0250366515 y 0605584358 en calidad de autores y titulares de los derechos morales y patrimoniales del Trabajo de Titulación: DESARROLLO DE UN SISTEMA INFORMÁTICO PARA LA GESTIÓN Y VENTA DE BOLETOS EN LA COOPERATIVA DE TRANSPORTES “SAN PEDRITO” APLICANDO DOMAIN DRIVEN DESIGN (DDD), modalidad TRABAJO TECNOLÓGICO, de conformidad con el Art. 114 del CÓDIGO ORGÁNICO DE LA ECONOMÍA SOCIAL DE LOS CONOCIMIENTOS, CREATIVIDAD E INNOVACIÓN, concedemos a favor de la Universidad Estatal de Bolívar, una licencia gratuita, intransferible y no exclusiva para el uso no comercial de la obra, con fines estrictamente académicos. Conservamos a nuestro favor todos los derechos de autor sobre la obra, establecidos en la normativa citada. Así mismo, autorizamos a la Universidad Estatal de Bolívar, para que realice la digitalización y publicación de este trabajo de titulación en el Repositorio Digital, de conformidad a lo dispuesto en el Art. 144 de la Ley Orgánica de Educación Superior. Los autores declaran que la obra objeto de la presente autorización es original en su forma de expresión y no infringe el derecho de autor de terceros, asumiendo la responsabilidad por cualquier reclamación que pudiera presentarse por esta causa y liberando a la Universidad de toda responsabilidad. _____________________ _____________________ Eduardo Guastay Melanin Ganan cc: 0250366515 cc: 0605584358 vii ÍNDICE DE CONTENIDOS TEMA DEL PROYECTO .............................................................................................................. I DEDICATORIA ............................................................................................................................. II AGRADECIMIENTO ................................................................................................................. III CERTIFICADO DE VALIDACIÓN ............................................................................................ V DERECHOS DE AUTOR ........................................................................................................... VI ÍNDICE DE CONTENIDOS ...................................................................................................... VII INDICE DE TABLAS .................................................................................................................. XI INDICE DE FIGURAS ............................................................................................................... XII INTRODUCCIÓN ........................................................................................................................... 1 RESUMEN ....................................................................................................................................... 3 ABSTRACT ..................................................................................................................................... 4 CAPÍTULO I ................................................................................................................................... 5 FORMULACIÓN GENERAL DEL PROYECTO ...................................................................... 5 1.1 TEMA.................................................................................................................................. 5 1.2 DESCRIPCIÓN DEL PROBLEMA ................................................................................. 5 1.3 JUSTIFICACIÓN .............................................................................................................. 6 1.4 OBJETIVOS ....................................................................................................................... 7 1.4.1 GENERAL .......................................................................................................................... 7 1.4.2 ESPECÍFICOS ................................................................................................................... 7 CAPÍTULO II ................................................................................................................................. 8 MARCO TEÓRICO ....................................................................................................................... 8 2.1 ANTECEDENTES ............................................................................................................. 8 2.2 CIENTÍFICO ................................................................................................................... 10 2.2.1 DOMAIN-DRIVEN DESIGN (DDD) ............................................................................. 10 2.2.2 ENTITIES (ENTIDADES) .............................................................................................. 10 2.2.3 VALUE OBJECTS (OBJETOS DE VALOR) ............................................................... 11 2.2.4 SERVICES (SERVICIOS) .............................................................................................. 11 2.2.5 AGGREGATES (AGREGADOS) .................................................................................. 11 viii 2.2.6 REPOSITORIES (REPOSITORIOS) ............................................................................ 13 2.2.7 FACTORIAS .................................................................................................................... 14 2.2.8 ARQUITECTURA EN CAPAS ...................................................................................... 14 2.2.9 CAPA DE DOMINIO ...................................................................................................... 15 2.2.10 CAPA DE APLICACIÓN ........................................................................................... 15 2.2.11 CAPA DE INFRAESTRUCTURA ............................................................................. 15 2.2.12 ARQUITECTURA HEXAGONAL ........................................................................... 16 2.2.13 BOUNDED CONTEXT (CONTEXTO DELIMITADO) ......................................... 17 2.2.14 COMMAND-QUERY RESPONSIBILITY SEGREGATION (CQRS) ................. 17 2.2.15 EVENT-DRIVEN ARCHITECTURE (ARQUITECTURA ORIENTADA A EVENTOS) .................................................................................................................................... 18 2.2.16 EVENTOS DE DOMINIO .......................................................................................... 19 2.2.17 CONFIG SERVICE..................................................................................................... 20 2.2.18 MICROSERVICIOS ................................................................................................... 20 2.3 CONCEPTUAL ................................................................................................................ 21 2.3.1 ARQUITECTURA DE SOFTWARE ............................................................................. 21 2.3.2 HIBERNATE .................................................................................................................... 21 2.3.3 PATRÓN CRITERIA ...................................................................................................... 21 2.3.4 PRINCIPIO DE RESPONSABILIDAD ÚNICA ........................................................... 21 2.3.5 PRINCIPIO DE ABIERTO/CERRADO ....................................................................... 21 2.3.6 PRINCIPIO DE SUSTITUCIÓN DE LISKOV ............................................................ 22 2.3.7 PRINCIPIO DE SEGREGACIÓN DE INTERFACES ................................................ 22 2.3.8 PRINCIPIO DE INVERSIÓN DE DEPENDENCIAS ................................................. 22 2.3.9 RABBITMQ ..................................................................................................................... 22 2.3.10 REACTJS ..................................................................................................................... 23 2.3.11 UUID ............................................................................................................................. 23 2.3.12 KUBERNETES ............................................................................................................ 23 2.3.13 BOLETO DE VIAJE ................................................................................................... 23 2.3.14 COOPERATIVA DE TRANSPORTES .................................................................... 23 ix 2.4 LEGAL.............................................................................................................................. 24 2.4.1 LEY ORGÁNICA DE TRANSPORTE TERRESTRE TRANSITO Y SEGURIDAD VIAL 24 2.4.2 LEY ORGÁNICA DE PROTECCIÓN DE DATOS ..................................................... 24 2.4.3 DE LA INSTITUCIÓN. ................................................................................................... 24 CAPÍTULO III .............................................................................................................................. 25 METODOLOGÍA ......................................................................................................................... 25 3.1 METODOLOGÍA DE DESARROLLO DE SOFTWARE (SCRUM) ........................ 25 3.1.1 PROCESO DE SCRUM .................................................................................................. 25 3.1.2 ROLES DE SCRUM: ....................................................................................................... 26 3.1.3 EVENTOS (CEREMONIAS): ........................................................................................ 26 3.1.4 ARTEFACTOS: ............................................................................................................... 27 3.1.5 HISTORIA DE USUARIO .............................................................................................. 27 3.1.6 SCRUM Y DOMAIN DRIVEN DESING ...................................................................... 27 3.2 TÉCNICAS E INSTRUMENTOS DE RECOPILACIÓN DE DATOS ...................... 28 3.2.1 ENTREVISTA .................................................................................................................. 28 CAPÍTULO IV .............................................................................................................................. 29 INGENIERÍA DEL PROYECTO ............................................................................................... 29 4.1 ANÁLISIS Y PLANIFICACIÓN ................................................................................... 29 4.1.1 VISIÓN ............................................................................................................................. 29 4.1.2 SCRUM TEAM ................................................................................................................ 29 4.1.3 STAKEHOLDERS ........................................................................................................... 29 4.1.4 HISTORIAS DE USUARIO ............................................................................................ 30 4.1.5 BACKLOG ....................................................................................................................... 33 4.1.6 PLAN DE PRUEBAS ....................................................................................................... 34 4.1.6.1 OBJETIVO DE LAS PRUEBAS ................................................................................ 34 4.1.6.2 ALCANCE DE LAS PRUEBAS ................................................................................. 34 4.1.6.3 CRITERIOS DE ACEPTACIÓN ............................................................................... 34 4.1.6.4 PROCEDIMIENTOS DE LAS PRUEBAS ............................................................... 34 x 4.2 DISEÑO ............................................................................................................................ 35 4.2.1 ARQUITECTURA DE MICROSERVICIOS ............................................................... 35 4.2.2 DEFINICIÓN DE MICROSERVICIOS ........................................................................ 36 4.2.3 COMUNICACIÓN ENTRE MICROSERVICIOS ....................................................... 36 4.2.4 ARQUITECTURA DEL SOFTWARE .......................................................................... 50 CONCLUSIONES ......................................................................................................................... 72 RECOMENDACIONES ............................................................................................................... 73 BIBLIOGRAFÍA ........................................................................................................................... 74 ANEXOS ........................................................................................................................................ 76 xi INDICE DE TABLAS Tabla 1: Resumen historias de usuario.................................................................. 30 Tabla 2: Backlog ................................................................................................... 33 Tabla 3: Product Backlog Sprint 1 ........................................................................ 52 Tabla 4 Product Backlog Sprint 2 ......................................................................... 59 Tabla 5 Product Backlog Sprint 3 ......................................................................... 63 Tabla 6 Product Backlog Sprint 4 ......................................................................... 67 xii INDICE DE FIGURAS Figura 1: Diagrama de relación entre los building blocks .................................... 10 Figura 2: Ciclo de vida de una entidad.................................................................. 11 Figura 3: Agregado ............................................................................................... 12 Figura 4: Relación Entre Agregados. .................................................................... 12 Figura 5:Obtención de datos mediante el Patrón Criteria ..................................... 13 Figura 6: Patrón factoría........................................................................................ 14 Figura 7: Representación Arquitectura en Capas .................................................. 15 Figura 8: Representación Arquitectura Hexagonal ............................................... 16 Figura 9: Representación CQRS ........................................................................... 18 Figura 10: Elementos Arquitectura basa en eventos. ............................................ 19 Figura 11: Representación Microservicios............................................................ 20 Figura 12: Proceso Scrum ..................................................................................... 25 Figura 13: Arquitectura de Microservicios ........................................................... 35 Figura 14: Comunicación entre microservicios .................................................... 36 Figura 15: Estructura de Directorios Arquitectura Hexagonal ............................. 51 Figura 16 Cobertura de los TEST ......................................................................... 51 Figura 17 Diagrama E-R Servicio de Usuarios ..................................................... 53 Figura 18: Pantalla Iniciar Sesión ......................................................................... 54 Figura 19: Pantalla para restaurar la contraseña. .................................................. 54 Figura 20: Despliegue del servicio ........................................................................ 59 Figura 21 Diagrama E-R Servicio de Boletería .................................................... 60 Figura 22 Interfaz para crear un Bus ..................................................................... 61 Figura 23: Formulario para crear la carrocería ..................................................... 61 Figura 24 Interfaz para crear una Ruta .................................................................. 62 Figura 25 Diagrama E-R servicio de contabilidad ................................................ 64 Figura 26 Diagrama E-R Servicio de Facturación Electrónica ............................. 65 Figura 27 Interfaz del plan de cuentas .................................................................. 66 Figura 28 Interfaz para crear un asiento contable ................................................. 66 Figura 29 Interfaz del sistema ............................................................................... 67 Figura 30 Servicios desplegados en GKE ............................................................. 70 Figura 31 Balanceador de Carga ........................................................................... 71 xiii Figura 32: Consumo de CPU ................................................................................ 71 1 INTRODUCCIÓN Domain-Driven Design (DDD), introducido por Eric Evans en su libro “Domain- Driven Design - Tackling Complexity in the Heart of Software”, redefine el diseño de software al incorporar una perspectiva no solo técnica, sino también organizativa. Este enfoque pone un énfasis especial en comprender a fondo el dominio de negocio, fomentando la colaboración entre expertos y desarrolladores mediante la creación de un lenguaje compartido. En el ámbito del desarrollo de sistemas informáticos para la gestión y venta de boletos, existe una brecha en cuanto a la aplicación efectiva de metodologías que aborden de manera precisa las complejidades y relaciones del dominio específico de la Cooperativa de Transportes “San Pedrito”. Aquí es donde Domain Driven Design a diferencia de enfoques convencionales, ofrece herramientas y conceptos que permiten modelar el dominio (lógica de negocio) de manera más precisa, proporcionando así una solución a las necesidades específicas de la cooperativa. Mediante la aplicación de DDD, no solo se desarrolló un sistema informático eficiente, sino también una herramienta estratégica que refleja con precisión los procesos de gestión y venta de boletos, promoviendo así una mayor eficiencia operativa y una experiencia mejorada para los usuarios finales. Al haber optado por una metodología que fomente la colaboración y la comprensión profunda del dominio, se buscó no solo cerrar la brecha identificada, sino también establecer un estándar más elevado para el desarrollo de sistemas informáticos en el contexto específico de la Cooperativa de Transportes “San Pedrito”. El capítulo I describe la problemática en la gestión y venta de boletos de la Cooperativa de Transportes “San Pedrito”. Justifica la necesidad de desarrollar una aplicación informática, identificando beneficios y alcance. El capítulo II explora los antecedentes relacionados con proyectos similares y fundamentos científicos y conceptuales. El capítulo III detalla cómo aplicar la metodología de desarrollo de software (SCRUM) en el proyecto, además de las técnicas de recopilación de datos. En el capítulo IV detalla la implementación especifica del proyecto utilizando la metodología SCRUM, Se destacan los elementos característicos de esta 2 metodología en la ingeniería del software, como la planificación de sprints, el product backlog y el desarrollo de los sprints. 3 RESUMEN El sistema desarrollado para la Cooperativa de Transportes “San Pedrito” ha abordado con éxito varios desafíos, como la venta duplicada del número de asiento, la falta de control en la disponibilidad de asientos y la ineficiencia en la administración de la información. Estos problemas se resolvieron mediante la implementación de una aplicación informática que utiliza tecnologías avanzadas como Domain-Driven Design (DDD), Scrum, microservicios y GraphQL. Con la adopción del enfoque de Domain-Driven Design (DDD), se logró una clara separación de la lógica de negocio del resto de la aplicación, lo que permitió resolver los problemas de duplicación de ventas de asientos y mejorar la gestión de la información. Además, la metodología Scrum posibilitó una entrega iterativa y adaptativa, lo que permitió abordar los desafíos de manera eficiente y responder a los cambios en los requisitos del proyecto. La arquitectura basada en microservicios, utilizando Spring Boot como framework principal, brindó modularidad y flexibilidad al sistema. La implementación de GraphQL facilitó la comunicación entre los microservicios y permitió consultas más eficientes, mejorando así la experiencia del usuario final. Además, se adoptó el patrón de diseño API Gateway para gestionar la comunicación entre los microservicios, simplificando la interacción cliente-servidor y centralizando la lógica de enrutamiento y seguridad. La arquitectura dirigida por eventos permitió una integración más flexible y escalable entre los microservicios, lo que redujo la dependencia entre ellos y facilitó la gestión de la concurrencia y la escalabilidad. Es importante destacar que la evolución constante del sistema requiere capacitación continua del personal para garantizar su mantenimiento óptimo y aprovechar al máximo todas las funcionalidades ofrecidas por la aplicación. Palabras clave: Domain Driven Design, Transporte, GraphQL, Arquitectura hexagonal, Event-driven-architecture. 4 ABSTRACT The system developed for the Cooperativa de Transportes "San Pedrito" has successfully addressed several challenges, such as duplicate seat number sales, lack of control over seat availability, and inefficient information management. These problems were solved by implementing a software application using advanced technologies such as Domain-Driven Design (DDD), Scrum, microservices, and GraphQL. By adopting the Domain-Driven Design (DDD) approach, a clear separation of the business logic from the rest of the application was achieved, solving the problems of duplicate seat sales and improving information management. In addition, the Scrum methodology enabled iterative and adaptive delivery, allowing challenges to be addressed efficiently and responding to changes in project requirements. The microservices-based architecture, using Spring Boot as the main framework, provided modularity and flexibility to the system. The implementation of GraphQL facilitated communication between the microservices and enabled more efficient queries, thus improving the end-user experience. In addition, the API Gateway design pattern was adopted to manage communication between the microservices, simplifying client-server interaction and centralizing routing and security logic. The event-driven architecture allowed for more flexible and scalable integration between microservices, reducing dependency between them and facilitating concurrency management and scalability. It is important to note that the constant evolution of the system requires continuous staff training to ensure optimal maintenance and to take full advantage of all the functionalities offered by the application. Keywords: Domain Driven Design, Transport, GraphQL, Hexagonal architecture, Event-driven-architecture. 5 CAPÍTULO I FORMULACIÓN GENERAL DEL PROYECTO 1.1 Tema DESARROLLO DE UN SISTEMA INFORMÁTICO PARA LA GESTIÓN Y VENTA DE BOLETOS EN LA COOPERATIVA DE TRANSPORTES “SAN PEDRITO” APLICANDO DOMAIN DRIVEN DESIGN (DDD) 1.2 Descripción del Problema La Cooperativa de Transportes “San Pedrito” es una empresa que se dedica al transporte de pasajeros a diversas localidades de Ecuador, gestionaba y vendía boletos a través de un sistema de escritorio descentralizado ubicado en diferentes puntos de venta. Sin embargo, este enfoque descentralizado conllevaba a diversos problemas, como la venta duplicada de boletos a diferentes personas, falta de visibilidad en tiempo real de la disponibilidad de asientos y dificultades en la administración de la información de los pasajeros, entre los inconvenientes más comunes que tenían eran: • Venta Duplicada del número de Asiento: Debido a la falta de comunicación entre los puntos de venta, se registraban casos en los que un mismo número de asiento se vendía a varias personas, lo que generaba conflictos y malestar entre los pasajeros. • Falta de Control en la Disponibilidad de Asientos: Los puntos de venta no tenían una visión en tiempo real de la disponibilidad de asientos en los diferentes viajes, lo que causaban sobreventa o sobre venta de boletos. • Ineficiencia en la Administración de la Información: El sistema no permitía una administración eficiente de la información de los pasajeros, lo que dificulta el seguimiento de ventas de boletos, cancelaciones y cambios en los itinerarios. 6 1.3 Justificación La Cooperativa de Transportes “San Pedrito” reconoció la urgente necesidad de implementar un sistema informático para la gestión y venta de boletos. Esta iniciativa surgió como una respuesta fundamentada ante los desafíos derivados de la descentralización en la venta de boletos. La motivación principal radicó en la búsqueda de la modernización y optimización de los procesos existentes para superar problemas operativos. Esta inversión en tecnología no solo superó los obstáculos que existían, sino que también se estableció como un paso estratégico hacia la mejora continua y la eficiencia en la gestión de la cooperativa. El sistema se caracteriza por contar con un módulo de contabilidad que se encarga de gestionar y organizar la información financiera de la empresa, sus funciones principales son registro de transacciones, libro mayor, libro diario e informes. Además, controla en tiempo real de la disponibilidad de asientos, que garantiza la asignación de asientos únicos. La centralización de la gestión no solo reduce los costos de mantenimiento, sino que también simplifica la administración de los puntos de venta, promoviendo así una mayor eficacia operativa. La implementación del sistema fue indispensable, y los beneficios resultantes de su aplicación son significativos tanto para la cooperativa como para sus operaciones y clientes. La cooperativa estuvo firmemente comprometida con la mejora continua de sus procesos, considerando este proyecto como un paso esencial hacia la modernización y automatización de procesos. La implementación de Domain Driven Design (DDD) en el proyecto de la Cooperativa de Transportes “San Pedrito” representó la adopción de un enfoque metodológico altamente estructurado. Este enfoque actuó como un plano detallado, proporcionando una guía precisa para la construcción de un sistema de venta de boletos que se alinean de manera óptima con los requisitos y desafíos técnicos específicos de la cooperativa. Este enfoque de diseño contribuyó a establecer un lenguaje común entre todos los miembros del equipo, evitando confusiones y mejorando la colaboración entre los que trabajaron en el proyecto. Además, permitió construir un sistema que se adapta fácilmente a los cambios en el negocio, 7 asegurando que la cooperativa pudiera crecer y ajustarse sin problemas a medida que evolucionan sus operaciones. El proyecto se enmarcó en la línea de investigación Ingeniería De Software, Redes y Telecomunicaciones, sublínea Diseño e implementación de sistemas de información de la carrera de Software. 1.4 Objetivos 1.4.1 General Desarrollar un sistema informático para la gestión y venta de boletos en la Cooperativa de Transportes “San Pedrito” aplicando Domain Driven Design (DDD). 1.4.2 Específicos • Analizar los procesos de negocio de la Cooperativa de Transportes “San Pedrito” relacionados con la gestión y venta de boletos. • Definir la arquitectura del sistema basada en DDD. • Implementar sistema informático para la gestión y venta de boletos. 8 CAPÍTULO II MARCO TEÓRICO 2.1 Antecedentes Según (SANDOVAL POZO, 2021) en su tesis de pregrado titulada “Aplicación Web para mejorar la Gestión Administrativa de la Cooperativa de Transportes Huaca - Julio Andrade", propusieron el desarrollo de un sistema informático con el objetivo de mejorar la gestión administrativa de la Cooperativa ubicada en la ciudad de Tulcán. El estudio identificó una problemática significativa: la ausencia de un archivo físico adecuado para la documentación, lo cual estaba ocasionando pérdidas, demoras y retrasos en los trámites administrativos. Para hacer frente a este desafío, se emplearon las tecnologías PHP y JavaScript en el desarrollo de la aplicación, respaldadas por una base de datos en MySQL. La aplicación se organiza en módulos diseñados específicamente para la administración y control del talento humano, facilitando las labores del personal administrativo y asegurando la agilidad y seguridad de los procesos. Además, la aplicación brinda a los usuarios la capacidad de mantenerse informados sobre la caducidad de sus documentos personales y reglamentarios. Se destaca la importancia de capacitar al personal para aprovechar eficientemente esta herramienta tecnológica, con el objetivo de optimizar la toma de decisiones gerenciales. (Cando Jacome & Tenesaca Pérez, 2021) en su Monografía titulada Desarrollo de una aplicación web y móvil para la automatización en la gestión de venta y reserva de boletos en la Cooperativa de Transportes Ambateñita de la ciudad de Ambato crearon una aplicación para ayudar a la cooperativa a vender y reservar boletos de manera más eficiente, ya que no tenían una aplicación para esto. Recopilaron y analizaron los requisitos para el sistema web y móvil propuestos por la cooperativa. Utilizaron herramientas como MySQL para organizar la información en la base de datos, asegurando la integridad de los datos. La metodología Scrum fue utilizada para guiar el proceso ágil de codificación y diseño del sistema. Finalmente, entregaron tanto el sistema web como la aplicación móvil de manera segura, 9 cumpliendo con los requisitos establecidos en el certificado de implementación de la cooperativa. Según (SALAN VILLENA, 2015) es su tesis de pregrado titulada Aplicación web para la gestión de rutas y pre-reservas de la cooperativa de transportes El Dorado, se abordó la carencia de un sistema de facturación de boletos y la realización de procesos manuales en la cooperativa. La ausencia de una guía de rutas y la falta de información sobre las unidades por parte de los socios revelaban la necesidad de automatizar los procesos de reservas. Para solucionar estos problemas, se desarrolló una aplicación utilizando MySQL y Visual Studio, aprovechando software libre para facilitar la gestión de rutas y lograr un control exhaustivo. Este desarrollo mejoró significativamente los procesos automatizados de la cooperativa, permitiendo una gestión más eficiente y proporcionando a los socios información detallada sobre las rutas y disponibilidad de unidades. 10 2.2 Científico 2.2.1 Domain-Driven Design (DDD) Es un enfoque de diseño de software propuesto por Eric Evans en su libro "Domain- Driven Design: Tackling Complexity in the Heart of Software". DDD se centra en la colaboración estrecha entre expertos del dominio y desarrolladores para construir un modelo que refleje con precisión el negocio subyacente, en la figura 1 podemos observar la relación que existe entre los bloques que este lo componen. Fuente: Relación entre bloques tomado de (Autentia S.L., 2023) 2.2.2 Entities (Entidades) Según (Evans, 2003) las "entidades" son como objetos que tienen una identidad única y que son distinguibles a lo largo del tiempo. Estas representan objetos clave dentro del dominio y son fundamentales para modelar la lógica de negocio. Una entidad se refiere a un objeto en un dominio específico que puede estar compuesto por varios objetos de valor para enriquecer su significado. Una entidad en un dominio es un objeto autónomo con un ciclo de vida (Figura 2) definido. La finalidad de definir entidades en nuestro dominio es evitar el uso de tipos primitivos, proporcionar significado a nivel de código y facilitar la incorporación de la lógica de negocio en el dominio (Autentia S.L., 2023) Figura 1: Diagrama de relación entre los building blocks 11 Figura 2: Ciclo de vida de una entidad. Fuente: Ciclo de una entidad tomado de (Autentia S.L., 2023) 2.2.3 Value Objects (Objetos de Valor) Según (Fowler, 2003) Son objetos que no tienen una identidad única y se definen únicamente por sus atributos. Los "objetos de valor" son inmutables y representan conceptos que son importantes, pero no necesitan una identidad propia. 2.2.4 Services (Servicios) En DDD, los servicios son acciones que no pertenecen directamente a entidades u objetos de valor, desacoplando tareas en capas como infraestructura, aplicación y dominio. Se definen por la acción que realizan y no por un concepto de negocio específico. Pueden ser de dominio (orquestando funcionalidades), de aplicación (coordinando acciones entre servicios) y de infraestructura (proveyendo acceso a recursos externos). Sus operaciones no tienen estado y manejan conceptos de negocio (Autentia S.L., 2023). 2.2.5 Aggregates (Agregados) Un agregado es una agrupación de entidades y objetos de valor que, en términos conceptuales, están vinculados como un conjunto, estos definen límites dentro de los cuales las operaciones se realizan de manera consistente y deben ser tratados como una unidad en el sistema. (Evans, 2003). Cada Agregado cuenta con una entidad raíz (aggregate root) que sirve como punto de dependencia para las demás entidades y objetos de valor. 12 Figura 3: Agregado Fuente: Agregados tomado de (Autentia S.L., 2023) Cualquier modificación a un componente interno del agregado debe llevarse a cabo a través de métodos accesibles en la entidad raíz, asegurando la integridad y estado del conjunto en memoria. Las referencias desde fuera del agregado deben dirigirse exclusivamente a la raíz de este (Autentia S.L., 2023). Figura 4: Relación Entre Agregados. Fuente: Relación entre agregados tomado de (Autentia S.L., 2023) Los agregados se relacionan entre sí exclusivamente a través de los identificadores de sus entidades raíces. Son la unidad fundamental para la transferencia de datos, ya que se cargan o guardan como entidades completas. Las transacciones no deben traspasar los límites de los agregados. Los clientes que consumen un agregado no necesitan conocer los detalles de implementación ni navegar entre referencias internas. Los atributos, propiedades, elementos y comportamientos internos del agregado no deben ser accesibles para el cliente (Autentia S.L., 2023). 13 2.2.6 Repositories (Repositorios) Según (Fowler, 2003) Los repositorios son responsables de la persistencia de los agregados. Proporcionan una interfaz para acceder y almacenar agregados en una forma que sea alineada con el modelo del dominio. Existen tres maneras de obtener objetos durante su ciclo de vida: crear uno nuevo, obtenerlo mediante la asociación con otro objeto existente, o construirlo utilizando atributos de una base de datos. En el caso de la última opción, se emplea el patrón repositorio, que encapsula el acceso a la base de datos para obtener los valores necesarios. Este enfoque permite que el cliente del repositorio no se preocupe por cómo se recupera la información ni por la tecnología utilizada, manteniendo el enfoque en el dominio (Autentia S.L., 2023). Un repositorio debe proporcionar al menos métodos para añadir, recuperar y eliminar objetos de un tipo, utilizando consultas a la base de datos para estas operaciones. También puede ofrecer métodos para que el cliente recupere datos según criterios específicos, como el identificador o un valor de atributo, devolviendo objetos individuales o colecciones que cumplan con el criterio. Además, puede incluir funciones que realicen cálculos sobre la base de datos, como sumas de atributos o el conteo de objetos que cumplen con un criterio (Autentia S.L., 2023). Además, los repositorios pueden ofrecer métodos que aceptan especificaciones de criterios de consulta proporcionadas por el cliente. Esto permite que el cliente defina los criterios sin preocuparse por la tecnología utilizada para recuperar los datos, ya que es responsabilidad del repositorio transformar esos criterios en consultas a la base de datos (Autentia S.L., 2023). Figura 5:Obtención de datos mediante el Patrón Criteria Fuente: Patrón criterio tomado de (Autentia S.L., 2023) 14 2.2.7 Factorias Cuando la creación de objetos o agregados se vuelve complicada, el patrón factoría (factory) puede simplificar el proceso y ocultar la estructura interna de los objetos creados. Evita que el cliente, especialmente si forma parte de la capa de aplicación, asuma responsabilidades indebidas, lo cual violaría la encapsulación de los objetos de dominio y agregados. La creación de objetos complejos es responsabilidad de la capa de dominio, y para abordar esto, se introducen nuevos objetos en el diseño del dominio que no son entidades, value objects ni servicios, pero son esenciales para la capa de dominio (Autentia S.L., 2023). Figura 6: Patrón factoría Fuente: Patrón Factoría tomado de (Autentia S.L., 2023) Cada lenguaje orientado a objetos ofrece un método para crear objetos, como los constructores, pero surge la necesidad de mecanismos de construcción más abstractos que estén desacoplados de otros objetos. Un componente del programa encargado de la creación de objetos se denomina factoría. 2.2.8 Arquitectura en capas Para diseñar una arquitectura por capas siguiendo los principios de DDD, es esencial comenzar con la regla de dependencia, asegurando que un elemento de una capa solo dependa de otros elementos dentro de la misma capa o de capas más internas. Esto facilita la incorporación y adaptación de nuevas piezas de código a medida que el proyecto crece, simplificando el mantenimiento al tener piezas de software claramente diferenciadas. En el contexto de DDD, se distinguen tres capas fundamentales: la capa de dominio, la capa de aplicación y la capa de infraestructura (Autentia S.L., 2023). 15 Figura 7: Representación Arquitectura en Capas . Fuente: Arquitectura en capas tomado de (Autentia S.L., 2023) 2.2.9 Capa de dominio La capa de dominio constituye el núcleo o esencia de la aplicación, encargándose de traducir las principales necesidades del negocio en código. Para lograr esto, se emplean los conceptos de entidades, objetos de valor y agregados, como se han definido previamente. En esta capa, podemos diferenciar entre el modelo y los servicios de dominio. El modelo engloba aquellos objetos esenciales para el núcleo del dominio, representando de manera única aspectos del negocio, como, por ejemplo, las entidades. Cuando la lógica de negocio resulta compleja y no puede ser expresada en el modelo, surgen los servicios de dominio, que representan servicios con lógica específica para un dominio en particular (Autentia S.L., 2023). 2.2.10 Capa de aplicación La capa de aplicación asume la responsabilidad de crear y recuperar objetos de dominio para atender las solicitudes del usuario. Aunque carece de lógica de negocio, desempeña funciones de coordinación entre ellos de acuerdo con los requisitos y casos de uso de la aplicación. En otras palabras, alberga los servicios que establecen la conexión entre la capa de dominio y el entorno externo (Autentia S.L., 2023). 2.2.11 Capa de Infraestructura La capa de infraestructura suministra capacidades técnicas a las capas superiores o internas, como la posibilidad de persistir las entidades de dominio en bases de datos. 16 Es fundamental que esté totalmente desacoplada de la capa de dominio. Esto asegura que, por ejemplo, si actualmente utilizamos una base de datos relacional para la persistencia de datos y en el futuro deseamos cambiar a otro motor de persistencia, dicho cambio no afectará a las capas superiores (Autentia S.L., 2023). 2.2.12 Arquitectura Hexagonal Según (Vieira, 2022) La arquitectura hexagonal, también conocida como la arquitectura de puertos y adaptadores, es un enfoque de diseño de software que busca separar las preocupaciones y minimizar las dependencias entre las diferentes capas de un sistema. Fue propuesta por Alistair Cockburn y se centra en la idea de organizar el código en hexágonos concéntricos para lograr un diseño modular y flexible. Figura 8: Representación Arquitectura Hexagonal Fuente: Arquitectura hexagonal. Tomado de (Fidao, 2023) En esta arquitectura, el núcleo del sistema está representado por un hexágono central (No está limitado a 6 capas por el número de lados) que contiene la lógica de negocio o aplicación. Este hexágono no está directamente acoplado a ninguna tecnología externa, como bases de datos, interfaces de usuario o servicios web. Alrededor del núcleo, se encuentran hexágonos externos que representan los diferentes puertos de entrada y salida del sistema. Estos puertos pueden incluir interfaces de usuario, servicios web, bases de datos, entre otros. Los adaptadores actúan como puentes entre el núcleo y los puertos, facilitando la comunicación. La ventaja clave de la arquitectura hexagonal es su capacidad para aislar el núcleo de la aplicación de las implementaciones concretas de los componentes externos. Esto facilita la prueba unitaria, el mantenimiento y la evolución independiente de 17 las distintas partes del sistema. Además, permite cambiar fácilmente las tecnologías subyacentes sin afectar la lógica de negocio central. 2.2.13 Bounded context (Contexto Delimitado) (Evans, 2003) Introduce el concepto de "contexto delimitado" para definir límites claros en los cuales un determinado término o concepto tiene un significado específico. Esto ayuda a evitar malentendidos y conflictos en la interpretación de conceptos en diferentes partes del sistema. Este representa un área donde el dominio de un problema de negocio está completamente definido utilizando un lenguaje común, conocido como "ubiquitous language" (Autentia S.L., 2023). En cualquier negocio, existen reglas y sistemas existentes que deben integrarse en la solución. Cada departamento de una empresa puede tener sus propios objetivos y métricas, así como términos específicos con significados particulares dentro de su contexto. El lenguaje común o "ubiquitous language" se utiliza para definir el dominio dentro de cada contexto o subdominio (Autentia S.L., 2023). Por ejemplo, en un negocio donde existen dos departamentos: uno de ventas y otro de soporte, el termino cliente tiene un concepto diferente en cada uno de estos, para ventas el cliente realiza compras, pagos, pedidos y para soporte el cliente tiene problemas, tickets relacionados con los productos que tiene el negocio (Autentia S.L., 2023). Es esencial emplear un lenguaje común en cada contexto para distinguir los términos específicos de cada departamento. Este lenguaje debe ser claro y compartido por todo el equipo, incluyendo desarrolladores, expertos de dominio y usuarios finales. La evolución de este lenguaje se logra con la participación continua del equipo, no se define en una única reunión. Cada "bounded context" normalmente representa un subdominio, separando diferentes áreas de negocio (Autentia S.L., 2023). 2.2.14 Command-Query Responsibility Segregation (CQRS) CQRS es un modelo arquitectónico que se fundamenta en la distinción entre las operaciones de lectura y las de escritura, denominadas como modelos Query y Command respectivamente. En términos conceptuales, esto implica la separación de ambos modelos de datos para que operen de manera independiente. El propósito 18 principal es mejorar la simplicidad en la escalabilidad, lectura y escritura, así como fortalecer la seguridad de ambas partes de forma individual. A pesar de estos beneficios, es importante destacar que introduce una complejidad adicional en nuestro sistema (Betts et al., 2012). Los Commands Se alinea con el modelo de escritura encargado de almacenar la información proveniente de la capa de presentación. Debería ser la única vía para modificar el estado del sistema y podría abarcar reglas de validación aplicadas a los datos (Autentia S.L., 2023). Los Querys corresponde con el modelo de lectura de datos, el cual proporciona un resultado sin modificar el estado del sistema. Su función principal es transformar los datos para presentarlos en la interfaz de usuario según lo requerido (Autentia S.L., 2023). Figura 9: Representación CQRS Fuente: Diagrama cqrs tomado de (Autentia S.L., 2023) La ventaja principal proporcionada por esta distinción o segregación es la independencia entre los dos modelos, lo que permite escalar cada uno según nuestras necesidades. Incluso es posible ejecutarlos en máquinas diferentes. Al tratarse de dos "entidades" claramente diferenciadas, tenemos la capacidad de aplicar niveles de seguridad de manera separada y optimizar el tipo de tarea, ya sea consulta o persistencia en la base de datos (Autentia S.L., 2023). 2.2.15 Event-driven architecture (Arquitectura orientada a eventos) Según (Green, 2022) La arquitectura orientada a eventos (EDA) es un patrón que fomenta el uso de eventos para la comunicación entre componentes independientes, 19 siendo común en aplicaciones basadas en microservicios. Un evento, en este contexto, representa un cambio asíncrono de estado o una actualización, como agregar un artículo al carrito en un sitio web de comercio electrónico. Estos eventos pueden contener información de estado, como los detalles de un artículo comprado, su precio y dirección de entrega, o ser identificadores, como una notificación de envío de un pedido. Figura 10: Elementos Arquitectura basa en eventos. Fuente: Event Driven architecture tomado de (Autentia S.L., 2023) Las arquitecturas basadas en eventos constan de tres elementos clave: los publicadores de eventos, los brokers de mensajes (routers) de eventos y los consumidores de eventos. Un publicador emite un evento al broker de mensajes, el cual filtra y envía los eventos a los consumidores registrados para ese tipo específico de evento. La relación entre el servicio que publica eventos y el servicio que los consume es desacoplada, permitiendo escalar, actualizar e implementar ambos de manera independiente. A través del canal (channel), los eventos se transmiten desde el publicador a los consumidores suscritos a ese canal. 2.2.16 Eventos de dominio Un evento de dominio transporta información sobre un suceso dentro del dominio y tiene como objetivo comunicar este acontecimiento a otras partes de este. La reacción a dicho evento por otras partes del dominio puede variar. Cada evento de dominio captura información proveniente de su origen, y si se planea utilizar los registros como auditoría, es crucial que estos datos de origen sean inmutables. En otras palabras, una vez que se ha creado el objeto de evento, los datos de origen no pueden ser modificados. Sin embargo, existe otro tipo de datos relacionados con el evento que registra las acciones realizadas por el sistema en respuesta a dicho evento, conocidos como datos de procesamiento (Autentia S.L., 2023). 20 Los datos de un evento de dominio se dividen en dos categorías: datos de origen inmutables que describen la naturaleza del evento, y datos de procesamiento mutables que registran las acciones ejecutadas por el sistema en respuesta al evento. Aunque los datos de origen son inalterables, puede surgir la necesidad de realizar cambios, generalmente debido a que el evento original fue incorrecto. Para abordar esto, se emplea otro tipo de evento llamado evento retroactivo, utilizado para corregir las consecuencias de eventos erróneos anteriores (Autentia S.L., 2023). 2.2.17 Config service Con el Config Server, tienes un lugar centralizado para gestionar propiedades externas para aplicaciones en todos los entornos. Los conceptos en el cliente y el servidor se mapean de manera idéntica a las abstracciones Environment y PropertySource (Vieira, 2022). 2.2.18 Microservicios La arquitectura de microservicios, también conocida como MSA, consiste en desarrollar una aplicación mediante un conjunto de pequeños servicios. Cada uno de estos servicios opera en su propio proceso y se comunica a través de mecanismos livianos, generalmente mediante una API de recursos HTTP. Cada microservicio asume la implementación completa de una funcionalidad de negocio y puede ser desplegado de manera autónoma, permitiendo la utilización de diferentes lenguajes de programación y tecnologías de almacenamiento de datos. Esta arquitectura descompone los modelos de dominio de negocio en contextos más reducidos, coherentes y bien definidos, implementados por los servicios individuales (Pacheco, 2018). Figura 11: Representación Microservicios Fuente: Diseño de microservicios tomado de (Richardson, 2023) https://microservices.io/patterns/microservices.html 21 2.3 Conceptual 2.3.1 Arquitectura de software Según (Pressman, 2010)La arquitectura de software abarca las estructuras del sistema, los componentes o módulos del software, las propiedades externamente visibles de esos componentes y las relaciones entre ellos. 2.3.2 Hibernate Según (Tudose et al., 2023) Hibernate es un framework de mapeo objeto-relacional para Java que facilita la interacción entre aplicaciones Java y bases de datos relacionales. Permite a los desarrolladores trabajar con objetos Java en lugar de consultas SQL directas, gestionando el mapeo de objetos a tablas de base de datos, consultas mediante el lenguaje HQL, transacciones y caching. Con características como el mapeo de asociaciones y una gestión eficiente de la capa de persistencia, Hibernate simplifica el desarrollo de aplicaciones empresariales que requieren una conexión robusta entre la lógica de la aplicación y la persistencia de datos en una base de datos relacional. 2.3.3 Patrón Criteria Según (Evans, 2003) es un patrón de diseño, mediante el cual, se permite filtrar una colección de objetos bajo diversos criterios, encadenándolos de una manera desacoplada por medio de operaciones lógicas. Este patrón se utiliza en escenarios específicos, donde la obtención de uno o más entidades depende de reglas de negocio. 2.3.4 Principio de Responsabilidad Única Según (Iglberger, n.d.) El principio de responsabilidad única, también conocido como single responsibility, postula que un componente de software debe tener únicamente un motivo para ser modificado. La responsabilidad, en este contexto, se refiere a ese motivo de cambio específico. 2.3.5 Principio de Abierto/Cerrado Según (Iglberger, n.d.) El principio Open/Closed (OCP) establece que los módulos de software deben ser diseñados de manera que sean abiertos para su extensión, permitiendo la incorporación de nuevos comportamientos conforme evolucionan los requisitos de la aplicación. Simultáneamente, deben ser cerrados para su modificación, lo cual implica que un módulo con una interfaz estable y bien 22 definida no debería requerir cambios en su código original al extender su funcionalidad. En otras palabras, se busca la capacidad de ampliar el comportamiento sin afectar el código existente, asegurando una estructura flexible y resistente a modificaciones innecesarias. 2.3.6 Principio de sustitución de Liskov Según (Iglberger, n.d.) El principio de sustitución de Liskov establece que los objetos de un programa deben ser intercambiables por instancias de sus subtipos sin afectar el correcto funcionamiento del programa. En esencia, si utilizamos una clase en alguna parte de nuestro código y luego extendemos esa clase, deberíamos poder emplear cualquiera de las clases derivadas sin que el programa pierda su validez. Este principio nos ayuda a garantizar que la extensión de una clase no altere el comportamiento de la clase padre. 2.3.7 Principio de segregación de interfaces Según (Iglberger, n.d.) El principio de segregación de interfaces sostiene que es preferible tener múltiples interfaces específicas para los clientes en lugar de una interfaz general para todos los propósitos. Cuando los clientes se ven obligados a utilizar partes de una interfaz que no necesitan en su totalidad, están expuestos a cambios innecesarios en esa interfaz. Esto conduce, en última instancia, a un acoplamiento innecesario entre los clientes y las interfaces, generando una mayor dependencia de lo requerido. 2.3.8 Principio de inversión de dependencias Según (Iglberger, n.d.)El principio de segregación de interfaces propone que es más beneficioso contar con múltiples interfaces específicas para los clientes en lugar de una interfaz general que abarque todos los propósitos. Cuando los clientes se ven obligados a utilizar partes de una interfaz que no requieren completamente, quedan expuestos a cambios superfluos en esa interfaz. Este escenario, en última instancia, resulta en un acoplamiento innecesario entre los clientes y las interfaces, creando una dependencia mayor de lo necesario. 2.3.9 RabbitMQ Según (Dobbelaere & Esmaili, 2017) RabbitMQ funciona como un broker de mensajería, actuando como intermediario en el proceso de intercambio de mensajes. Ofrece a las aplicaciones una plataforma compartida para el envío y recepción de 23 mensajes, garantizando un entorno seguro para que los mensajes permanezcan hasta su recepción. 2.3.10 ReactJS Según (Frensia Tanaga Anaclaudia et al., 2023) React.js, o simplemente React, es una biblioteca de JavaScript de código abierto desarrollada por Facebook. Se utiliza para construir interfaces de usuario (UI) interactivas y eficientes para aplicaciones web. React se centra en la creación de componentes reutilizables que representan partes específicas de la interfaz de usuario. 2.3.11 UUID Según (Leach et al., 2023) UUID, que significa "Identificador Único Universal" en inglés, es un estándar para identificadores únicos que se utiliza en el ámbito de la informática. Un UUID es una cadena de caracteres alfanuméricos que se asigna a un recurso o entidad de manera única en el tiempo y el espacio. La intención detrás de los UUID es proporcionar identificadores únicos incluso en entornos distribuidos y sin necesidad de coordinación centralizada. 2.3.12 Kubernetes Kubernetes es una plataforma de código abierto que automatiza el despliegue, escalado y gestión de aplicaciones en contenedores, permitiendo a los usuarios agrupar contenedores en "pods" y gestionarlos eficientemente en un clúster de servidores, con características como autosanación, autoscalabilidad y gestión declarativa, lo que simplifica el proceso de implementación y administración de aplicaciones a gran escala en entornos de nube y locales. (Kubernetes, 2021) 2.3.13 Boleto de Viaje Un boleto de viaje es un documento que confirma la reserva y pago de un servicio de transporte, como avión, tren o autobús. Contiene detalles esenciales como la fecha, hora y ruta del viaje, y es necesario para acceder al medio de transporte. Con el avance tecnológico, los boletos electrónicos son cada vez más comunes, almacenados en dispositivos móviles o enviados por correo electrónico. 2.3.14 Cooperativa de Transportes Organización empresarial conformada por un grupo de individuos que se asocian para proporcionar servicios de transporte de manera conjunta. 24 2.4 Legal 2.4.1 Ley Orgánica de Transporte Terrestre Transito y Seguridad Vial De acuerdo con el artículo 46 de la Ley Orgánica de Transporte Terrestre Transito y Seguridad Vial “El transporte terrestre automotor es un servicio público esencial y una actividad económica estratégica del Estado, que consiste en la movilización libre y segura de personas o de bienes de un lugar a otro, haciendo uso del sistema vial nacional, terminales terrestres y centros de transferencia de pasajeros y carga en el territorio ecuatoriano. Su organización es un elemento fundamental contra la informalidad, mejorar la competitividad y lograr el desarrollo productivo, económico y social del país, interconectado con la red vial internacional.” 2.4.2 Ley Orgánica de Protección de datos De acuerdo con el artículo 66 numeral 19 de la Constitución de la República reconoce y garantiza a las personas: "19. El derecho a la protección de datos carácter personal, que incluye el acceso y la decisión sobre información y datos de este carácter, así como su correspondiente protección. La recolección, archivo, procesamiento, distribución o difusión de estos datos personales requerirán la autorización del titular o el mandato de ley"; 2.4.3 De la Institución. De acuerdo con el estatuto de la cooperativa de transportes “san pedrito” no existe impedimento para poder realizar la implementación de un sistema informático para la gestión y venta de boletos. 25 CAPÍTULO III METODOLOGÍA 3.1 Metodología de Desarrollo de Software (Scrum) Según (Schwaber & Sutherland, 2020) “Scrum es un marco de trabajo ágil para el desarrollo de software que se centra en la entrega iterativa e incremental de productos. Surgió en la década de 1990 y se ha convertido en uno de los enfoques más populares para gestionar proyectos complejos y adaptarse a cambios rápidos en los requisitos del cliente. Scrum se basa en principios de transparencia, inspección y adaptación, y se organiza en torno a roles definidos, eventos y artefactos”. 3.1.1 Proceso de Scrum Figura 12: Proceso Scrum Fuente: Scrum methodology: Understanding the process of agile software development tomato de (“Purpose of the Scrum Guide,” 2020) De acuerdo con (“Purpose of the Scrum Guide,” 2020) el proceso de trabajo en Scrum se organiza en iteraciones llamadas "sprints" y contiene lo siguiente: a) Planificación del Sprint: • El equipo y el propietario del producto se reúnen para seleccionar las tareas que se abordarán durante el próximo sprint. • Se define el objetivo del sprint. 26 b) Sprint: • Durante el sprint, que suele durar de 2 a 4 semanas, el equipo trabaja en las tareas seleccionadas. • Se llevan a cabo reuniones diarias de seguimiento, llamadas "Daily Scrum", para sincronizar el progreso. c) Revisión del Sprint: • Al final del sprint, se lleva a cabo una reunión de revisión en la que el equipo presenta el trabajo completado. • Se recopilan comentarios y se pueden realizar ajustes para futuros sprints. d) Retrospectiva del Sprint: • Después de la revisión, el equipo tiene una retrospectiva para analizar lo que salió bien, lo que salió mal y cómo mejorar en el próximo sprint. e) Reinicio del Ciclo: • Se inicia un nuevo sprint y el ciclo se repite. 3.1.2 Roles de Scrum: • Product Owner: “Es responsable de definir y priorizar el backlog del producto, representando los intereses del cliente y asegurándose de que el equipo desarrolle funcionalidades de alto valor” (“Purpose of the Scrum Guide,” 2020). • Scrum Master: “Facilita el proceso Scrum, elimina obstáculos para el equipo y asegura que se sigan las prácticas y reglas de Scrum”(“Purpose of the Scrum Guide,” 2020). • Equipo de Desarrollo: “El grupo de profesionales que realiza el trabajo para entregar un incremento de producto potencialmente entregable al final de cada sprint” (“Purpose of the Scrum Guide,” 2020). 3.1.3 Eventos (Ceremonias): • Sprint Planning: “Reunión al comienzo de cada sprint donde se seleccionan las tareas a realizar y se planifica cómo se abordarán” (“Purpose of the Scrum Guide,” 2020). 27 • Daily Scrum: “Reunión diaria corta para que el equipo sincronice actividades y planifique el trabajo para las próximas 24 horas”(“Purpose of the Scrum Guide,” 2020). • Sprint Review: “Reunión al final de cada sprint para revisar el trabajo completado y adaptar el backlog del producto en consecuencia” (“Purpose of the Scrum Guide,” 2020). • Sprint Retrospective: “Sesión al final de cada sprint para reflexionar sobre el proceso y buscar mejoras continuas” (“Purpose of the Scrum Guide,” 2020). 3.1.4 Artefactos: • Backlog del Producto: “Una lista priorizada de todas las características, funciones, mejoras y correcciones que constituyen el trabajo que debe realizarse”(“Purpose of the Scrum Guide,” 2020) • Backlog del Sprint: “Un conjunto de elementos seleccionados del backlog del producto que el equipo se compromete a completar durante un sprint” (“Purpose of the Scrum Guide,” 2020). • Incremento: “El producto funcional y potencialmente entregable al final de cada sprint” (“Purpose of the Scrum Guide,” 2020). 3.1.5 Historia de Usuario Las historias de usuario son descripciones breves de funcionalidades en el desarrollo de software, enfocadas en las necesidades del usuario. Se expresan como "Como [usuario], quiero [realizar una acción] para [lograr un objetivo]" (Singh, 2019). 3.1.6 Scrum y Domain Driven Desing Integrar Scrum con Domain-Driven Design (DDD) ofrece beneficios sinérgicos para el desarrollo de software. Scrum proporciona una estructura ágil, iterativa e incremental, mientras que DDD enfoca la atención en comprender y modelar el dominio del problema. Al combinarlos, se logra una colaboración más estrecha entre los desarrolladores y los expertos en el dominio, lo que resulta en un entendimiento profundo y continuo del dominio. Esto facilita la adaptación rápida a cambios, la entrega de funcionalidades valiosas y la mejora constante del modelo 28 del dominio a lo largo del tiempo, asegurando un desarrollo de software más alineado con las necesidades del negocio. 3.2 Técnicas e Instrumentos de Recopilación de Datos 3.2.1 Entrevista Según (Pressman, 2010) “Una entrevista es un proceso clave para recopilar información valiosa y comprender las necesidades de los stakeholders, usuarios finales y otros expertos relevantes”. Durante estas interacciones, el equipo de desarrollo se reunió con las partes interesadas, como los directivos, contadora y los empleados encargados de la venta de boletos de la cooperativa de transportes “San Pedrito”. Para llevar a cabo las entrevistas, se utilizó un guion que incluirá preguntas específicas diseñadas para obtener una comprensión más profunda de los requisitos y expectativas del software (Ver Anexo 5). 29 CAPÍTULO IV INGENIERÍA DEL PROYECTO 4.1 Análisis y Planificación 4.1.1 Visión Se desarrollo un sistema informático integral para la gestión y venta de boletos en la Cooperativa de Transportes “San Pedrito” aplicando los principios y prácticas de Domain Driven Design (DDD). 4.1.2 Scrum Team • Scrum Master: Eduardo Bonilla, responsable de coordinar y facilitar el proceso Scrum. • Product Owner: Melanin Ganan, se encargó de definir y priorizar los elementos del producto. • Developers Team : Integrado por Eduardo Bonilla y Melanin Ganan, quienes llevaron a cabo la implementación y desarrollo del producto. 4.1.3 Stakeholders • Personal de Venta: Empleados encargados de la venta de los boletos, la atención al cliente en las boleterías y controlar la asignación de viajes en las frecuencias diarias. • Contador: Encargado de la gestión contable, registro de ingresos y gastos, así como la generación de informes financieros para garantizar la transparencia y el cumplimiento de las obligaciones fiscales. • Administradores de la Cooperativa: Personas responsables de la gestión general de la cooperativa y supervisión del sistema. • Desarrolladores del Sistema: El equipo de desarrollo encargado de diseñar, construir y mantener el sistema informático. 30 4.1.4 Historias de Usuario A continuación, se presenta un resumen de las historias de usuarios el documento completo se encuentra en el Anexo 1 Tabla 1: Resumen historias de usuario ID Nombre Descripción Prioridad XS-9 Gestionar el inicio de sesión. Como usuario, quiero implementado un módulo eficiente para la gestión del inicio de sesión, asegurando la autenticación segura y autorización adecuada de los usuarios. Alta XS-14 Gestionar recuperación contraseña. Como usuario, quiero restablecer mi contraseña de manera segura en caso de olvido. Media XS-19 Gestionar Socios. Como contador, quiero ser capaz de gestionar la información de los socios. Alta XS-41 Gestión de Carrocerías. Como Administrador, quiero realizar un seguimiento detallado de la configuración de asientos en cada vehículo. Esto incluye el número de asientos, su disposición y ubicación en la carrocería. Alta XS-20 Gestionar Vehículos. Como Administrador, quiero gestionar la Alta 31 información esencial para cada unidad de transporte. XS-42 Gestión de Conductores. Como Administrador, quiero una herramienta de control que me permita registrar de manera efectiva la información clave asociada a cada conductor en los buses. Alta XS-34 Gestión de Frecuencias. Como Administrador, quiero que me permita organizar de los horarios de los vehículos, la herramienta debe ser capaz de manejar información detallada sobre las frecuencias de salida y llegada. Alta XS-36 Gestión de Rutas. Como Administrador, quiero una herramienta que me permita gestionar las rutas aprobadas por el ant. Alta XS-21 Gestión plan de cuentas contables. Como contador, quiero crear, editar o eliminar las cuentas contables del sistema. Media 32 XS-22 Gestión Asientos contables. Como Contador, quiero un sistema que permita la gestión eficiente de asientos contables, Para mantener un seguimiento preciso de las transacciones financieras y generar informes financieros fiables. Media XS-23 Reporte de Mayores. Como Contador, quiero un sistema que permita la gestión eficiente de asientos contables, para mantener un seguimiento preciso de las transacciones financieras y generar informes financieros fiables. Media XS-45 Implementar Facturación Electrónica. Como Contador, quiero que el sistema emita la facturación electrónica de acuerdo con la normativa vigente del SRI. Media XS-32 Venta de boletos. Como oficinista quiero realizar la venta de los boletos de una manera eficiente. Alta Realizado por: Eduardo G & Melanin G 33 4.1.5 Backlog Tabla 2: Backlog Código Incidencia Estado XS-9 Gestionar el inicio de sesión. Finalizada XS-14 Gestionar recuperación contraseña. Finalizada XS-19 Gestionar Socios. Finalizada XS-41 Gestión de Carrocerías. Finalizada XS-20 Gestionar Vehículos. Finalizada XS-42 Gestión de Conductores. Finalizada XS-34 Gestión de Frecuencias. Finalizada XS-36 Gestión de Rutas. Finalizada XS-21 Gestión plan de cuentas contables. Finalizada XS-22 Gestión Asientos contables. Finalizada XS-23 Reporte de Mayores. Finalizada XS-45 Implementar Facturación Electrónica. Finalizada XS-32 Venta de boletos. Finalizada Realizado por: Eduardo G & Melanin G 34 4.1.6 Plan de pruebas 4.1.6.1 Objetivo de las pruebas • Validar la correcta implementación de las reglas de negocio definidas en el dominio. • Asegurar la integración adecuada entre los diferentes componentes del sistema. • Verificar que las historias de usuario cumplan con los criterios de aceptación establecidos. 4.1.6.2 Alcance de las pruebas • Pruebas unitarias se aplicó a los casos de uso. • Pruebas de integración para validar la comunicación entre las capas del sistema. • Pruebas de integración con elementos externos al sistema. • Pruebas de aceptación del usuario para validar las historias implementadas. 4.1.6.3 Criterios de Aceptación • Todas las pruebas unitarias deben pasar satisfactoriamente. • Todas las historias de usuario deben pasar las pruebas de aceptación. • Las pruebas de integración deben demostrar la comunicación correcta entre las capas. • No se deben incluir librerías sin soporte y desactualizadas. 4.1.6.4 Procedimientos de las pruebas • Las pruebas unitarias, integración y aceptación deberán pasar a nivel de desarrollo. • Las pruebas unitarias, integración, aceptación análisis de código estático se analizar una vez que se envíen los cambios al repositorio, en el caso de no pasar no se aprobara el merge request. 35 4.2 Diseño 4.2.1 Arquitectura de Microservicios La arquitectura de microservicios orientada a eventos es un enfoque arquitectónico que se centra en la comunicación asíncrona y la interacción basada en eventos entre los distintos componentes de un sistema. En contraste con los modelos tradicionales basados en solicitudes y respuestas, donde los componentes se comunican de manera síncrona, la arquitectura orientada a eventos permite una mayor flexibilidad, escalabilidad y desacoplamiento entre los servicios. En la Figura 13 se observa la arquitectura implementada en el proyecto. Esta arquitectura cuenta con un balanceador de carga que dirige el tráfico tanto al servicio de frontend a través del endpoint "/" como al servicio de backend mediante el endpoint "/graphql". El servicio backend se comunica con el API Gateway, implementado con NestJS, cuya función es centralizar la comunicación con los microservicios, además de gestionar la autenticación y autorización. Los microservicios están ubicados en una zona segura, donde se asume que las solicitudes entrantes están debidamente autenticadas y autorizadas. Además, estos microservicios se comunican con el servicio de configuración centralizada (config- service) desarrollado con Spring Config Service, que obtiene la configuración alojada en GitLab. Es importante mencionar que cada microservicio genera eventos de dominio, los cuales se envían y reciben a través de una cola de mensajería implementada en RabbitMQ. Figura 13: Arquitectura de Microservicios Realizado por: Eduardo G & Melanin G 36 4.2.2 Definición de Microservicios • Servicio de Usuarios.- Este servicio se encarga de gestionar la información relacionada con los usuarios del sistema. Incluye funcionalidades como registro de usuarios, autenticación, gestión de roles y permisos. • Servicio de Contabilidad.- Este servicio se dedica a la gestión contable de la cooperativa. • Servicio de gestión de buses y boletos.- Este servicio está orientado a la gestión operativa de los autobuses de la cooperativa. Incluye funciones como programación de rutas, asignación de conductores y buses a rutas específicas, la venta de boletos de transporte. • Servicio de facturación electrónica.- Este servicio se encarga de la emisión de facturas electrónicas por los servicios de transporte prestados. Incluye funciones como la generación y envío de facturas electrónicas a los clientes, además cumple con la normativa establecida por el Servicio de Rentas Internas de Ecuador. 4.2.3 Comunicación entre microservicios La comunicación entre los distintos servicios se facilita mediante RabbitMQ, donde los servicios actúan como productores de eventos al publicar mensajes relevantes en colas específicas, y otros servicios, actuando como consumidores, se suscriben a estas colas para recibir y procesar los mensajes cuando estén disponibles, permitiendo una comunicación asíncrona y confiable que mejora la flexibilidad, escalabilidad y robustez del sistema. Figura 14: Comunicación entre microservicios Fuente: Comunicación de microservicios tomado de (Green, 2022) 37 A continuación, se muestra el código fuente para implementar y configurar los publicadores y consumidores en springboot con rabbitmq. RabbitMqDomainEventsConsumer.java package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; import com.devsoftec.xyphire.auth.shared.domain.Service; import com.devsoftec.xyphire.auth.shared.domain.Utils; import com.devsoftec.xyphire.auth.shared.domain.bus.event.DomainEven t; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventJsonDeserializer; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventSubscribersInformation; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessagePropertiesBuilder; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.listener.AbstractMessageListe nerContainer; import org.springframework.amqp.rabbit.listener.RabbitListenerEndpoi ntRegistry; import org.springframework.context.ApplicationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @Service public final class RabbitMqDomainEventsConsumer { private final String CONSUMER_NAME = "domain_events_consumer"; private final int MAX_RETRIES = 2; private final DomainEventJsonDeserializer deserializer; 38 private final ApplicationContext context; private final RabbitMqPublisher publisher; private final HashMap domainEventSubscribers = new HashMap<>(); RabbitListenerEndpointRegistry registry; private DomainEventSubscribersInformation information; public RabbitMqDomainEventsConsumer( RabbitListenerEndpointRegistry registry, DomainEventSubscribersInformation information, DomainEventJsonDeserializer deserializer, ApplicationContext context, RabbitMqPublisher publisher ) { this.registry = registry; this.information = information; this.deserializer = deserializer; this.context = context; this.publisher = publisher; } public void consume() { AbstractMessageListenerContainer container = (AbstractMessageListenerContainer) registry.getListenerContainer( CONSUMER_NAME ); container.addQueueNames(information.rabbitMqFormatted Names()); container.start(); } @RabbitListener(id = CONSUMER_NAME, autoStartup = "false") public void consumer(Message message) throws Exception { String serializedMessage = new String(message.getBody()); DomainEvent domainEvent = deserializer.deserialize(serializedMessage); String queue = message.getMessageProperties().getConsumerQueue(); Object subscriber = domainEventSubscribers.containsKey(queue) 39 ? domainEventSubscribers.get(queue) : subscriberFor(queue); Method subscriberOnMethod = subscriber.getClass().getMethod("on", domainEvent.getClass()); try { subscriberOnMethod.invoke(subscriber, domainEvent); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException error) { throw new Exception(String.format( "The subscriber <%s> should implement a method `on` listening the domain event <%s>", queue, domainEvent.eventName() )); } catch (Exception error) { handleConsumptionError(message, queue); } } private void handleConsumptionError(Message message, String queue) { if (hasBeenRedeliveredTooMuch(message)) { sendToDeadLetter(message, queue); } else { sendToRetry(message, queue); } } private void sendToRetry(Message message, String queue) { sendMessageTo(RabbitMqExchangeNameFormatter.retry("do main_events"), message, queue); } private void sendToDeadLetter(Message message, String queue) { sendMessageTo(RabbitMqExchangeNameFormatter.deadLette r("domain_events"), message, queue); } private void sendMessageTo(String exchange, Message message, String queue) { Map headers = message.getMessageProperties().getHeaders(); 40 headers.put("redelivery_count", (int) headers.getOrDefault("redelivery_count", 0) + 1); MessageBuilder.fromMessage(message).andProperties( MessagePropertiesBuilder.newInstance() .setContentEncoding("utf-8") .setContentType("application/json") .copyHeaders(headers) .build()); publisher.publish(message, exchange, queue); } private boolean hasBeenRedeliveredTooMuch(Message message) { return (int) message.getMessageProperties().getHeaders().getOrDefault("red elivery_count", 0) >= MAX_RETRIES; } public void withSubscribersInformation(DomainEventSubscribersInformation information) { this.information = information; } private Object subscriberFor(String queue) throws Exception { String[] queueParts = queue.split("\\."); String subscriberName = Utils.toCamelFirstLower(queueParts[queueParts.length - 1]); try { Object subscriber = context.getBean(subscriberName); domainEventSubscribers.put(queue, subscriber); return subscriber; } catch (Exception e) { throw new Exception(String.format("There are not registered subscribers for <%s> queue", queue)); } } } 41 Este código implementa un consumidor de eventos de dominio basado en RabbitMQ en Java utilizando Spring AMQP. El consumidor está diseñado para manejar mensajes de eventos de dominio que son publicados en colas específicas en RabbitMQ. Utiliza un deserializador para convertir los mensajes JSON en objetos de eventos de dominio y luego los enruta a los suscriptores correspondientes basados en el nombre de la cola. Además, el consumidor maneja la lógica de reintento y envío a la cola de dead-letter en caso de errores durante el procesamiento del evento. También proporciona métodos para iniciar el consumo de eventos y configurar la información de los suscriptores. RabbitMqEventBusConfiguration.java package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventSubscribersInformation; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventsInformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.*; import org.springframework.amqp.rabbit.connection.CachingConnectionF actory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @Configuration public class RabbitMqEventBusConfiguration { private final DomainEventSubscribersInformation domainEventSubscribersInformation; 42 private final DomainEventsInformation domainEventsInformation; private final Logger logger = LoggerFactory.getLogger(RabbitMqEventBusConfiguration.class); //RabbitMq Variables @Value("${rabbitmq.host}") private String rabbitmqHost; @Value("${rabbitmq.port}") private String rabbitmqPort; @Value("${rabbitmq.login}") private String rabbitmqLogin; @Value("${rabbitmq.password}") private String rabbitmqPassword; @Value("${rabbitmq.vhost}") private String rabbitmqVhost; @Value("${rabbitmq.exchange}") private String exchangeName; public RabbitMqEventBusConfiguration( DomainEventSubscribersInformation domainEventSubscribersInformation, DomainEventsInformation domainEventsInformation ) { this.domainEventSubscribersInformation = domainEventSubscribersInformation; this.domainEventsInformation = domainEventsInformation; } @Bean public CachingConnectionFactory connection() { logger.info("RabbitMQ connection created"); CachingConnectionFactory factory = new CachingConnectionFactory(); factory.setHost(rabbitmqHost); factory.setPort(Integer.parseInt(rabbitmqPort)); factory.setUsername(rabbitmqLogin); factory.setPassword(rabbitmqPassword); factory.setVirtualHost(rabbitmqVhost); return factory; } @Bean public Declarables declaration() { 43 String retryExchangeName = RabbitMqExchangeNameFormatter.retry(exchangeName); String deadLetterExchangeName = RabbitMqExchangeNameFormatter.deadLetter(exchangeName); TopicExchange domainEventsExchange = new TopicExchange(exchangeName, true, false); TopicExchange retryDomainEventsExchange = new TopicExchange(retryExchangeName, true, false); TopicExchange deadLetterDomainEventsExchange = new TopicExchange(deadLetterExchangeName, true, false); List declarables = new ArrayList<>(); declarables.add(domainEventsExchange); declarables.add(retryDomainEventsExchange); declarables.add(deadLetterDomainEventsExchange); Collection queuesAndBindings = declareQueuesAndBindings( domainEventsExchange, retryDomainEventsExchange, deadLetterDomainEventsExchange ).stream().flatMap(Collection::stream).collect(Collec tors.toList()); declarables.addAll(queuesAndBindings); return new Declarables(declarables); } private Collection> declareQueuesAndBindings( TopicExchange domainEventsExchange, TopicExchange retryDomainEventsExchange, TopicExchange deadLetterDomainEventsExchange ) { return domainEventSubscribersInformation.all().stream().map(informat ion -> { String queueName = RabbitMqQueueNameFormatter.format(information); String retryQueueName = RabbitMqQueueNameFormatter.formatRetry(information); String deadLetterQueueName = RabbitMqQueueNameFormatter.formatDeadLetter(information); Queue queue = QueueBuilder.durable(queueName).build(); 44 Queue retryQueue = QueueBuilder.durable(retryQueueName).withArguments( retryQueueArguments(domainEventsExchange, queueName) ).build(); Queue deadLetterQueue = QueueBuilder.durable(deadLetterQueueName).build(); Binding fromExchangeSameQueueBinding = BindingBuilder .bind(queue) .to(domainEventsExchange) .with(queueName); Binding fromRetryExchangeSameQueueBinding = BindingBuilder .bind(retryQueue) .to(retryDomainEventsExchange) .with(queueName); Binding fromDeadLetterExchangeSameQueueBinding = BindingBuilder .bind(deadLetterQueue) .to(deadLetterDomainEventsExchange) .with(queueName); List fromExchangeDomainEventsBindings = information.subscribedEvents().stream().map( domainEventClass -> { String eventName = domainEventsInformation.forClass(domainEventClass); return BindingBuilder .bind(queue) .to(domainEventsExchange) .with(eventName); }).collect(Collectors.toList()); List queuesAndBindings = new ArrayList<>(); queuesAndBindings.add(queue); queuesAndBindings.add(fromExchangeSameQueueBindin g); queuesAndBindings.addAll(fromExchangeDomainEvents Bindings); queuesAndBindings.add(retryQueue); 45 queuesAndBindings.add(fromRetryExchangeSameQueueB inding); queuesAndBindings.add(deadLetterQueue); queuesAndBindings.add(fromDeadLetterExchangeSameQ ueueBinding); return queuesAndBindings; }).collect(Collectors.toList()); } private HashMap retryQueueArguments(TopicExchange exchange, String routingKey) { return new HashMap() {{ put("x-dead-letter-exchange", exchange.getName()); put("x-dead-letter-routing-key", routingKey); put("x-message-ttl", 1000); }}; } } Este código Java configura la conexión a RabbitMQ y declara los elementos necesarios, como intercambios y colas, para establecer un bus de eventos en una aplicación. Utiliza Spring AMQP para gestionar la comunicación asíncrona entre los componentes, permitiendo el enrutamiento y procesamiento eficiente de mensajes de eventos de dominio en colas específicas, incluyendo reintentos y dead-letter queues para manejar errores y fallos en el procesamiento de eventos. 46 RabbitMqPublisher.java package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; import com.devsoftec.xyphire.auth.shared.domain.Service; import com.devsoftec.xyphire.auth.shared.domain.bus.event.DomainEven t; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventJsonSerializer; import org.springframework.amqp.AmqpException; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessagePropertiesBuilder; @Service public final class RabbitMqPublisher { private final RabbitTemplate rabbitTemplate; public RabbitMqPublisher(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } public void publish(DomainEvent domainEvent, String exchangeName) throws AmqpException { String serializedDomainEvent = DomainEventJsonSerializer.serialize(domainEvent); Message message = new Message( serializedDomainEvent.getBytes(), MessagePropertiesBuilder.newInstance() .setContentEncoding("utf-8") .setContentType("application/json") .build() ); rabbitTemplate.send(exchangeName, domainEvent.eventName(), message); } public void publish(Message domainEvent, String exchangeName, String routingKey) throws AmqpException { 47 rabbitTemplate.send(exchangeName, routingKey, domainEvent); } } Este código Java implementa un publicador para el bus de eventos en RabbitMQ utilizando Spring AMQP. El publicador se encarga de enviar mensajes de eventos de dominio a un intercambio específico en RabbitMQ. Utiliza un RabbitTemplate proporcionado por Spring para enviar los mensajes, y serializa los eventos de dominio en formato JSON antes de enviarlos. Además, proporciona métodos para publicar mensajes utilizando un intercambio y clave de enrutamiento específicos, lo que permite una mayor flexibilidad en la configuración de la comunicación entre los componentes del sistema. RabbitMqEventBus.java package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; import com.devsoftec.xyphire.auth.shared.domain.Service; import com.devsoftec.xyphire.auth.shared.domain.bus.event.DomainEven t; import com.devsoftec.xyphire.auth.shared.domain.bus.event.EventBus; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ma riadb.MariaDBEventBus; import org.springframework.amqp.AmqpException; import org.springframework.context.annotation.Primary; import java.util.Collections; import java.util.List; @Service @Primary public class RabbitMqEventBus implements EventBus { private final RabbitMqPublisher publisher; private final MariaDBEventBus failoverPublisher; private final String exchangeName; 48 public RabbitMqEventBus(RabbitMqPublisher publisher, MariaDBEventBus failoverPublisher) { this.publisher = publisher; this.failoverPublisher = failoverPublisher; this.exchangeName = "domain_events"; } @Override public void publish(List events) { events.forEach(this::publish); } private void publish(DomainEvent domainEvent) { try { this.publisher.publish(domainEvent, exchangeName); } catch (AmqpException error) { failoverPublisher.publish(Collections.singletonLi st(domainEvent)); } } } Este código Java implementa un bus de eventos utilizando RabbitMQ como mecanismo principal de comunicación. La clase `RabbitMqEventBus` implementa la interfaz `EventBus` y utiliza un `RabbitMqPublisher` para publicar eventos en un intercambio específico en RabbitMQ. En caso de que ocurra un error al publicar un evento, como una excepción de AmqpException, el bus de eventos realiza un failover utilizando un `MariaDBEventBus`, que es otro mecanismo de publicación de eventos basado en MariaDB. Esto garantiza una mayor robustez y resiliencia en la comunicación de eventos dentro del sistema. La anotación `@Primary` indica que esta implementación del bus de eventos es la principal en caso de que haya varias implementaciones disponibles. 49 RabbitMqExchangeNameFormatter.java, RabbitMqQueueNameFormatter.java package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; public final class RabbitMqExchangeNameFormatter { public static String retry(String exchangeName) { return String.format("retry-%s", exchangeName); } public static String deadLetter(String exchangeName) { return String.format("dead_letter-%s", exchangeName); } } package com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.ra bbitmq; import com.devsoftec.xyphire.auth.shared.infrastructure.bus.event.Do mainEventSubscriberInformation; public final class RabbitMqQueueNameFormatter { public static String format(DomainEventSubscriberInformation information) { return information.formatRabbitMqQueueName(); } public static String formatRetry(DomainEventSubscriberInformation information) { return String.format("retry.%s", format(information)); } public static String formatDeadLetter(DomainEventSubscriberInformation information) { return String.format("dead_letter.%s", format(information)); } } 50 Los primeros dos fragmentos de código Java presentan utilidades para formatear nombres de intercambio y cola en RabbitMQ. `RabbitMqExchangeNameFormatter` proporciona métodos estáticos para agregar prefijos a los nombres de intercambio, como "retry-" y "dead_letter-", mientras que `RabbitMqQueueNameFormatter` ofrece funciones para generar nombres de cola y sus variantes de reintentos y dead-letter, basándose en la información del suscriptor de eventos de dominio. Estas clases son útiles para establecer una convención de nomenclatura consistente en la configuración del bus de eventos de RabbitMQ. 4.2.4 Arquitectura del Software La arquitectura hexagonal, es un estilo de diseño de software que busca crear sistemas más mantenibles, flexibles y testables.