======= Delivering Domain Events in MSA: Applicable Design Patterns ======= prepared by student of HSE Software Engineering Master Program Rogoza Kirill (karogoza@edu.hse.ru) ===== Introduction ===== Microservices Architecture (MSA) has fundamentally transformed software engineering by enabling the creation of scalable, resilient, and maintainable applications through the decomposition of monolithic systems into loosely coupled, independently deployable services [1]. This architectural paradigm empowers organizations to innovate swiftly, scale individual components according to demand, and enhance fault isolation, thereby boosting overall system robustness. Central to MSA’s effectiveness is the management and delivery of domain events, which encapsulate significant changes or actions within a business domain and facilitate seamless inter-service communication. Domain events are pivotal for event-driven communication in microservices, allowing services to react to and propagate changes asynchronously. Effective event delivery is essential for maintaining data consistency, ensuring system reliability, and achieving real-time responsiveness. However, the distributed nature of microservices introduces challenges such as reliable event delivery, event ordering, schema evolution, and maintaining eventual consistency across services [2]. Addressing these challenges requires robust design patterns that enhance the reliability and efficiency of domain event delivery within MSA. This essay examines the applicable design patterns for delivering domain events in Microservices Architecture, evaluating their strengths and limitations to provide a comprehensive understanding of how these patterns can effectively overcome the inherent challenges of event delivery in distributed systems. ===== Design Patterns Review ===== Delivering domain events in Microservices Architecture (MSA) involves addressing challenges inherent to distributed systems, such as ensuring scalability, reliability, and maintainability. This review synthesizes contemporary research on three pivotal design patterns: Event Sourcing, Publish-Subscribe (Pub/Sub), and Command Query Responsibility Segregation (CQRS). Each pattern offers unique solutions to facilitate robust event delivery within microservices ecosystems. === Event Sourcing === Event Sourcing is a design pattern where state changes in an application are captured as a sequence of events . Instead of storing only the current state, every change is recorded, enabling the reconstruction of past states and providing a comprehensive audit trail. According to Fowler (2005)[3], Event Sourcing enhances system transparency and facilitates debugging and auditing processes by maintaining a history of all state transitions: {{:arch:2024:event_sourcing.png?400|}} **Figure 1**. Using an event to capture the change example [3]. Overeem et al. (2021)[4] conducted an in-depth empirical study to analyze Event Sourced Systems (ESSs) and their approach to schema evolution in real-world scenarios. Through interviews with 25 experienced engineers, the research revealed that Event Sourcing significantly enhances fault tolerance and scalability by separating the write and read models. This separation allows systems to efficiently manage high-throughput event streams, contributing to overall system resilience and performance. Despite these complexities, Event Sourcing remains a vital pattern for developing scalable and resilient microservices. The findings from Overeem et al. provide valuable insights into both the benefits and the operational challenges of adopting Event Sourcing, offering practical strategies for managing schema evolution and ensuring system robustness. === Publish-Subscribe (Pub/Sub) Pattern === The Publish-Subscribe (Pub/Sub) pattern decouples event producers (publishers) from event consumers (subscribers) through an intermediary, typically a message broker or event bus. This decoupling enhances scalability, flexibility, and maintainability within distributed systems. Hohpe (2003)[5] identifies the Pub/Sub pattern as essential for building scalable and resilient enterprise integration solutions. By utilizing message brokers such as Apache Kafka, RabbitMQ, or Google Cloud Pub/Sub, systems can efficiently manage high-throughput event streams and facilitate real-time data processing. This setup enables multiple consumers to process events concurrently, promoting horizontal scalability and improved fault tolerance: {{:arch:2024:pub_sub_pattern.png?400|}} **Figure 2.** How can sender broadcast an event to all interested receivers?[5] However, implementing the Pub/Sub pattern introduces challenges related to message ordering, delivery guarantees, and system complexity. Ensuring reliable and ordered message delivery is crucial for maintaining data consistency across services. Techniques like idempotent message processing and sequence numbers can mitigate these issues [6]. Additionally, managing the infrastructure of message brokers requires careful planning to prevent them from becoming single points of failure or performance bottlenecks. Nonetheless, the Pub/Sub pattern remains a foundational design choice for modern distributed systems. Its ability to facilitate asynchronous communication, support real-time data processing, and enhance system scalability makes it indispensable for building robust microservices ecosystems across various domains, including financial services and e-commerce applications. === Command Query Responsibility Segregation (CQRS) Pattern === The Command Query Responsibility Segregation (CQRS) pattern is an architectural approach that distinctly separates the operations which modify data (commands) from those that retrieve data (queries). This separation allows each side to be optimized independently, enhancing both performance and scalability within MSA. By decoupling the read and write models, CQRS facilitates more efficient handling of complex business logic and varying workloads, which is particularly beneficial in distributed systems. According to the .NET Architecture documentation on applying simplified CQRS and Domain-Driven Design (DDD) patterns in microservices [7] CQRS integrates seamlessly with DDD, allowing developers to focus on domain-specific logic within commands while maintaining efficient query models. This integration supports the creation of a rich domain model that accurately reflects business processes, enhancing the overall maintainability and adaptability of the system. By leveraging CQRS, microservices can independently scale their read and write operations, ensuring that each can handle specific demands without bottlenecking the other: {{:arch:2024:cqrs.png?400|}} **Figure 3.** An example of microservice based on a simplified CQRS approach [7] Adopting the CQRS pattern introduces challenges related to system complexity and eventual consistency. Maintaining separate models for commands and queries requires additional infrastructure to synchronize data between the two, often necessitating robust messaging or event-handling mechanisms to ensure that changes are accurately reflected across both sides. Additionally, the asynchronous nature of CQRS can lead to scenarios where the read model lags behind the write model, requiring careful handling to manage data consistency and user expectations. CQRS`s ability to optimize read and write operations independently, coupled with its support for complex business logic through DDD, makes it an indispensable tool in modern software architecture. ===== Conclusion ===== Microservices Architecture (MSA) significantly enhances the scalability, resilience, and maintainability of software systems by decomposing monolithic applications into independent services. Central to maximizing the benefits of MSA is the effective management and delivery of domain events, which facilitate seamless communication and ensure data consistency across services. This essay reviewed three pivotal design patterns — Event Sourcing, Publish-Subscribe (Pub/Sub), and Command Query Responsibility Segregation (CQRS)—each offering unique solutions to the challenges of event delivery in distributed systems. By understanding and effectively implementing these patterns, organizations can overcome the inherent challenges of distributed systems, ensuring reliable and efficient event-driven communication that supports dynamic and evolving business requirements. ===== References ===== 1. Newman, S., 2015. Building Microservices. O'Reilly Media. https://www.oreilly.com/library/view/building-microservices/9781491950340/ 2. Evans, E. (2004). Domain-driven design: tackling complexity in the heart of software. Addison-Wesley, Boston. https://www.semanticscholar.org/paper/Domain-driven-design-tackling-complexity-in-the-of/09a22ed7bd58677f466d54173a4139696e456002 3. Fowler, M., 2005. Event Sourcing. Retrieved from https://martinfowler.com/eaaDev/EventSourcing.html 4.Overeem, M., Spoor, M., Jansen, S., & Brinkkemper, S. (2021). An Empirical Characterization of Event Sourced Systems and Their Schema Evolution - Lessons from Industry. Journal of Systems and Software, 178, 110970. https://www.semanticscholar.org/paper/An-Empirical-Characterization-of-Event-Sourced-and-Overeem-Spoor/664ddaf9f7abaf1b749a0f06a9908dcf11fbed75 5.Hohpe, G. (2003). Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. Addison-Wesley Professional. https://www.enterpriseintegrationpatterns.com/patterns/conversation/ 6.Jeffrey Dean and Sanjay Ghemawat. 2008. MapReduce: simplified data processing on large clusters. Commun. ACM 51, 1 (January 2008), 107–113. https://doi.org/10.1145/1327452.1327492 7.NET architecture documentation. Apply simplified CQRS and DDD patterns in a microservice. https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/apply-simplified-microservice-cqrs-ddd-patterns