Le design piloté par le domaine (DDD) s’oppose à l’idée d’avoir un modèle unique et unifié pour l’ensemble du système ; il encourage plutôt à diviser le système en contextes délimités, chacun ayant son propre modèle. Pendant la phase stratégique de la conception, vous mappez le domaine d’entreprise et définissez les limites de contexte de vos modèles de domaine.
La phase tactique consiste à définir vos modèles de domaine avec davantage de précision. Les modèles tactiques sont appliqués au sein d’une seule limite de contexte. Dans une architecture de microservices, où chaque contexte délimité est un candidat microservice, nous nous intéressons particulièrement aux motifs d’entité et d’agrégat. En appliquant ces modèles, nous nous donnons les moyens d'identifier les limites naturelles des services au sein de notre application (voir l'article suivant de cette série). En règle générale, un microservice doit être plus petit qu’un agrégat, et pas plus grand qu’une limite de contexte. Nous allons dans un premier temps examiner les modèles tactiques. Ensuite, nous les appliquerons à la limite du contexte Expédition dans l’application Drone Delivery.
Vue d’ensemble des modèles tactiques
Cette section propose une brève synthèse des modèles tactiques de la conception pilotée par domaine. Aussi, si vous maîtrisez bien cette solution, vous pouvez passer cette section. Les modèles sont décrits plus en détail dans les chapitres 5 à 6 de l’ouvrage d’Eric Evans et dans le livre Implementing Domain-Driven Design de Vaughn Vernon.
Entités. Une entité est un objet présentant une identité unique et permanente. Par exemple, dans une application bancaire, les clients et les comptes sont des entités.
- Une entité présente un identifiant unique dans le système, pouvant être utilisé pour la rechercher ou la récupérer. Cela ne signifie pas que les identifiants sont toujours exposés directement aux utilisateurs. Il peut s’agit d’un GUID ou de la clé primaire dans une base de données.
- Une identité peut être associée à plusieurs limites de contexte et persister au-delà de la durée de vie de l’application. Par exemple, les numéros de comptes bancaires ou les numéros d’identification nationaux n’arrivent pas à expiration à la disparition d’une application spécifique.
- Les attributs d’une entité peuvent évoluer au cours du temps. Par exemple, le nom ou l’adresse d’une personne peuvent évoluer.
- Une entité peut comporter des références à d’autres entités.
Objets de valeur. Un objet de valeur n’a aucune identité. Il est défini uniquement par les valeurs de ses attributs. Les objets de valeur sont également immuables. Pour modifier un objet de valeur, vous devez toujours créer une nouvelle instance de remplacement. Les objets de valeur peuvent comporter des méthodes encapsulant la logique du domaine. Toutefois, ces méthodes ne doivent avoir aucun effet sur l’état de l’objet. Comme exemples typiques des objets de valeur, citons les couleurs, les dates et les heures, ainsi que les valeurs de devise.
Agrégats. Un agrégat définit la limite de cohérence autour d’une ou plusieurs entités. Une seule des entités d’un agrégat est la racine. La recherche s’effectue à l’aide de l’identifiant de l’entité racine. Toutes les autres entités de l’agrégat sont des enfants de la racine ; elles sont référencées en suivant les pointeurs de la racine.
La finalité d’un agrégat est de modéliser les éléments transactionnels invariants. Les composantes du monde réel présentent des réseaux complexes de relations. Les clients créent des commandes, les commandes contiennent des produits, les produits ont des fournisseurs, etc. Si l’application modifie plusieurs objets connexes, comment garantit-elle la cohérence ? Comment effectuer le suivi des éléments invariants ? Comment les appliquer ?
Les applications traditionnelles ont bien souvent valorisé les transactions de base de données pour garantir les principes de cohérence. Dans une application distribuée, toutefois, ce n’est pas toujours possible. Une seule transaction commerciale peut être associée à plusieurs magasins de données, peut être à long terme ou encore impliquer le recours à des services tiers. Finalement, c’est à l’application, non à la couche de données, d’appliquer les éléments invariants requis pour le domaine. C’est ce que les agrégats ont vocation à modéliser.
Notes
Un agrégat peut être constitué d’une entité unique, sans entité enfant. Il s’agit d’un agrégat parce qu’une limite transactionnelle est identifiée.
Services de domaine et d’application. Dans la terminologie de la conception pilotée par domaine, un service est un objet implémentant une certaine logique sans avoir aucun effet sur l’état. Evans fait la différence entre les services de domaine, qui encapsulent la logique du domaine, et les services d’application, qui offrent une fonctionnalité technique, comme l’authentification utilisateur ou l’envoi d’un message SMS. Les services de domaine sont souvent utilisés pour modéliser un comportement valable sur plusieurs entités.
Notes
Le terme service présente plusieurs significations en développement logiciel. Ici, la définition n’est pas directement liée aux microservices.
Événements de domaine. Les événements de domaine peuvent servir à communiquer des signalements à d’autres composantes du système. Comme le nom le suggère, les événements de domaine sont liés au déroulé des opérations au sein du domaine. Par exemple, « un enregistrement a été inséré dans un tableau » n’est pas un événement de domaine. « Une livraison a été annulée » est un événement de domaine. Les événements de domaine sont particulièrement pertinents au sein d’une architecture de microservices. Les microservices étant distribués sans partager de magasins de données, ils tirent parti des événements de domaine pour se coordonner entre eux. L'article Communication entre les services évoque plus en détail la messagerie asynchrone.
Il existe plusieurs modèles de conception pilotée par domaine non répertoriés ici, comme les fabriques, les référentiels et les modules. Si ces modèles peuvent s’avérer utiles lors de l’implémentation d’un microservice, ils sont moins intéressants au moment de la conception des limites entre les microservices.
Application Drone Delivery : Application des modèles
Nous allons commencer par les scénarios devant être pris en charge par la limite de contexte Expédition.
- Un client peut demander qu’un drone collecte des marchandises au sein d’une entreprise enregistrée auprès du service de livraison par drone.
- L’expéditeur génère une balise (un code-barres ou une carte RFID) qu’il place sur le colis.
- Un drone récupère le colis à l’emplacement source et le dépose à sa destination finale.
- Lorsqu’un client planifie une livraison, le système communique un horaire prévu en fonction des données d’itinéraire, des conditions météorologiques et des données d’historique.
- Lorsque le drone est en vol, un utilisateur peut effectuer le suivi de son parcours et s’informer de l’horaire prévu actualisé.
- Jusqu’à ce que le drone collecte le colis, le client peut annuler une livraison.
- Le client est informé de la remise du colis.
- L’expéditeur peut demander la confirmation de la livraison au client, sous la forme d’une signature par écrit ou par empreinte digitale.
- Les utilisateurs peuvent rechercher l’historique d’une livraison effectuée.
Pour ces scénarios, l’équipe de développement a identifié les entités suivantes.
- Livraison
- Package
- Drone
- Compte
- Confirmation
- Notification
- Tag
Les quatre premiers éléments,associés à la livraison, au colis, au drone et au compte sont tous des agrégats représentant des limites de cohérence transactionnelles. Les confirmations et les notifications sont des entités enfants des livraisons, tandis que les balises sont des entités enfants des colis.
Les objets de valeur de cette conception sont l’emplacement, l’horaire prévu, le poids du colis et la taille du colis.
À titre d’illustration, voici un diagramme UML de l’agrégat de livraison. Notez qu’il comporte des références à d’autres agrégats, dont le compte, le colis et le drone.
Il existe deux événements de domaine :
Lorsqu’un drone est en vol, l’entité Drone transmet l’événement DroneStatus qui décrit l’emplacement du drone et son état (en vol, à terre).
L’entité de livraison transmet les événements DeliveryTracking à chaque changement d’étape de la livraison. Il peut par exemple s’agir d’une création de livraison, d’un report, d’une échéance proche ou d’une fin de mission (DeliveryCreated, DeliveryRescheduled, DeliveryHeadedToDropoff et DeliveryCompleted, respectivement).
Notez que ces événements décrivent les éléments importants du modèle de domaine. Ils ont trait à une situation au sein du domaine, et ne sont liés à aucune construction particulière de langage de programmation.
L’équipe en charge du développement a identifié un domaine supplémentaire de fonctionnalités qui ne peut être pris en compte dans aucune des entités décrites jusqu’à présent. Une partie du système doit coordonner l’ensemble des étapes associées à la planification et à la mise à jour d’une livraison. En conséquence, l’équipe de développement a ajouté deux services de domaine à la livraison : un Planificateur en charge de la coordination des étapes et un Superviseur qui surveille l’état de chaque étape, afin de détecter les défaillances ou les échéances. Il s’agit d’une variante du modèle de superviseur de l’agent planificateur.
Étapes suivantes
L'étape suivante consiste à définir les limites de chaque microservice.