Designing Cohesive Microservices with Domain Driven Design

Designing Cohesive Microservices with Domain Driven Design

This article aims to provide a comprehensive overview of Domain Driven Design (DDD) applied to microservices architecture, emphasizing its significance in creating well-structured, cohesive, and loosely coupled distributed systems. In the rapidly evolving landscape of technology, understanding how to properly design microservices based on domain models is crucial for software architects and developers alike. This article will delineate the core concepts of DDD, practical applications in microservices design, and best practices in software architecture, helping readers to enhance their skills and make informed decisions when decomposing monolithic applications into microservices.

The main focus is on the importance of understanding the problem domain first, creating a solid domain model, and then designing microservices that align with business boundaries rather than technical concerns. We demonstrate these principles through a practical Tic-Tac-Toe game implementation that showcases how proper domain modeling leads to better service cohesion and appropriate coupling levels.

Repository

If you want to reproduce this tic-tac-toe example in your computer you can clone this repository:

Repository URL: https://github.com/moroquin/Tictactoe-Microservices-eureka

Environment Requirements

To execute this repository effectively, ensure you have the following environment and software requirements in place:

  • Programming Language: Java 21
  • Frameworks and Libraries:
    • Spring Boot 3.4.0
    • Spring Cloud 2024.0.2
    • Netflix Eureka for service discovery
    • OpenTelemetry for distributed tracing
    • LangChain4j for AI integration
    • React for frontend
  • Environment Variables:
    • OPENAI_API_KEY_SECRET: API key from OpenAI for LangChain4j to connect to AI model
  • Dependencies:
    • Docker (v20.10 or higher)
    • Docker Compose (v2.0 or higher)
    • Maven 3.9+ (for local development)
    • Node.js 16+ (for frontend development)

Build information are in the readme.md file in the repository.

Key Concepts

This section covers essential concepts and methodologies relevant to Domain Driven Design and microservices architecture:

  • Ubiquitous Language: A common vocabulary shared between domain experts and developers, ensuring clear communication and reducing misunderstandings in the development process.
  • Domain Model: A conceptual model that captures the essential business logic and rules of the problem domain, serving as the foundation for microservice boundaries.
  • Microservices: An architectural pattern that structures an application as a collection of loosely coupled, independently deployable services organized around business capabilities.
  • Cohesion: The degree to which elements within a microservice work together toward a common purpose, with high cohesion being desirable for maintainability.
  • Afferent Coupling: The number of external services that depend on a particular service, indicating incoming dependencies.
  • Efferent Coupling: The number of external services that a particular service depends on, indicating outgoing dependencies.
  • Spring Boot: A framework that simplifies the development of production-ready applications with embedded servers and auto-configuration.

Methodology: Domain Driven Design (DDD) – A software development approach that focuses on modeling software to match the business domain.

Architectural Patterns: Microservices Architecture with Model-View-Controller (MVC) pattern for each individual service.

Case study

In this section, we explore a Tic-Tac-Toe game implementation that illustrates the practical application of Domain Driven Design principles in microservices architecture. The case study demonstrates how to decompose a simple game into well-defined microservices based on domain boundaries rather than technical layers.

The project consists of a distributed Tic-Tac-Toe game with multiple game modes (Human vs Human, Human vs Computer, Computer vs Computer), implemented using Spring Boot microservices with service discovery, distributed tracing, and a React frontend.

Diagram Model

Concept

It is important to use the vocabulary defined in the domain model to describe the problem: Tic-tac-toe is a game that consists of a board, two players, and a series of turns. The board is made up of a 3×3 matrix of squares, where each square can be marked as X, O, or left empty. Each player has specific goals: the first goal is to win by placing three marks in a row, either horizontally, vertically, diagonally, or in an inverse diagonal; the second goal is to block or prevent the other player from winning. The turn mechanism handles the game logic and is responsible for alternating turns and managing the overall flow of the game.

From this model, we can identify four important subdomains:

  • Board: This subdomain manages everything related to the game board, including the placement of marks and checking whether a player’s turn is valid. It also determines if the game is over and who the winner is.
  • Player: Players use the board to observe the game and decide where to place their mark during their turn. It is essential for players to consider their goals when making their decisions.
  • Turns: This subdomain is responsible for alternating player turns. It prompts a player for the coordinates of their move and checks with the board to verify if the chosen coordinates are valid. While checking the validity of the coordinates is the board’s responsibility, the turn mechanism must confirm whether the coordinates are correct before proceeding to the next player or asking the same player for a valid move if the coordinates are incorrect.
  • Game: The game acts as an API gateway that calls all the subdomains to manage the entire logic of the game.

This structure demonstrates that we have cohesive subdomains with well-defined responsibilities, ensuring that each subdomain performs its designated tasks effectively. Additionally, the coupling is appropriate, as communication occurs only as needed while maintaining cohesion among the subdomains.

Project Development

The project was designed following Domain Driven Design principles with the following approach:

  1. Domain Analysis: First, we analyzed the Tic-Tac-Toe game domain to identify core business concepts and their relationships.
  2. Domain Model Creation: We created a domain model that captures the essential entities and their interactions:
  • Game: Orchestrates the overall game flow
  • Board: Manages the game state and board positions
  • Player: Handles player information and types (Human/Computer)
  • Turn: Manages turn validation and move execution
  1. Service Boundaries: Based on the domain model, we identified natural service boundaries that align with business capabilities rather than technical concerns.
  2. Architecture Design: We implemented a microservices architecture with:

The design emphasizes high cohesion within services and appropriate coupling between services, following DDD principles to ensure each microservice has a clear responsibility aligned with the domain model.

In the follow image you can see jaeger showing the calls in each microservice

Testing the Project

The testing strategy for this project utilizes Postman for comprehensive API testing across all microservices:

  • Postman Collection: postman/tictactoe.postman_collection.json contains pre-configured requests for testing each microservice endpoint
  • Service Testing: Each microservice can be tested individually using the provided Postman collection
  • Integration Testing: The collection includes workflows that test the complete game flow across multiple services
  • Distributed Tracing: Use Jaeger UI (http://localhost:16686) to monitor request flows and identify performance bottlenecks

To test the project:

  1. Import the Postman collection from postman/tictactoe.postman_collection.json
  2. Ensure all services are running via Docker Compose
  3. Execute the test requests to validate individual service functionality
  4. Monitor distributed traces in Jaeger for end-to-end request analysis

Recommendations

Based on the implementation of this Domain Driven Design microservices project, here are key best practices and recommendations:

  • Domain-First Approach: Always start by understanding the problem domain thoroughly before proposing technical solutions. Invest time in domain analysis and modeling before writing code.
  • Proper Service Boundaries: Design microservices based on domain boundaries and business capabilities, not technical layers. Each service should have high cohesion and represent a distinct business concept.
  • Balanced Coupling: Strive for appropriate levels of afferent and efferent coupling. Services should be loosely coupled but still able to collaborate effectively to fulfill business requirements.
  • Service Discovery: Implement proper service discovery mechanisms (like Eureka) to enable dynamic service location and improve system resilience.
  • Distributed Tracing: Use distributed tracing tools (like Jaeger) to monitor request flows across services, identify bottlenecks, and debug issues in distributed systems.
  • Containerization: Leverage Docker and Docker Compose for consistent development and deployment environments across different stages.
  • API-First Design: Design clear, well-documented APIs that serve as contracts between services, enabling independent development and testing.
  • Monitoring and Observability: Implement comprehensive logging, metrics, and health checks to ensure system visibility and maintainability.

Finally, emphasize the importance of continuous learning and adaptation to new technologies and methodologies in the field of software architecture. Domain Driven Design principles remain relevant as systems evolve, but the tools and patterns for implementing them continue to advance.

By following this structured approach to Domain Driven Design in microservices, readers will gain a thorough understanding of how to create well-architected distributed systems that align with business domains, leading to more maintainable, scalable, and understandable software solutions.

moroquin Avatar