S'adapter au changement - AWS Conseils prescriptifs

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

S'adapter au changement

Les systèmes logiciels ont tendance à se compliquer. Cela peut s'expliquer notamment par des modifications fréquentes des exigences de l'entreprise et le peu de temps nécessaire pour adapter l'architecture logicielle en conséquence. Une autre raison pourrait être l'investissement insuffisant pour mettre en place l'architecture logicielle au début du projet afin de l'adapter aux changements fréquents. Quelle que soit la raison, un système logiciel peut devenir complexe au point qu'il est presque impossible d'apporter une modification. Il est donc important de créer une architecture logicielle maintenable dès le début du projet. Une bonne architecture logicielle permet de s'adapter facilement aux changements.

Cette section explique comment concevoir des applications maintenables à l'aide d'une architecture hexagonale qui s'adapte facilement aux exigences non fonctionnelles ou commerciales.

Adaptation aux nouvelles exigences non fonctionnelles à l'aide de ports et d'adaptateurs

En tant que cœur de l'application, le modèle de domaine définit les actions requises du monde extérieur pour répondre aux exigences de l'entreprise. Ces actions sont définies par le biais d'abstractions, appelées ports. Ces ports sont implémentés par des adaptateurs séparés. Chaque adaptateur est responsable d'une interaction avec un autre système. Par exemple, vous pouvez disposer d'un adaptateur pour le référentiel de base de données et d'un autre adaptateur pour interagir avec une API tierce. Le domaine n'est pas au courant de l'implémentation de l'adaptateur. Il est donc facile de remplacer un adaptateur par un autre. Par exemple, l'application peut passer d'une base de données SQL à une base de données NoSQL. Dans ce cas, un nouvel adaptateur doit être développé pour implémenter les ports définis par le modèle de domaine. Le domaine ne dépend pas du référentiel de base de données et utilise des abstractions pour interagir. Il ne serait donc pas nécessaire de modifier quoi que ce soit dans le modèle de domaine. Par conséquent, l'architecture hexagonale s'adapte facilement aux exigences non fonctionnelles.

S'adapter aux nouvelles exigences de l'entreprise à l'aide de commandes et de gestionnaires de commandes

Dans une architecture en couches classique, le domaine dépend de la couche de persistance. Si vous souhaitez modifier le domaine, vous devez également modifier la couche de persistance. En comparaison, dans une architecture hexagonale, le domaine ne dépend pas des autres modules du logiciel. Le domaine est le cœur de l'application et tous les autres modules (ports et adaptateurs) dépendent du modèle de domaine. Le domaine utilise le principe d'inversion de dépendance pour communiquer avec le monde extérieur via des ports. L'avantage de l'inversion des dépendances est que vous pouvez modifier librement le modèle de domaine sans avoir peur de casser d'autres parties du code. Étant donné que le modèle de domaine reflète le problème commercial que vous essayez de résoudre, la mise à jour du modèle de domaine pour l'adapter à l'évolution des exigences commerciales ne pose aucun problème.

Lorsque vous développez un logiciel, la séparation des préoccupations est un principe important à suivre. Pour réaliser cette séparation, vous pouvez utiliser un modèle de commande légèrement modifié. Il s'agit d'un modèle de conception comportementale dans lequel toutes les informations requises pour effectuer une opération sont encapsulées dans un objet de commande. Ces opérations sont ensuite traitées par des gestionnaires de commandes. Les gestionnaires de commandes sont des méthodes qui reçoivent une commande, modifient l'état du domaine, puis renvoient une réponse à l'appelant. Vous pouvez utiliser différents clients, tels que des API synchrones ou des files d'attente asynchrones, pour exécuter des commandes. Nous vous recommandons d'utiliser des commandes et des gestionnaires de commandes pour chaque opération sur le domaine. En suivant cette approche, vous pouvez ajouter de nouvelles fonctionnalités en introduisant de nouvelles commandes et de nouveaux gestionnaires de commandes, sans modifier votre logique métier existante. Ainsi, l'utilisation d'un modèle de commande facilite l'adaptation aux nouvelles exigences de l'entreprise.

Découplage des composants à l'aide de la façade de service ou du modèle CQRS

Dans l'architecture hexagonale, les adaptateurs principaux sont chargés de coupler de manière souple les demandes de lecture et d'écriture entrantes des clients au domaine. Il existe deux manières de réaliser ce couplage souple : en utilisant un modèle de façade de service ou en utilisant le modèle de ségrégation des responsabilités par requête de commande (CQRS).

Le modèle de façade de service fournit une interface orientée vers l'avant pour servir les clients tels que la couche de présentation ou un microservice. Une façade de service fournit aux clients plusieurs opérations de lecture et d'écriture. Il est chargé de transférer les demandes entrantes vers le domaine et de mapper la réponse reçue du domaine aux clients. L'utilisation d'une façade de service est facile pour les microservices qui ont une seule responsabilité et plusieurs opérations. Cependant, lorsque l'on utilise la façade de service, il est plus difficile de suivre les principes de responsabilité unique et de fermeture ouverte. Le principe de responsabilité unique stipule que chaque module ne doit être responsable que d'une seule fonctionnalité du logiciel. Le principe ouvert-fermé stipule que le code doit être ouvert pour extension et fermé pour modification. Au fur et à mesure que la façade de service s'étend, toutes les opérations sont regroupées dans une seule interface, de nouvelles dépendances y sont encapsulées et de plus en plus de développeurs commencent à modifier la même façade. Par conséquent, nous recommandons d'utiliser une façade de service uniquement s'il est clair que le service ne s'étendra pas beaucoup pendant le développement.

Une autre façon d'implémenter des adaptateurs principaux dans une architecture hexagonale consiste à utiliser le modèle CQRS, qui sépare les opérations de lecture et d'écriture à l'aide de requêtes et de commandes. Comme expliqué précédemment, les commandes sont des objets qui contiennent toutes les informations nécessaires pour modifier l'état du domaine. Les commandes sont exécutées par des méthodes de gestion de commandes. Les requêtes, en revanche, ne modifient pas l'état du système. Leur seul objectif est de renvoyer des données aux clients. Dans le modèle CQRS, les commandes et les requêtes sont implémentées dans des modules distincts. Cela est particulièrement avantageux pour les projets qui suivent une architecture pilotée par les événements, car une commande peut être implémentée sous la forme d'un événement traité de manière asynchrone, alors qu'une requête peut être exécutée de manière synchrone à l'aide d'une API. Une requête peut également utiliser une autre base de données optimisée pour elle. L'inconvénient du modèle CQRS est qu'il prend plus de temps à mettre en œuvre qu'une façade de service. Nous vous recommandons d'utiliser le modèle CQRS pour les projets que vous envisagez de développer et de maintenir à long terme. Les commandes et les requêtes constituent un mécanisme efficace pour appliquer le principe de responsabilité unique et développer des logiciels couplés de manière souple, en particulier dans le cadre de projets de grande envergure.

Le CQRS présente de grands avantages à long terme, mais nécessite un investissement initial. C'est pourquoi nous vous recommandons d'évaluer votre projet avec soin avant de décider d'utiliser le modèle CQRS. Cependant, vous pouvez structurer votre application en utilisant des commandes et des gestionnaires de commandes dès le départ sans séparer les opérations de lecture et d'écriture. Cela vous aidera à refactoriser facilement votre projet pour le CQRS si vous décidez d'adopter cette approche ultérieurement.

Évolutivité d'organisation

Une combinaison d'architecture hexagonale, de conception axée sur le domaine et (en option) de CQRS permet à votre organisation de faire évoluer rapidement votre produit. Selon la loi de Conway, les architectures logicielles ont tendance à évoluer pour refléter les structures de communication d'une entreprise. Cette observation a toujours eu une connotation négative, car les grandes organisations structurent souvent leurs équipes en fonction d'une expertise technique telle qu'une base de données, un bus de services d'entreprise, etc. Le problème de cette approche est que le développement de produits et de fonctionnalités implique toujours des préoccupations transversales, telles que la sécurité et l'évolutivité, qui nécessitent une communication constante entre les équipes. La structuration des équipes en fonction des caractéristiques techniques crée des silos inutiles au sein de l'organisation, ce qui entraîne de mauvaises communications, un manque d'appropriation et une perte de vue d'ensemble. Finalement, ces problèmes d'organisation se reflètent dans l'architecture logicielle.

La manœuvre inverse de Conway, quant à elle, définit la structure organisationnelle en fonction des domaines qui promeuvent l'architecture logicielle. Par exemple, les équipes interfonctionnelles sont chargées d'un ensemble spécifique de contextes délimités, qui sont identifiés à l'aide du DDD et du Event Storming. Ces contextes limités peuvent refléter des caractéristiques très spécifiques du produit. Par exemple, l'équipe chargée du compte peut être responsable du contexte de paiement. Chaque nouvelle fonctionnalité est confiée à une nouvelle équipe dont les responsabilités sont très cohérentes et peu liées, afin qu'elle puisse se concentrer uniquement sur la fourniture de cette fonctionnalité et réduire les délais de commercialisation. Les équipes peuvent être redimensionnées en fonction de la complexité des fonctionnalités, de sorte que les fonctionnalités complexes peuvent être attribuées à un plus grand nombre d'ingénieurs.