DĂ©veloppeur Cookbook: DDD Recipes (Part 3, Application Architecture)

Présentation


Dans les articles précédents, nous avons identifié la portée de l' approche et examiné les principes méthodologiques de base de la conception pilotée par domaine .


Dans cet article, je voudrais décrire les principales approches modernes de la construction de l'architecture des systèmes d'entreprise: Souple, Screaming, Clean et leur donner mon interprétation claire sous la forme d'une solution clé en main complète.


WM


À l'avenir, nous examinerons chaque modèle de conception en détail: nous indiquons la portée, donnons des exemples de code, mettons en évidence les pratiques recommandées. En conséquence, nous allons écrire un microservice prêt à l'emploi.


Architecture flexible


Dans le dernier article, nous nous sommes concentrés sur le fait que DDD inclut la pratique de l'implémentation via le modèle. Le sujet doit être décrit par votre code. Essayons de comprendre comment procéder.


Dans son livre, Eric Evans fournit une série de modèles de conception recommandés et désigne cette approche comme flexible:


Au nom de la flexibilité de l'architecture, beaucoup de constructions inutiles ont été empilées dans des programmes. Des niveaux excessifs d'abstraction et de liaison indirecte sont plus susceptibles d'interférer que d'aider dans cette affaire. Regardez l'architecture qui inspire vraiment les programmeurs à l'affiner, et vous verrez généralement quelque chose de très simple. Mais simple ne signifie pas facile à exécuter. Afin de créer de tels éléments qui peuvent être assemblés dans des systèmes complexes et en même temps faciles à comprendre, il est nécessaire de combiner "dévouement" à la conception selon le modèle avec un style architectural assez strict. Une certaine compétence de conception est nécessaire non seulement pour créer quelque chose, mais même pour utiliser celui fini.

Eric Evans, conception pilotée par domaine: s'attaquer à la complexité au cœur du logiciel

L'ensemble de modèles de conception présenté n'est pas une architecture stricte ou une solution prête à l'emploi, mais plutôt une matière à réflexion.


Architecture flashy


Des pensées similaires ont surgi dans l'esprit de nombreux développeurs et concepteurs de systèmes complexes.


En 2011, un article de Robert Martin - Screaming Architecture a été publié, qui dit que votre code ne doit pas seulement décrire le sujet, mais crier dessus, de préférence de manière obscène.


Alors, que fait l'architecture de votre application? Lorsque vous regardez la structure de répertoires de niveau supérieur et les fichiers source dans le package de plus haut niveau; crient-ils: système de soins de santé, système de comptabilité ou système de gestion des stocks? Ou crient-ils: Rails, ou Spring / Hibernate, ou ASP?

Robert C. Martin, 30 septembre 2011

Robert dit que votre code d'application doit refléter l'activité de l'application, au lieu de s'adapter aux règles du framework. La structure du framework ne doit pas limiter votre architecture. L'application, à son tour, ne doit pas être attachée à la base de données ou au protocole http, ce ne sont que des mécanismes de stockage et de livraison. Le cadre de sélection est un outil. Vous ne devez pas devenir un adhérent du cadre. Les tests de votre application sont des tests de la logique de son fonctionnement, et non des tests du protocole http.


Architecture épurée


Un an plus tard, le prochain article de Robert Martin - The Clean Architecture . L'auteur y explique comment faire crier le code. Ayant étudié plusieurs architectures, il identifie les principes de base:


  1. Indépendance du cadre. L'architecture ne dépend d'aucune bibliothèque existante. Cela vous permet d'utiliser des cadres comme outils, plutôt que les contraintes qui vous lient les mains.
  2. Testabilité. Les règles métier peuvent être testées sans interface utilisateur, base de données, serveur Web ou tout autre moyen technique.
  3. Indépendance de l'interface utilisateur. L'interface utilisateur peut être facilement modifiée sans changer le reste du système. Par exemple, l'interface Web peut être remplacée par l'interface de la console sans modifier la logique métier.
  4. Indépendance de la base de données. Vous pouvez échanger Oracle ou SQL Server contre Mongo, BigTable, CouchDB ou autre chose. Votre logique d'application ne doit pas être liée à la base de données.
  5. Indépendance des influences environnementales. En fait, les règles de votre entreprise ne savent tout simplement rien du monde extérieur.

Sur un habr déjà publié un très bon article Misconceptions Clean Architecture . Son auteur, Jeevuz, a très bien maîtrisé les subtilités de la compréhension de cette approche. Je vous recommande fortement de vous familiariser avec lui et avec les matériaux originaux.


Architecture variable


La description de l'approche ci-dessus ne semble pas si simple. Dans le cadre du développement de l'architecture d'un certain nombre de systèmes d'entreprise complexes, mes collègues et moi avons développé une interprétation assez claire des approches décrites, que j'ai l'intention de présenter ci-dessous.


Avant l'avènement des ordinateurs et des langages de programmation, le workflow papier était utilisé pour créer et gérer des systèmes avec une logique métier complexe. Le résultat de tout processus était un document qui décrivait finalement un objet métier particulier. En conséquence, les formalités administratives se résumaient à trois actions simples:


  1. Création de documents
  2. Traitement des documents
  3. Travailler avec l'archive de documents
  4. Soumission de documents

Document - enregistrement d'informations sur les activités économiques d'un objet commercial réel particulier.

Veuillez noter que le document lui-même n'est pas un véritable objet métier, mais uniquement son modèle . Actuellement, les documents papier sont remplacés par des documents électroniques. Un document peut être un enregistrement dans un tableau, une image, un fichier, une lettre envoyée ou toute autre information.
Je ne voudrais pas utiliser le mot document à l'avenir, car il sera plus déroutant, nous utiliserons le concept d'entité de la terminologie DDD. Mais vous pouvez imaginer que l'ensemble de votre système est désormais un système de gestion électronique de documents qui effectue quatre actions simples.


  1. Collectionner
  2. Traitement
  3. Stockage
  4. Représentation

Action - une unité structurelle d'activité d'un modèle d'entreprise; un acte séparé relativement achevé d'un objectif conscient, l'arbitraire et l'intentionnalité de l'activité individuelle d'un objet métier, distingué par l'utilisateur final.

Un bon exemple d' Action est un acte théâtral. Le théâtre modèle des événements de la vie réelle. L'acte est une partie significative de la pièce. Mais, pour compléter l'histoire, vous devez jouer plusieurs actes dans un ordre strictement défini. Un tel ordre dans notre architecture, nous l'appellerons le Mode .


Mode (Conduction) - un ensemble d' actions dans un certain ordre, ayant une signification complète, bénéfique pour l'utilisateur final.

conduction


Pour de tels modes de fonctionnement, un conducteur sélectif ou sélecteur a été inventé. Plus précisément, "Mécanisme de synchronisation pour la réalisation d'une séquence sélectionnée d'une pluralité de séquences de fonctionnement", pour lequel le brevet US2870278A a été obtenu. Nous connaissons cet appareil comme la «torsion» de la machine à laver. La touche architecturale est donnée au début de l'article.


La variabilité de l'approche se manifeste dans le fait qu'avec cette architecture, vous pouvez choisir l'un des quatre modes , en passant, sans exécuter d' actions inutiles.


Lors du démarrage du lave-linge, vous pouvez sélectionner le mode: lavage, rinçage ou essorage. Si vous choisissez de laver, votre machine rincera toujours le linge, puis le pressera. Avec le rinçage dans le kit, vous êtes sûr d'obtenir un essorage. Essorage - l' action finale du processus de lavage, c'est la plus «simple». Dans notre architecture, l' action la plus simple est la représentation , et nous allons commencer par elle.


Représentation


Si nous parlons d'une présentation pure sans recourir à une base de données ou à une source externe, nous donnons alors des informations statiques: une page html, un fichier, un répertoire se présentant sous la forme de json. Nous pouvons même donner juste une réponse Code - 200:


Écrivons le "vérificateur de santé" le plus simple


module Health class Endpoints < Sinatra::Base get '/check' do; end end end 

Dans sa forme la plus primitive, notre schéma ressemblera à ceci:


Représentation


Digression lyrique

Je vous demande de noter que dans le cadre Sinatra, la classe Endpoints combine à la fois le routeur et le contrôleur en une seule classe. Cela viole-t-il le principe de la responsabilité exclusive? En fait, Endpoints n'est pas une classe, mais une couche exprimée à travers une classe et son domaine de responsabilité à un niveau supérieur.


Ok, qu'en est-il du routeur et du contrôleur ? Ils ne sont pas représentés par un ensemble de classes, mais par le nom et l'implémentation d'une fonction. Un fichier statique est généralement un fichier. Une classe est responsable d'une responsabilité, mais n'essayez pas d'exprimer chaque responsabilité à travers une classe. Utilisez l'aspect pratique, pas le dogmatisme.


Travailler avec le système de stockage


Les entreprises exigent la disponibilité de votre application. Pourquoi quelqu'un aurait-il besoin de votre service si nous ne pouvons pas l'utiliser au bon moment? Pour garantir l'intégrité des données, nous enregistrons une modification de l'état d'un objet métier après chaque traitement.


Pour extraire un objet du stockage, il n'est pas nécessaire d'accéder à la logique métier. Imaginez que nous automatisons les activités d'une chaîne hôtelière et que nous ayons un magazine invité à la réception. Nous avons décidé de voir des informations sur le visiteur.


  module Reception class Endpoints < Sinatra::Base # Show item get '/residents/:id', provides: :json do resident = Repository::Residents.find params[:id] status 200 serialize(resident) end end end 

Travailler avec le système de stockage sous forme de diagramme graphique:


Stockage


Comme nous pouvons le voir, la communication entre la couche responsable du stockage et la couche responsable de la présentation des données est implémentée via le modèle Response. Ce modèle n'appartient à aucune de ces couches. En fait, il s'agit d'un objet métier et il est situé sur la couche responsable de la logique métier.


Traitement


S'il s'agit du fait que le modèle d'objet change en fonction de ses propriétés sans introduire de nouvelles données, alors nous nous tournons directement vers la couche Interactor . La couche Interactor est la clé de notre application, c'est en elle que toute la logique métier est décrite sous forme de cas d'utilisation distincts, et c'est sur elle que les Entités changent.


Considérez ce cas d'utilisation. Le visiteur est déjà inscrit dans notre hôtel, mais nous célébrons chaque arrivée ou départ.


  module Reception class Endpoints < Sinatra::Base # Register resident arrival post '/residents/:uid/arrival', provides: :json do result = Interactors::Arrival.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end # Register resident departure post '/residents/:uid/departure', provides: :json do result = Interactors::Departure.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end end end 

Arrêtons-nous un peu. Pourquoi ne pas faire de l'implémentation une méthode unique avec le paramètre status ? Les interacteurs Arrival et Departure sont fondamentalement différents. Si un invité vient à nous, nous devons vérifier si le nettoyage est terminé, s'il y a eu de nouveaux messages pour lui, etc. Avec son départ, nous devons au contraire initier le nettoyage si nécessaire. À son tour, nous ne nous souvenons même pas des messages, car s'il avait été dans un hôtel, nous l'aurions appelé immédiatement. C'est toute cette logique métier que nous prescrivons sur la couche Interactor .


Traitement


Mais que devons-nous faire si nous avons des données de l'extérieur? Ici l'action de Data Collection est connectée.


Collecte de données


Lors de l'inscription initiale d'un invité à l'hôtel, il remplit le formulaire d'inscription. Ce formulaire est en cours de vérification. Si les données sont correctes, le processus commercial d'enregistrement a lieu. Le processus renvoie des données - le modèle commercial "locataire" créé. Nous présentons ce modèle à l'invité sous une forme lisible:


 module Reception class Endpoints < Sinatra::Base # Register new resident post '/residents', provides: [:json] do form = Forms::Registration.new(params) complete! form do check! form.result do status 201 serialize form.result.data end end end end end 

Schématiquement, cela ressemble à ceci:


Collectionner


Règles du jeu (Règles)


  • Le système variatif du point de vue des processus est divisĂ© en actions .
  • La sĂ©quence d' actions est dĂ©terminĂ©e par le mode .
  • Les modes sont incrĂ©mentiels.
  • Un mode plus «complexe» complète un mode plus «simple» pour strictement une action.
  • Chaque action se dĂ©roule dans le cadre d'une couche .
  • Chaque couche est reprĂ©sentĂ©e par une classe .
  • Ă€ l'intĂ©rieur d'une couche, il peut y avoir des classes de couches et des classes de responsabilitĂ© .
  • La communication a lieu uniquement entre la couche et la classe intercouche .
  • Les modèles de reprĂ©sentation sont des exceptions.
  • La gestion des erreurs doit avoir lieu au niveau de la couche de classe .

Arbre


Schéma général


Cette approche a un seuil d'entrée élevé. Son application nécessite une grande expérience de la part du concepteur pour une bonne compréhension des tâches à résoudre. La complexité représente également la variété des choix de l'outil requis. Mais, malgré la complexité de la structure, l'implémentation au niveau du code est incroyablement simple et expressive. Bien qu'il contienne un certain nombre de conventions et de procurations. À l'avenir, nous analyserons chaque modèle de conception individuellement, décrirons comment le créer, le tester et désigner la portée. Et pour ne pas se confondre dans leur diversité, une carte complète est proposée:


Carte haute résolution




Sources d'inspiration

Source: https://habr.com/ru/post/fr429750/


All Articles