[JAVA] [DDD] Présentation de l'architecture basée sur le domaine + Onion

Article sérialisé DDD

Contexte

Je l'ai recommandé dans l'article Quelle est l'architecture la plus accessible pour commencer à implémenter avec une conception pilotée par domaine Était l'architecture d'oignon.

Cette fois, je voudrais expliquer en détail l'architecture de l'oignon.

Comme je l'ai écrit dans l'article ci-dessus, "Hexagonal, Onion, Clean" sont essentiellement les mêmes, et l'idée est qu'ils sont terminés en hexagonal, mais l'oignon qui est expliqué plus concrètement. Je pense que c'est plus facile à comprendre si vous lisez l'explication de l'architecture.
Après cela, quand vous lisez l'explication de Hexagonal, cela devient "Je vois" et "Oh, c'est Hexagonal après tout". Lol

Architecture traditionnelle en couches

image.png

Cette architecture est conçue pour regrouper littéralement toute la logique métier dans la couche de logique métier. Mais,

Il existe des inconvénients tels que.

Architecture en couches introduite dans «Eric Evans Domain Driven»

image.png

Cette architecture est une tentative d'améliorer la maintenabilité en donnant des connaissances métier au modèle de couche de domaine à partir de l'architecture en couches traditionnelle.

Ceci est expliqué dans l'article Qu'est-ce qui exprime la connaissance du domaine dans un modèle avec un exemple de code. Veuillez vous y référer.

Cette conception a grandement amélioré la facilité de modélisation, mais elle a toujours ses faiblesses. *** La couche Domaine dépend de la couche Infrastructure ***.

Cela signifie que les modifications de la couche d'infrastructure, telles que les modifications de bibliothèque ou le changement de base de données, peuvent affecter l'ensemble de votre logique métier.

Laissez-moi vous donner un exemple concret.

image.png

Supposons que vous ayez implémenté l'accès à la base de données pour un modèle en tant que RDB.
Si la mise en œuvre de la couche Infrastructure et domaine est une description de la prémisse à utiliser dans un SGBDR spécifique, combien de code doit être changé si vous essayez de changer RDB en Dynamo d'AWS plus tard ... ?? C'est difficile à imaginer.

Comme autre exemple de remplacement de la couche Infrastructure, vous pouvez imaginer de manière réaliste le cas où vous souhaitez passer de la création de votre propre service d'envoi de courrier à un service externe plus sophistiqué.

Le problème est que vous essayez de «concevoir autour du modèle de domaine», mais la couche de domaine dépend d'une couche. La couche de domaine ne souhaite être modifiée qu'en cas de modification du modèle de domaine.

Architecture d'oignon

Principe de l'inversion de dépendance

image.png Voilà donc l'architecture.

À expliquer en fonction de l'exemple d'objet présenté dans l'article Qu'est-ce que l'expression de la connaissance du domaine dans un modèle ・ ・ ・

Tâche: couche de modèle de domaine(Vraie classe)
TaskRepository: couche de service de domaine(Dépôt/Interface)
TaskApplication: couche de service d'application
TaskRDBRepository: couche d'infrastructure(Dépôt/Vraie classe)
TaskDynamoRepository: couche d'infrastructure(Dépôt/Vraie classe)

image.png

Oups, j'ai pu implémenter avec succès le modèle de domaine en tant que classe qui ne dépend de rien!

Quelle est la différence?

Oui, la dépendance avec la couche Infrastructure a été inversée car le TaskRepository est devenu une interface au lieu d'une vraie classe.

Cette méthode est appelée le principe de l'inversion des dépendances. (Référence)
*** Plutôt que d'implémenter une couche de bas niveau et de s'appuyer ensuite sur une couche de haut niveau, elle est élevée. La couche de bas niveau implémente *** en fonction de l'interface exposée par la couche de niveau! Cela permet un niveau d'indépendance de couche plus élevé.

Dans ce cas,

public inteterface TaskRepository {
  Task findById(Long taksId);

  void save(Task task);
}

Dans DomainService, seuls la méthode d'appel et le type de retour sont définis de cette manière et la destination de persistance n'est pas spécifiée. * Vous le déclarez sous la forme "La destination de persistance peut être n'importe où, mais la classe d'implémentation doit correspondre à cela car elle est recherchée et enregistrée de cette manière" *. ApplicationService est défini par le type TaskRepository, puis par [DI (Dependency Injection)](https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6% 80% A7% E3% 81% AE% E6% B3% A8% E5% 85% A5) et ainsi de suite pour que la classe réelle soit jugée au moment de l'exécution.

Désormais, même si vous souhaitez remplacer RDB par Dynamo comme destination de persistance, si vous préparez une autre classe d'implémentation, vous n'aurez pas du tout à modifier DomainModel, DomainService, ApplicationService. C'est merveilleux.

Le mérite n'est pas seulement qu'il est facile de remplacer la classe d'implémentation, mais aussi qu'il est plus facile à lire et à maintenir car le code de bas niveau n'est pas inclus dans le modèle qui exprime l'entreprise.

Signification d'exprimer dans une forme ronde

Dans la figure ci-dessus, la couche est représentée à plat à des fins de comparaison avec l'architecture en couches, mais la définition originale est qu'elle est représentée sous forme de cercle car elle est appelée "oignon".

image.png

Alors, que signifie cette forme ronde?

Il représente le modèle *** qui a une frontière entre l'application et son extérieur, et communique entre eux via un adaptateur ***. (Les flèches représentent la direction de la requête, chacune recevant une réponse dans la direction opposée)

image.png

Par exemple, dans le cas d'une demande d'un certain HttpClient, l'application la reçoit d'abord avec un adaptateur dédié, l'application effectue un traitement, acquiert des informations de la base de données si nécessaire, et l'application traite la réponse de la base de données et la renvoie en tant que réponse HttpClient. ..

Dans le cas du test d'intégration également, l'application reçoit une demande de l'adaptateur dédié et la traite, mais dans ce cas, il est également possible de remplacer la base de données par MockDB (en mémoire, etc.).

L'avantage de ce modèle est que *** DomainModel et Application peuvent toujours être écrits indépendamment et la qualité peut être garantie dans cette unité ***. Puisqu'il ne peut être appelé que par la méthode autorisée par Application depuis l'extérieur, si la qualité de l'application est garantie par le test automatique, on peut considérer que l'Application ne se comporte pas étrangement quel que soit le client qui l'appelle. Ce sentiment de sécurité est énorme.

Stratégie de test

Je pense que cela dépend de la politique de chaque projet, mais je pense personnellement que la politique consistant à implémenter uniquement le test d'intégration pour Application Service est la plus rentable.

De plus, DDD met l'accent sur le refactoring pour mûrir le modèle, mais il y a aussi l'avantage qu'il est plus facile de refactoriser librement l'intérieur en testant avec une certaine granularité importante appelée Application Serice. Si vous testez de trop près classe par classe, vous pouvez vous sentir mal à l'aise avec la refactorisation car chaque classe disparaît au moment de la refactorisation et, par conséquent, la dynamique de non-refactorisation peut fonctionner.

Comme mentionné ci-dessus, si vous testez par Application Service, vous pouvez être rassuré sur la qualité. Lorsque vous envisagez une stratégie de test, je pense qu'il suffit de la spécifier comme référence.

Oh, cette forme

Oups, et le dernier adaptateur ressemble à quelque chose ...
Oui, c'est une architecture hexagonale.

image.png

L'architecture hexagonale présentée dans l'article Quelle est l'architecture la plus simple à mettre en œuvre avec une conception pilotée par domaine figure de modèle

C'est vrai, l'idée de connecter cette application et le monde extérieur avec un adaptateur utilise le hexagonal tel quel. Après tout, cette idée hexagonale est très bonne, n'est-ce pas?

L'architecture de l'oignon est juste un peu plus détaillée dans l'application, spécifiant le type d'adaptateur et le rendant un peu plus spécifique dans l'ensemble.

Comme je l'ai écrit au début de cet article, avez-vous dit "Oh, c'est hexagonal après tout"? Lol

Résumé

Au fait, avez-vous transmis l'attrait de l'architecture oignon et de l'image de mise en œuvre? Si vous pouvez imaginer jusqu'ici, je pense que vous pouvez procéder petit à petit en vous référant aux histoires détaillées au besoin.

J'écrirai des histoires plus détaillées à l'avenir, alors restez en contact avec moi si vous le souhaitez.

Si vous voulez en savoir plus

Nous avons publié un livre pour ceux qui apprennent le DDD pour la première fois ou pour ceux qui ont réellement commencé et rencontrent des difficultés.

Guide de modélisation / mise en œuvre de la conception pilotée par domaine

En commençant par des explications sur «l'objectif de DDD» et «modèle», qui ont tendance à se perdre Nous visons à expérimenter l'attrait et les effets du DDD sur la base d'exemples de modélisation et de mise en œuvre concrètes.

Le "Chapitre 5 Architecture" de ce livre fournit une explication plus détaillée du contenu de cet article. Veuillez acheter si vous le souhaitez.

Sur Twitter, nous envoyons également des questions sur DDD et acceptons les questions via un service appelé "Boîte à questions". Suivez-moi si vous le souhaitez.

@little_hand_s

Recommended Posts

[DDD] Présentation de l'architecture basée sur le domaine + Onion
Réponse aux questions sur DDD [Domain Driven Design]
Qu'est-ce que la conception axée sur le domaine tente de résoudre [DDD]
[DDD] Quelle est l'architecture la plus accessible pour démarrer avec la conception pilotée par domaine?
Quelle est la différence entre les responsabilités de la couche domaine et de la couche application dans l’architecture onion [DDD]