Maison >développement back-end >Tutoriel Python >Création d'applications Python maintenables avec une architecture hexagonale et une conception basée sur le domaine
Dans le paysage actuel du développement logiciel, en évolution rapide, il est crucial de créer des applications faciles à maintenir, à adapter et à faire évoluer. L'architecture hexagonale (également connue sous le nom de ports et adaptateurs) et la conception pilotée par domaine (DDD) constituent une combinaison efficace pour relever ces défis. L'architecture hexagonale favorise une séparation nette des préoccupations, facilitant ainsi le remplacement, le test ou l'amélioration de parties du système sans perturber la logique de base. Pendant ce temps, DDD se concentre sur l’alignement de votre code avec des concepts commerciaux réels, garantissant ainsi que votre système est à la fois intuitif et résilient. Ensemble, ces approches permettent aux développeurs de créer des systèmes robustes, résilients et conçus pour s'adapter de manière transparente aux exigences changeantes et à la croissance future.
L'architecture hexagonale, également connue sous le nom de modèle de ports et d'adaptateurs, a été introduite par Alistair Cockburn pour répondre à la rigidité et à la complexité de l'architecture en couches traditionnelle. Son objectif principal est de rendre la logique centrale (domaine) de l'application indépendante des systèmes externes, permettant ainsi des tests, une maintenance et une adaptabilité plus faciles.
À la base, Hexagonal Architecture divise l'application en trois couches principales :
Core (Business Logic/Domain) : Le cœur du système où résident les règles métier et la logique de domaine. Cette couche est indépendante et ne s'appuie pas sur des bibliothèques ou des frameworks externes.
Exemple : Calculer les intérêts d'un prêt ou valider l'action d'un utilisateur par rapport aux règles métier.
Ports (interfaces) : Définitions abstraites (par exemple, interfaces ou protocoles) pour la manière dont le noyau interagit avec le monde extérieur. Les ports représentent des cas d'utilisation ou des API spécifiques à une application. Ils définissent ce qui doit être fait sans préciser comment.
Exemple : Le port du référentiel définit des méthodes pour interagir avec les sources de données telles que :
src/ports/repository.py from abc import ABC, abstractmethod from typing import List from src.entities import Entity class Repository(ABC): @abstractmethod def get(self, id: str) -> Entity: pass @abstractmethod def insert(self, entity: Entity) -> None: pass @abstractmethod def update(self, entity: Entity) -> None: pass
# src/adapters/postgres_repository.py from sqlalchemy import create_engine, Column, String from sqlalchemy.orm import declarative_base, sessionmaker from src.entities import Entity from src.ports.repository import Repository Base = declarative_base() # Define the database table for Entity class EntityModel(Base): __tablename__ = "entities" id = Column(String, primary_key=True) name = Column(String, nullable=False) description = Column(String) class PostgresRepository(Repository): def __init__(self, db_url: str): """ Initialize the repository with the PostgreSQL connection URL. Example db_url: "postgresql+psycopg2://username:password@host:port/dbname" """ self.engine = create_engine(db_url) Base.metadata.create_all(self.engine) self.Session = sessionmaker(bind=self.engine) def get(self, id: str) -> Entity: session = self.Session() try: entity_model = session.query(EntityModel).filter_by(id=id).first() if not entity_model: raise ValueError(f"Entity with id {id} not found") return Entity(id=entity_model.id, name=entity_model.name, description=entity_model.description) finally: session.close() def insert(self, entity: Entity) -> None: session = self.Session() try: entity_model = EntityModel(id=entity.id, name=entity.name, description=entity.description) session.add(entity_model) session.commit() finally: session.close() def update(self, entity: Entity) -> None: session = self.Session() try: entity_model = session.query(EntityModel).filter_by(id=entity.id).first() if not entity_model: raise ValueError(f"Entity with id {entity.id} not found") entity_model.name = entity.name entity_model.description = entity.description session.commit() finally: session.close()
L'architecture est souvent visualisée comme un hexagone, symbolisant plusieurs façons d'interagir avec le noyau, chaque côté représentant un adaptateur ou un port différent.
Domain-Driven Design (DDD) est une approche de conception de logiciels qui met l'accent sur un alignement étroit entre les objectifs commerciaux et le logiciel construit pour les atteindre. Cette méthodologie a été introduite par Eric Evans dans son livre Domain-Driven Design: Tackling Complexity in the Heart of Software.
À la base, DDD se concentre sur la compréhension et la modélisation du domaine (l'espace des problèmes commerciaux) avec l'aide d'experts du domaine et sur la traduction de cette compréhension dans le système logiciel. DDD favorise le découplage des domaines, garantissant que les différentes parties du système restent indépendantes, claires et faciles à gérer.
Concepts clés de la conception basée sur le domaine :
Domaine : Le domaine de connaissances ou d'activité spécifique abordé par le logiciel. Par exemple, dans une application bancaire, le domaine inclut des concepts tels que les comptes, les transactions et les clients.
Langage omniprésent : Un langage commun développé en collaboration par des développeurs et des experts du domaine. Ce vocabulaire partagé garantit une communication claire et une compréhension cohérente entre toutes les parties prenantes.
Entités et objets de valeur :
Agrégats : Clusters d'entités associées et d'objets de valeur traités comme une seule unité pour les modifications de données. Chaque agrégat possède une entité racine qui garantit l'intégrité de l'ensemble du cluster.
Dépôts : Mécanismes de récupération et de stockage des agrégats, fournissant une couche d'abstraction sur l'accès aux données.
Services :Opérations ou processus qui ne correspondent pas naturellement à des entités ou à des objets de valeur mais qui sont essentiels au domaine, comme le traitement d'un paiement.
src/ports/repository.py from abc import ABC, abstractmethod from typing import List from src.entities import Entity class Repository(ABC): @abstractmethod def get(self, id: str) -> Entity: pass @abstractmethod def insert(self, entity: Entity) -> None: pass @abstractmethod def update(self, entity: Entity) -> None: pass
Dans cette section, je ne fournis pas d'exemple détaillé de mise en œuvre de la conception pilotée par domaine (DDD) car il s'agit d'une méthodologie complète principalement axée sur la résolution de défis complexes en matière de logique métier. DDD excelle dans la structuration et la gestion de règles métier complexes, mais pour réaliser pleinement son potentiel et répondre à d'autres problèmes de codage, il est préférable de l'utiliser dans un cadre architectural complémentaire. Ainsi, dans la section suivante, la conception pilotée par domaine sera combinée à l'architecture hexagonale pour mettre en évidence ses points forts et fournir une base solide pour résoudre des problèmes de codage supplémentaires au-delà de la logique métier, accompagnée d'un exemple détaillé.
La conception pilotée par domaine (DDD) et l'architecture hexagonale se complètent en mettant l'accent sur des limites claires et en alignant les logiciels sur les besoins de l'entreprise. DDD se concentre sur la modélisation du domaine principal et l'isolation de la logique métier, tandis que l'architecture hexagonale garantit que cette logique reste indépendante des systèmes externes via des ports et des adaptateurs. Ils répondent à des préoccupations distinctes mais complémentaires :
L'architecture hexagonale comme cadre :
Conception basée sur le domaine comme logique de base :
Ensemble, ils permettent des systèmes évolutifs, testables et flexibles où le domaine reste au centre de l'attention, à l'abri des changements d'infrastructure ou de technologie. Cette synergie garantit une conception robuste qui s'adapte facilement aux exigences métier évolutives.
La section suivante offre un exemple pratique de la façon dont la conception pilotée par domaine (DDD) et l'architecture hexagonale fonctionnent ensemble pour créer des systèmes logiciels robustes, maintenables et adaptables.
Ce projet applique l'architecture hexagonale et la conception pilotée par domaine (DDD) pour créer des systèmes évolutifs et maintenables, fournissant une base moderne et robuste pour le développement d'applications. Construit avec Python, il utilise FastAPI comme framework Web et DynamoDB comme base de données.
Le projet est organisé comme suit :
src/ports/repository.py from abc import ABC, abstractmethod from typing import List from src.entities import Entity class Repository(ABC): @abstractmethod def get(self, id: str) -> Entity: pass @abstractmethod def insert(self, entity: Entity) -> None: pass @abstractmethod def update(self, entity: Entity) -> None: pass
Vous pouvez trouver le code source dans mon référentiel GitHub.
L'intégration de l'architecture hexagonale et de la conception pilotée par domaine (DDD) dans les applications Python favorise le développement de systèmes maintenables, adaptables et étroitement alignés sur les objectifs commerciaux. L'architecture hexagonale garantit une séparation claire entre la logique métier principale et les systèmes externes, favorisant la flexibilité et la facilité de test. DDD met l'accent sur la modélisation précise du domaine, ce qui aboutit à un logiciel qui reflète véritablement les processus et les règles métier. En intégrant ces méthodologies, les développeurs peuvent créer des applications robustes qui non seulement répondent aux exigences actuelles, mais sont également bien préparées pour évoluer avec les futurs besoins de l'entreprise.
Connectez-moi si vous avez apprécié cet article !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!