logo le blog invivoo blanc

Domain Driven Design Part 1 – Les Outils

27 avril 2023 | Python | 0 comments

Introduction

La conception pilotée par le domaine (Domain Driven Design en anglais, ou DDD en abréviation) est une méthodologie de développement de logiciels qui met l’accent sur l’importance de comprendre le domaine du métier et de créer des logiciels alignés sur les besoins du métier. Il a été introduit par Eric Evans dans son livre « Domain-Driven Design : Tackling Complexity in the Heart of Software » en 2003 [1]. Depuis sa publication, la conception pilotée par le domaine (DDD) est devenue une approche populaire pour développer des systèmes logiciels complexes ou non anémique [2].

L’idée de base derrière la conception pilotée par le domaine (DDD) est de se concentrer sur le domaine métier et de créer un modèle de domaine qui représente avec précision les processus et concepts métier [3]. Ce modèle de domaine sert de base au système logiciel, guidant sa conception et sa mise en œuvre [4, 5]. Il nous ouvre également beaucoup de portes pour s’adapter aux besoins du métier très divers lors des mises en emplacement sophistiquées.

Dans cet optique, nous explorerons de manière pratique les outils, les principes et les mises en pratique de la conception pilotée par le domaine (DDD), en examinant ses avantages et ses défis via les exemples codés en Python.

Comme cette Odyssée de la conception pilotée par le domaine est assez ambitieuse, nous allons présenter les outils dans cet article, alors que les restes seront abordés dans les articles suivants.

Outils de la conception pilotée par le domaine

Eric Evans a présenté la conception pilotée par le domaine dans son livre [1] avec différents éléments par une navigation dans la figure [1]. En effet, ce sont les outils comme les couteux suisses qui coupent les logiciels complexes en petits morceaux, puis assemblent et réutilisent ces pièces au cours de la pratique. Nous allons prendre l’exemple du commerce électronique qui est codé en Python pour apprendre les outils.

Figure [1] : Navigation de DDD

1 Domaines

Dans la conception pilotée par le domaine (DDD), un domaine fait référence à un domaine d’activité ou à une activité spécifique autour duquel un système logiciel est construit. Le domaine est le cœur du système logiciel et contient la logique métier et les règles qui régissent le comportement du système.

La conception pilotée par le domaine met l’accent sur l’importance de comprendre le domaine et de le modéliser d’une manière qui reflète avec précision les règles et processus métier. En se concentrant sur le domaine, la conception pilotée par le domaine vise à créer des systèmes logiciels qui correspondent étroitement aux besoins et aux exigences du métier, et qui sont flexibles et adaptables aux changements de l’environnement commercial.

1.1 Domaine principal

Le domaine principal (Core Domain en anglais) fait référence au domaine du métier qui offre le plus de valeur et de différenciation au métier. C’est le cœur de l’application et contient la logique métier la plus complexe et la plus critique.

1.2 Domaine générique

Le domaine générique (Generic Sub-Domain en anglais) fait référence aux parties du métier qui sont communes et pourraient être mises en œuvre de manière générique. Ce sont généralement les parties de l’application qui n’offrent pas de différenciation ou d’avantage concurrentiel significatif.

1.3 Domain de support

Le domaine de support est un domaine qui fournit des fonctionnalités de support au domaine principal. Les domaines de support ne sont pas directement liés à la valeur commerciale du système, mais sont nécessaires pour prendre en charge le fonctionnement du domaine principal.

Nous pouvons distinguer les 3 types de domaine par les branches de décision dans la figure 2.

Figure [2] : Distinction des domaines

Voici un exemple en Python d’une application e-commerce simple pour mettre en lumière le concept entre le domaine principal, le domaine générique et le domaine de support.

from typing import List

class Product:
    def __init__(self, name, description, price):
        self.name = name
        self.description = description
        self.price = price


class Order:
    def __init__(self, customer_name, items, shipping_address, total_price):
        self.customer_name = customer_name
        self.items = items
        self.shipping_address = shipping_address
        self.total_price = total_price


class ProductRepository:
    def __init__(self):
        self.products = []

    def add_product(self, product):
        self.products.append(product)

    def get_all_products(self):
        return self.products


class OrderService:
    def __init__(self, product_repository):
        self.product_repository = product_repository

    def create_order(self, order):
        for product in order.products:
            if product not in self.product_repository.get_all_products():
                raise ValueError("Product not found")
        total_price = sum(product.price for product in order.products)
        order.total_price = total_price
        return order

# Supporting domain module: authentication.py

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def authenticate(self, password):
        return self.password == password

class UserRepository:
    def __init__(self):
        self.users = []

    def add_user(self, user):
        self.users.append(user)

    def get_user(self, username):
        for user in self.users:
            if user.username == username:
                return user
        return None

Dans cet exemple, les classes Product et Order représentent des entités dans le domaine principal de l’application de commerce électronique. Ce sont les parties du système qui offrent le plus de valeur et de différenciation.

La classe ProductRepository, en revanche, est un exemple de domaine générique. Il est responsable de l’accès aux données et de la gestion de l’entité Produit, mais il ne contient aucune logique métier complexe.

En fait, la classe OrderService est un service d’application qui relie le domaine principal et le domaine générique. Il contient une logique spécifique à l’application pour la création de commandes et utilise ProductRepository pour valider que tous les produits de la commande sont valides.

Sinon, le module d’authentification fournit des fonctionnalités pour l’authentification de l’utilisateur. La classe User représente un compte d’utilisateur avec un nom d’utilisateur et un mot de passe, et la classe UserRepository fournit des méthodes pour ajouter et récupérer des utilisateurs à partir du stockage.

Bien que le module d’authentification ne soit pas directement lié à la valeur métier du système, il est nécessaire pour prendre en charge le fonctionnement du domaine central. Le module d’authentification peut être intégré au domaine central de manière à permettre aux utilisateurs de s’authentifier avant de soumettre une commande, par exemple.

2 Architecture en couches

L’architecture en couches (Layered Architecture en anglais) est un modèle architectural couramment utilisé dans le développement de logiciels et peut également être appliqué à la conception pilotée par le domaine. Dans une architecture en couches, l’application ciblée est divisée en couches verticales et horizontales dans la figure 3, chacune étant responsable d’un type spécifique de fonctionnalité.

Figure [3] : Architecture en couches

2.1 Couche de domaine

La couche de domaine est responsable de l’encapsulation de la logique métier et des modèles de domaine. Dans cet exemple, supposons que nous ayons un modèle Product qui représente un produit dans notre boutique e-commerce.

# domain/models.py

class Product:
    def __init__(self, id: int, name: str, price: float):
        self.id = id
        self.name = name
        self.price = price

    def calculate_tax(self, tax_rate: float) -> float:
        return self.price * tax_rate

2.2 Couche d’application

La couche application agit comme un pont entre la couche présentation et la couche domaine. Dans cet exemple, supposons que nous ayons une classe ProductService qui expose des méthodes pour créer, lire, mettre à jour et supprimer des produits.

# application/product_service.py

from typing import List

from domain.models import Product
from infrastructure.repositories import ProductRepository

class ProductService:
    def __init__(self, product_repository: ProductRepository):
        self.product_repository = product_repository

    def create_product(self, name: str, price: float) -> Product:
        product_id = self.product_repository.get_next_id()
        product = Product(product_id, name, price)
        self.product_repository.save(product)
        return product

    def get_product(self, product_id: int) -> Product:
        return self.product_repository.get_by_id(product_id)

    def update_product(self, product: Product):
        self.product_repository.save(product)

    def delete_product(self, product_id: int):
        self.product_repository.delete(product_id)

    def calculate_product_tax(self, product_id: int, tax_rate: float) -> float:
        product = self.product_repository.get_by_id(product_id)
        return product.calculate_tax(tax_rate)

    def get_all_products(self) -> List[Product]:
        return self.product_repository.get_all()

2.3. Couche d’infrastructure

La couche d’infrastructure fournit l’infrastructure technique qui prend en charge l’application. Dans cet exemple, supposons que nous ayons une classe ProductRepository qui gère l’accès aux données pour les produits. Nous utiliserons une simple implémentation en mémoire à des fins de démonstration.

# infrastructure/repositories.py

from typing import List

from domain.models import Product

class ProductRepository:
    def __init__(self):
        self.products = {}
        self.next_id = 1

    def get_by_id(self, product_id: int) -> Product:
        return self.products.get(product_id)

    def save(self, product: Product):
        self.products[product.id] = product

    def delete(self, product_id: int):
        del self.products[product_id]

    def get_next_id(self) -> int:
        next_id = self.next_id
        self.next_id += 1
        return next_id

    def get_all(self) -> List[Product]:
        return list(self.products.values())

2.4 Couche de présentation

La couche de présentation est responsable de la gestion des entrées et sorties de l’utilisateur. Dans cet exemple, supposons que nous ayons une application Web Flask qui expose une API REST pour la gestion des produits.

from flask import Flask, render_template, request
from application import ProductService

app = Flask(__name__)
product_service = ProductService()

@app.route('/')
def index():
    # Render the home page with a list of products
    products = product_service.get_all_products()
    return render_template('index.html', products=products)

@app.route('/product/<product_id>')
def product_detail(product_id):
    # Render the product detail page for a specific product
    product = product_service.get_product_by_id(product_id)
    return render_template('product_detail.html', product=product)

@app.route('/search')
def search():
    # Render the search results page for a query
    query = request.args.get('query')
    results = product_service.search_products(query)
    return render_template('search_results.html', query=query, results=results)

Dans ce code, nous utilisons le framework Web Flask pour créer une application Web de base avec trois routes :

‘/’ : Cette route affiche la page d’accueil de notre site e-commerce. Il appelle la méthode get_all_products() de la classe ProductService pour obtenir une liste de tous les produits et transmet cette liste à un modèle appelé ‘index.html’ à afficher dans le navigateur.

‘/product/<product_id>’ : cette route affiche une page de détails de produit pour un produit spécifique. Il prend un paramètre product_id de l’URL, appelle la méthode get_product_by_id() de la classe ProductService pour obtenir le produit correspondant et le transmet à un modèle appelé ‘product_detail.html’ à afficher dans le navigateur.

‘/search’ : cette route affiche une page de résultats de recherche pour une requête. Il prend un paramètre de requête à partir de l’URL, appelle la méthode search_products() de la classe ProductService pour obtenir une liste de produits correspondant à la requête, et transmet la requête et les résultats à un modèle appelé ‘search_results.html’ à afficher dans le navigateur .

Notez que dans ce code, la couche de présentation est responsable de la gestion des entrées et sorties de l’utilisateur et de l’appel des méthodes de la couche d’application (ProductService) pour obtenir et manipuler des données.

2.5 Couche de persistance

La couche de persistance est responsable du stockage et de la récupération des données d’une base de données ou d’un autre support de stockage persistant. Il est généralement mis en œuvre à l’aide d’un système de gestion de base de données (SGBD) ou d’un cadre de mappage objet-relationnel (ORM).

Dans une application de commerce électronique, la couche de persistance serait responsable de la gestion des données relatives aux produits, commandes, clients et autres entités. Par exemple, il fournirait la fonctionnalité pour créer, lire, mettre à jour et supprimer (CRUD) des produits et des commandes de la base de données.

Voici un exemple de la façon dont vous pourriez implémenter une couche de persistance pour une application de commerce électronique en Python, en utilisant un framework ORM comme SQLAlchemy :

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Product(Base):
    __tablename__ = 'products'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    price = Column(Integer)

class Order(Base):
    __tablename__ = 'orders'

    id = Column(Integer, primary_key=True)
    customer_name = Column(String)
    customer_email = Column(String)
    total_price = Column(Integer)

    items = relationship('OrderItem')

class OrderItem(Base):
    __tablename__ = 'order_items'

    id = Column(Integer, primary_key=True)
    order_id = Column(Integer, ForeignKey('orders.id'))
    product_id = Column(Integer, ForeignKey('products.id'))
    quantity = Column(Integer)

engine = create_engine('sqlite:///ecommerce.db')
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

# Create a new product
product = Product(name='iPhone', price=1000)
session.add(product)
session.commit()

# Create a new order with some items
order = Order(customer_name='Léo', customer_email='leo.hu@invivoo.com', total_price=2000)
order.items = [OrderItem(product_id=product.id, quantity=2)]
session.add(order)
session.commit()

# Retrieve all products
products = session.query(Product).all()
print(products)

# Retrieve all orders with their items and products
orders = session.query(Order).options(
    relationship(Order.items, innerjoin=True).subqueryload(OrderItem.product)
).all()
print(orders)

Dans cet exemple, nous définissons trois modèles SQLAlchemy pour les entités Product, Order et OrderItem. Nous créons ensuite une base de données SQLite et les tables correspondantes à l’aide de Base.metadata.create_all(). Nous utilisons ensuite l’ORM pour créer de nouveaux produits et commandes, ainsi que pour les récupérer dans la base de données.

3 Conception pilotée par le modèle (MDD)

La conception pilotée par le modèle (Model Driven Design, ou MDD en anglais) [6] est une approche du développement logiciel qui met l’accent sur la création de modèles précis et détaillés du système en cours de développement, y compris des modèles du domaine métier, de l’architecture du système et du comportement. La conception pilotée par le modèle est basé sur l’idée qu’en créant des modèles détaillés du système, les développeurs peuvent mieux comprendre et communiquer les exigences du système aux parties prenantes et s’assurer que le produit logiciel final répond à ces exigences. La conception pilotée par le modèle implique généralement l’utilisation de langages et d’outils de modélisation, tels que le langage de modélisation unifié (UML), pour créer ces modèles.

Voici un exemple de système de commerce électronique utilisant une approche de conception pilotée par un modèle en Python :

from typing import List

class Customer:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email

class Product:
    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price

class Order:
    def __init__(self, customer: Customer, products: List[Product]):
        self.customer = customer
        self.products = products

class OrderProcessor:
    def process(self, order: Order):
        # Process order logic here
        pass

class OrderRepository:
    def save(self, order: Order):
        # Save order to database
        pass

class ProductService:
    def get_products(self):
        # Retrieve list of products from database
        pass

class CustomerService:
    def get_customers(self):
        # Retrieve list of customers from database
        pass

Dans cet exemple, nous avons quelques modèles de domaine définis à l’aide de classes Python, notamment Customer, Product et Order. La classe OrderProcessor contient la logique métier pour le traitement des commandes et la classe OrderRepository gère la persistance des commandes dans une base de données.

Les classes ProductService et CustomerService fournissent une interface pour récupérer respectivement des listes de produits et de clients à partir de la base de données. Ces classes pourraient être implémentées à l’aide d’un ORM comme SQLAlchemy pour gérer les interactions de base de données.

En utilisant ces modèles de domaine et ces services, nous pouvons créer des modèles précis et détaillés du système de commerce électronique, y compris le domaine commercial, l’architecture du système et le comportement, ce qui peut nous aider à mieux comprendre et communiquer les exigences du système aux parties prenantes.

A part la conception pilotée par le modèle et l’architecture en couches chez les méthodologies traditionnelles, les mises en œuvre de la conception pilotée par le domaine nécessitent principalement les éléments qui seront adoptés dans les exemples applicatifs en Python chez notre prochain article.

4 Langage ubiquitaire (UBIQUITOUS en anglais)

Cette pratique a été introduite par la conception pilotée par le comportement (Behavior Driven Design ou BDD en anglais) [8] et elle met l’accent sur l’importance de créer un langage partagé entre l’équipe de développement et les experts du domaine. Les experts du domaine doivent pouvoir utiliser les mêmes termes et concepts que les développeurs, ce qui permet d’éviter les malentendus et favorise la collaboration.

5 Contextes bornés 

Ils consistent à diviser un domaine complexe en contextes plus petits et plus gérables. Chaque contexte a son propre langage, ses modèles et ses règles métier spécifiques qui sont pertinents pour ce contexte. Cela permet de garder les modèles de domaine ciblés et maintenables, tout en facilitant le développement et la maintenance de logiciels qui reflètent les besoins du métier. En plus, on doit noter que dans DDD, l’espace de nom du problème fait référence au domaine dans lequel le problème métier existe, tandis que l’espace de noms du contexte, d’autre part, fait référence à un contexte borné spécifique dans le domaine global.

Par exemple,

Domaine du commerce électronique
Espace de nom du problème : le commerce électronique
Espace de noms de contexte : la commande

Dans le domaine du commerce électronique, l’espace de noms problématique est le commerce électronique. Dans le domaine du commerce électronique, il peut y avoir différents contextes bornés, tels que la commande, la gestion des clients ou la gestion des produits. Dans cet exemple, l’espace de noms de contexte est la commande, qui se concentre sur le processus de commande de produits.

Il faudrait remarquer qu’un contexte borné pourrait comprendre plusieurs micro-services ou sous-domaines, mais pas au contraire.

6 Carte du contexte

La carte du contexte (CONTEXT MAP en anglais) consiste à identifier les relations et les dépendances entre différents contextes bornés dont les liaisons sont classifiées. Leur implémentations seront abordées lors de la mise en œuvre.

6.1 Service Hôte Ouvert

Le service hôte ouvert (Open Host Service en anglais) est utilisé pour s’intégrer à des systèmes ou services externes qui ne correspondent pas bien au modèle de domaine. L’idée est d’exposer le système externe en tant que service au modèle de domaine, plutôt que d’essayer de l’incorporer directement dans le domaine.

Un exemple de service hôte ouvert dans une application de commerce électronique pourrait être un service de passerelle de paiement. Le service de passerelle de paiement peut avoir son propre domaine et sa propre logique commerciale liée au traitement des paiements, ce qui peut ne pas convenir au domaine du commerce électronique. Au lieu d’essayer d’intégrer la logique de la passerelle de paiement directement dans le domaine du commerce électronique, la passerelle de paiement peut être présentée comme un service avec une interface standardisée que le domaine du commerce électronique peut utiliser pour communiquer avec elle.

6.2 Noyau partagé 

Le noyau partagé (Shared Kernel en anglais) est une relation entre deux ou plusieurs contextes bornés qui partagent une base de code ou un schéma de base de données commun. Ils collaborent étroitement pour développer et maintenir le noyau partagé, qui agit comme un pont entre les contextes.


Par exemple, imaginez une plateforme de commerce électronique qui propose à la fois une boutique en ligne et une application mobile. La boutique en ligne et l’application mobile nécessitent l’accès au même compte client et aux mêmes données d’historique des commandes. Pour éviter la duplication de ces données et assurer la cohérence entre les deux plates-formes, un noyau partagé pourrait être utilisé pour gérer ces données et les rendre disponibles à la fois pour la boutique en ligne et l’application mobile.

6.3 Client-fournisseur

Le client-fournisseur (Customer Supplier Teams en anglais) est une relation entre deux ou plusieurs contextes bornés où un contexte fournit un service ou des données à un autre contexte. Le contexte fournisseur est le fournisseur et le contexte récepteur est le client.

Dans le commerce électronique, un exemple d’application des équipes client-fournisseur dans la conception pilotée par le modèle pourrait être le processus de gestion des catalogues de produits. L’équipe client serait responsable de la définition des exigences et des règles commerciales liées aux informations sur les produits et à la gestion des catalogues. Ils travailleraient en étroite collaboration avec l’équipe du fournisseur, qui serait responsable de la mise en œuvre de l’infrastructure technique de gestion du catalogue de produits, y compris le stockage, l’indexation et la récupération des données.

6.4 Conformiste 

Le conformiste (Conformist en anglais) est une relation entre deux ou plusieurs contextes bornés où un contexte suit les conventions et les règles d’un autre contexte. Le contexte conformiste ajuste son comportement pour correspondre aux exigences du contexte dirigeant.

Un exemple de conformiste dans un contexte de commerce électronique pourrait être une équipe chargée de gérer l’inventaire des produits dans un entrepôt. Cette équipe utiliserait le même modèle de domaine que les autres équipes dans le contexte borné responsable de la gestion des commandes, des clients et des produits.

6.5 Couche anti-corruption (ACL) 

La couche anti-corruption (Anti-corruption Layer en anglais) est un mécanisme qui protège un contexte borné des complexités et des incohérences d’un système externe. Il agit comme un pont entre le contexte et le système externe, traduisant et validant les données échangées entre eux.

Par exemple, supposons que le système de commerce électronique doive s’intégrer à un ancien système de gestion des stocks qui utilise son propre modèle de données et sa propre API. Le modèle de domaine du système hérité pourrait ne pas être compatible avec le modèle de domaine du système de commerce électronique, et l’intégration directe des deux systèmes pourrait entraîner beaucoup de complexité et de confusion. Pour résoudre ce problème, une couche anti-corruption pourrait être introduite comme couche intermédiaire entre le système de commerce électronique et l’ancien système de gestion des stocks. L’ACL traduirait les données et les messages entre les deux systèmes, mappant les concepts de domaine du système hérité aux concepts de domaine du système de commerce électronique.

6.6 Chemins séparés 

Les Chemins séparés (Separate Ways en anglais) est la séparation des préoccupations est étroitement lié au concept de monolithes modulaires, qui sont des systèmes monolithiques qui ont été décomposés en modules plus petits et plus faciles à gérer qui peuvent être développés et déployés indépendamment. En décomposant un système en domaines ou sous-domaines distincts et bien définis, les développeurs peuvent créer des systèmes plus modulaires et maintenables, plus faciles à passer à l’échelle et à évoluer dans le temps.

Chez le commerce électronique, un exemple d’application pourrait être la séparation du sous-système de gestion des stocks de l’application principale de commerce électronique. Dans ce scénario, le sous-système de gestion des stocks est responsable de la gestion des niveaux de stock des produits et possède ses propres modèles de domaine et logique métier. Il communique avec la principale application de commerce électronique via une interface bien définie, telle qu’une API REST ou une file d’attente de messages. Du coup, le sous-système de gestion des stocks peut être développé et maintenu par une équipe distincte avec son propre ensemble d’exigences et de contraintes. En le séparant de l’application principale de commerce électronique, le développement et l’évolution du sous-système de gestion des stocks peuvent se faire indépendamment, sans affecter l’application principale de commerce électronique.

6.7 Grande boule de boue 

La grande boule de boue (Big Ball of Mud en anglais) décrit un système logiciel qui manque d’une structure ou d’une organisation claire. C’est un système qui s’est développé et a évolué au fil du temps sans un plan ou une architecture clairs, donnant lieu à une base de code déroutante et difficile à maintenir.

Pour éviter cet anti-pattern, il est important de suivre de bons principes de conception de logiciels, tels que ceux décrits au-dessus, et de refactoriser ou de reconcevoir le système selon les besoins pour maintenir une architecture propre et modulaire. Par ailleurs, les patrons de conception ­[9] pourront être exploités.

En somme, la carte de contexte de s’assurer que les différents contextes peuvent fonctionner ensemble de manière transparente et que tout changement dans un contexte n’a pas de conséquences involontaires dans un autre.

7 Entités et objets de valeur

Ce sont les éléments constitutifs du modèle de domaine. Les entités sont des objets qui ont une identité unique et sont modifiables, ce qui signifie que leurs propriétés peuvent changer au fil du temps. Les objets de valeur, en revanche, sont immuables et représentent des concepts importants pour le domaine mais qui n’ont pas d’identité unique.

8 Agrégats

Elles consistent à regrouper des entités liées et des objets de valeur dans des agrégats. Un agrégat est responsable de l’application des règles métier et du maintien de la cohérence dans ses modèles, en rendant son domaine invariant [1]. Cela aide à simplifier la complexité du modèle de domaine et facilite le raisonnement sur le comportement du système.

9 Services

Ils sont sans état et fonctionnent sur un ensemble d’entrées pour produire des sorties. Ils peuvent être utilisés pour coordonner les interactions entre plusieurs entités, appliquer des règles métier ou effectuer des calculs.

10 Usines (FACTORIES en anglais):

Elles sont responsables de la création d’objets de domaine complexes qui nécessitent plusieurs étapes ou dépendances. Les usines encapsulent le processus de création, permettant au code client de se concentrer sur la logique métier, et non sur les détails de la création d’objets [10, 11].

11 Entrepôts (REPOSITORIES en anglais) :

Ils fournissent une couche d’abstraction entre le modèle de domaine et la couche de persistance. Ils fournissent une interface standardisée pour accéder et stocker les objets du domaine. Le modèle d’entrepôt est utilisé pour encapsuler la logique nécessaire pour accéder à la base de données, comme l’interrogation, la mise à jour et la suppression d’entités. Les entrepôts peuvent également être utilisés pour implémenter la mise en cache et d’autres optimisations de performances.

12 Événements de domaine :

Ils impliquent l’identification et la capture d’événements importants au sein du domaine, tels qu’une nouvelle commande passée ou la mise à jour des détails d’un client. Les événements de domaine peuvent être utilisés pour déclencher d’autres processus ou mettre à jour d’autres modèles au sein du système. Il faudrait noter que les méthodes d’événements portent la signatures avec le verbes du temps passé.

Grace à ces outils, nous pourrons comprendre et procéder la conception des logiciels complexes.

Conclusion

Dans cet article, nous avons mis en lumière les outils de la conception pilotée par le domaine (DDD), qui est une puissante méthodologie de développement de logiciels. Car il met l’accent sur l’importance de comprendre le domaine du métier et de créer des logiciels alignés sur les besoins du métier. Actuellement,  nous avons embarqué dans notre paquebot pour l’Odyssée de la conception pilotée par le domaine, tout en nous équipant des différents outils nécessaires pour concevoir nos propres logiciels.

Références