Microservices Approach and Domain-Driven Design

Microservices Approach: Introduction

  • The growth of an application's features often leads to its expansion into a large single deployment unit, a concept known as a "monolith".

  • A microservices architecture develops an application as a collection of small services, each running in its own process and communicating via lightweight mechanisms using an HTTP-based API.

Comparing Microservices and Monolithic Architecture

  • Typically, enterprise applications are built in three parts:

    • User Interface

    • Database

    • Monolithic application, hosting all components on a server handling HTTP requests.

  • Over time, the application tends to grow, becoming a large monolithic structure consisting of many components within a single deployable unit.

Problems with Monolithic Applications

  • Evolution of the application becomes challenging (testing, rebuilding, scaling).

  • Key issues include:

    • Difficulty in scaling individual components (especially in terms of memory footprint).

    • Performance bottlenecks: the application's performance often depends on the slowest component.

    • Challenges with deploying new versions of individual components.

    • Strong interdependencies among components lead to increased complexity in understanding and modifying the code.

    • Difficulty in conducting precise tests on the application.

Characteristics of Microservices Architecture

  • Decomposition: Breaking the application into smaller services based on their business domain.

  • Independence: Each microservice operates independently, having its own database and codebase.

  • Scalability: Each service can scale independently (e.g., deploying multiple instances).

  • Flexibility: Each service can be implemented using distinct technologies tailored to its needs.

  • Resilience: Failure in one service does not affect the overall system.

Benefits of Microservices Architecture

  • Agility: Teams can independently develop, test, and deploy services, speeding up the delivery of new features.

  • Increased Scalability: Services can be instantiated independently to handle increased loads.

  • Isolation of Failures: When correctly designed, the failure of one service does not propagate to others, minimizing the impact of errors.

  • Technology Diversification: Teams can choose the most suitable technology for each service.

  • Improved Maintenance: Smaller codebases with well-defined boundaries simplify maintenance and error correction, enabling more efficient development cycles.

Domain-Driven Design (DDD) Overview

  • Facilitates migration from a monolithic architecture to microservices using DDD principles, which focus on business domain understanding.

  • DDD relies on business terminology to build an understandable model for domain experts.

  • It comprises design patterns and methodologies to model the understanding of the domain where the application operates.

  • Key Element: The bounded context model, which separates a domain model into sub-parts that manage their dependencies independently.

Core Ideas of DDD

  • The domain is the real problem or business area your software addresses (e.g., e-commerce, banking).

  • Ubiquitous Language: A shared and consistent language developed through collaboration between domain experts and developers.

  • Model-Driven Design: The software reflects a conceptual model of the domain, capturing its rules and processes.

  • Complexity Management: DDD is particularly beneficial for complex domains, helping to break down complexity into manageable parts without losing the overall perspective.

Key Building Blocks in DDD

  1. Entities: Objects identified by their identity rather than attributes.

    • Example: A customer with an ID remains the same entity even if their name or address changes.

  2. Value Objects: Objects without identity, defined solely by their attributes.

    • Example: An "address" (street, city, postal code).

  3. Aggregates: A cluster of related objects treated as a single unit.

    • Example: An aggregate order might include order items and a delivery address.

  4. Repositories: Mechanisms for storing and retrieving aggregates.

    • Example: A CustomerRepository to manage customer aggregates.

  5. Domain Services: Logic that does not fit naturally in an entity or value object.

  6. Bounded Contexts: Dividing a large domain into smaller, well-defined zones.

  7. Context Mapping: Defining relationships between bounded contexts.

DDD in Practice: Example of an Online Food Delivery Platform

  • Step 1: Define the domain (e.g., order management, restaurant management).

  • Step 2: Identify bounded contexts (e.g., order management, payment processing).

  • Step 3: Model entities, value objects, and aggregates for contexts (e.g., order entity).

  • Context Mapping connects contexts like restaurant management and order management using APIs or events.

General Architectural Principles for Microservices

  • Event-Driven Architecture (EDA): A microservice publishes an event each time something significant occurs. Services that receive these events can act on them, which may trigger further events.

  • Database Per Service: Each microservice has its database for autonomy and suitable tech choice.

  • API Gateway: A central service that routes client requests to the appropriate microservice.

  • CQRS (Command Query Responsibility Segregation): Separating read and write operations to optimize query performance.

  • Saga Pattern: A way to handle data consistency across multiple microservices without distributed transactions.

Development with NestJS for Microservices

  • NestJS facilitates microservices architecture via the @nestjs/microservices package, supporting TCP by default for persistent communication.

  • It allows for various message transport protocols (e.g., gRPC, RabbitMQ).

  • Message Patterns: Use decorators to handle specific message patterns, enabling organization of service communication.

Conclusion on Microservices

  • A microservices-based system can be understood through its messages and the services exchanging them.

  • New microservices can be developed through composition rather than modification of existing services.

  • Challenges exist, such as increased architectural complexity, necessary skill upgrades in teams, operational load, and ensuring that a single database does not become a contention point.

  • La croissance des fonctionnalités d'une application mène souvent à son expansion en une grande unité de déploiement unique, un concept connu sous le nom de "monolithe".

  • Une architecture de microservices développe une application comme une collection de petits services, chacun fonctionnant dans son propre processus et communiquant via des mécanismes légers utilisant une API basée sur HTTP.

Comparer les microservices et l'architecture monolithique
  • En général, les applications d'entreprise sont construites en trois parties :

    • Interface utilisateur

    • Base de données

    • Application monolithique, hébergeant tous les composants sur un serveur gérant les requêtes HTTP.

  • Au fil du temps, l'application a tendance à croître, devenant une grande structure monolithique composée de nombreux composants au sein d'une seule unité déployable.

Problèmes avec les applications monolithiques
  • L'évolution de l'application devient difficile (tests, reconstruction, mise à l'échelle).

  • Les problèmes clés incluent :

    • Difficulté à faire évoluer des composants individuels (en particulier en termes de consommation de mémoire).

    • Goulots d'étranglement de performance : les performances de l'application dépendent souvent du composant le plus lent.

    • Difficultés à déployer de nouvelles versions de composants individuels.

    • Fortes interdépendances entre les composants qui augmentent la complexité de compréhension et de modification du code.

    • Difficulté à réaliser des tests précis sur l'application.

Caractéristiques de l'architecture de microservices
  • Décomposition : Diviser l'application en services plus petits en fonction de leur domaine commercial.

  • Indépendance : Chaque microservice fonctionne indépendamment, ayant sa propre base de données et son propre code.

  • Scalabilité : Chaque service peut évoluer indépendamment (par exemple, déployer plusieurs instances).

  • Flexibilité : Chaque service peut être mis en œuvre en utilisant des technologies distinctes adaptées à ses besoins.

  • Résilience : Un échec dans un service n'affecte pas l'ensemble du système.

Avantages de l'architecture de microservices
  • Agilité : Les équipes peuvent développer, tester et déployer des services de manière indépendante, accélérant ainsi la livraison de nouvelles fonctionnalités.

  • Scalabilité accrue : Les services peuvent être instanciés indépendamment pour gérer des charges accrues.

  • Isolation des échecs : Lorsqu'il est bien conçu, l'échec d'un service ne se propage pas aux autres, minimisant l'impact des erreurs.

  • Diversification technologique : Les équipes peuvent choisir la technologie la plus appropriée pour chaque service.

  • Amélioration de la maintenance : Des bases de code plus petites avec des frontières bien définies simplifient la maintenance et la correction des erreurs, permettant des cycles de développement plus efficaces.

Vue d'ensemble du Design Axé sur le Domaine (DDD)
  • Facilite la migration d'une architecture monolithique vers des microservices en utilisant des principes de DDD, qui se concentrent sur la compréhension du domaine commercial.

  • DDD repose sur une terminologie commerciale pour construire un modèle compréhensible pour les experts du domaine.

  • Il comprend des modèles de conception et des méthodologies pour modéliser la compréhension du domaine dans lequel l'application opère.

  • Élément clé : Le modèle de contexte délimité, qui sépare un modèle de domaine en sous-parties qui gèrent leurs dépendances indépendamment.

Idées Clés de DDD
  • Le domaine est le véritable problème ou domaine commercial que votre logiciel aborde (par exemple, commerce électronique, banque).

  • Langage omniprésent : Un langage partagé et cohérent développé par la collaboration entre des experts du domaine et des développeurs.

  • Conception axée sur le modèle : Le logiciel reflète un modèle conceptuel du domaine, capturant ses règles et processus.

  • Gestion de la complexité : DDD est particulièrement bénéfique pour des domaines complexes, aidant à décomposer la complexité en parties gérables sans perdre la perspective d'ensemble.

Principaux éléments constitutifs de DDD
  1. Entités : Objets identifiés par leur identité plutôt que par leurs attributs.

    • Exemple : Un client avec un ID reste la même entité, même si son nom ou son adresse changent.

  2. Objets de valeur : Objets sans identité, définis uniquement par leurs attributs.

    • Exemple : Une "adresse" (rue, ville, code postal).

  3. Agrégats : Un ensemble d'objets liés traités comme une seule unité.

    • Exemple : Un agrégat commande pourrait inclure des articles de commande et une adresse de livraison.

  4. Référentiels : Mécanismes de stockage et de récupération des agrégats.

    • Exemple : Un ClientRepository pour gérer les agrégats clients.

  5. Services de domaine : Logique qui ne s'intègre pas naturellement dans une entité ou un objet de valeur.

  6. Contextes délimités : Division d'un grand domaine en zones plus petites et bien définies.

  7. Cartographie des contextes : Définir les relations entre les contextes délimités.

DDD en pratique : Exemple d'une plateforme de livraison de nourriture en ligne
  • Étape 1 : Définir le domaine (par exemple, gestion des commandes, gestion des restaurants).

  • Étape 2 : Identifier les contextes délimités (par exemple, gestion des commandes, traitement des paiements).

  • Étape 3 : Modéliser les entités, objets de valeur et agrégats pour les contextes (par exemple, entité de commande).

  • La cartographie des contextes connecte des contextes comme la gestion des restaurants et la gestion des commandes en utilisant des API ou des événements.

Principes architecturaux généraux pour les microservices
  • Architecture basée sur les événements (EDA) : Un microservice publie un événement chaque fois qu'un événement significatif se produit. Les services qui reçoivent ces événements peuvent agir en conséquence, ce qui peut déclencher d'autres événements.

  • Base de données par service : Chaque microservice a sa propre base de données pour l'autonomie et le choix de technologie approprié.

  • Passerelle API : Un service central qui route les requêtes des clients vers le microservice approprié.

  • CQRS (Séparation des responsabilités de commande et de requête) : Séparer les opérations de lecture et d'écriture pour optimiser les performances des requêtes.

  • Modèle Saga : Un moyen de gérer la cohérence des données entre plusieurs microservices sans transactions distribuées.

Développement avec NestJS pour les microservices
  • NestJS facilite l'architecture des microservices via le package @nestjs/microservices, prenant en charge TCP par défaut pour une communication persistante.

  • Il permet divers protocoles de transport de messages (par exemple, gRPC, RabbitMQ).

  • Modèles de messages : Utilisez des décorateurs pour gérer des modèles de messages spécifiques, permettant d'organiser la communication entre services.

Conclusion sur les microservices
  • Un système basé sur des microservices peut être compris à travers ses messages et les services qui les échangent.

  • De nouveaux microservices peuvent être développés par composition plutôt que par modification des services existants.

  • Des défis existent, tels que l'augmentation de la complexité architecturale, la nécessité de mises à niveau des compétences dans les équipes, la charge opérationnelle et la nécessité de garantir qu'une seule base de données ne devienne pas un point de contention.