## Contexte et enjeux
L'architecture hexagonale, également connue sous le nom d'architecture ports and adapters, est une approche de conception logicielle qui a été développée par Alistair Cockburn. Elle vise à améliorer la séparation des responsabilités dans les systèmes complexes et à rendre l'infrastructure extérieure indépendante du noyau du système métier. L'enjeu principal est d'assurer une meilleure évolutivité, la facilité de maintenance et le respect des principes SOLID.
## Concepts clés
### Ports and Adapters
**Ports** sont les interfaces qui définissent comment un composant interagit avec l'extérieur du système. Ils peuvent être soit synchrones (comme des méthodes) soit asynchrones (comme des callbacks). Les ports décrivent les actions que le système peut effectuer, mais ne spécifient pas comment elles sont réalisées.
**Adapters** sont les classes qui implémentent les ports et fournissent la connexion entre le système métier et l'environnement extérieur. Ils sont responsables de convertir les données en un format approprié pour le port et d'appeler les méthodes du port lorsqu'une action est requise.
### Architecture Hexagonale
L'architecture hexagonale prend son nom d'un modèle hexagonal, où le noyau du système (le core) est entouré par une couche extérieure formant un "hexagone" de ports. Cette structure permet une séparation claire entre les responsabilités du système métier et l'infrastructure technique.
### Exemple Pratique
Imaginons un système e-commerce. Le noyau du système est le core, qui gère les règles métier comme la création d'un panier, la gestion des paiements et la livraison. Les ports sont définis par des interfaces comme `IPayementGateway`, `IOrderService` et `ILoggingService`. Les adapters pourraient être des classes qui implémentent ces interfaces en utilisant des bibliothèques de paiement third-party, un service d'ordre externe et une solution de logging.
## Guide pratique pas à pas
### Étape 1 : Identifier les Ports
La première étape consiste à identifier les actions que le système peut effectuer. Ces actions sont définies par des ports. Par exemple :
- `IPayementGateway`: permet d'effectuer un paiement
- `IOrderService`: permet de créer, modifier et annuler un panier
- `ILoggingService`: permet de journaliser les activités du système
### Étape 2 : Implémenter les Adapters
Pour chaque port identifié, implémentez un adapter qui se connecte à l'environnement extérieur. Par exemple :
```python
class PayementGatewayAdapter:
def __init__(self, payment_gateway):
self.payment_gateway = payment_gateway
def pay(self, order_id, amount):
return self.payment_gateway.process_payment(order_id, amount)
class OrderServiceAdapter:
def __init__(self, order_service):
self.order_service = order_service
def create_order(self, items):
return self.order_service.create_order(items)
Étape 3 : Connecter le Core au Hexagone
Dans le noyau du système, utilisez les interfaces des ports pour effectuer les actions. Par exemple :
class OrderService:
def __init__(self, order_repository, payment_gateway_adapter):
self.order_repository = order_repository
self.payment_gateway_adapter = payment_gateway_adapter
def create_order(self, items):
order = Order(items)
self.order_repository.save(order)
self.payment_gateway_adapter.pay(order.id, order.total)
return order
Étape 4 : Tester les Adapters Indépendamment
Les adapters doivent être testés indépendamment du noyau du système. Utilisez des tests unitaires pour vérifier que chaque adapter fonctionne correctement.
import unittest
class TestPaymentGatewayAdapter(unittest.TestCase):
def test_pay(self):
payment_gateway = Mock()
adapter = PayementGatewayAdapter(payment_gateway)
order_id = 123
amount = 100.0
adapter.pay(order_id, amount)
payment_gateway.process_payment.assert_called_once_with(order_id, amount)
if __name__ == '__main__':
unittest.main()
Comparatif ou tableau recapitulatif
| Concept | Description |
|---|---|
| Ports | Interfaces définissant les actions du système. |
| Adapters | Classes implémentant les ports et connectant le système aux environnements extérieurs. |
| Core | Noyau du système, indépendant de l'infrastructure technique. |
Retour d'expérience concret
En adoptant l'architecture hexagonale, nous avons observé une amélioration significative de la flexibilité et de l'évolutivité de nos systèmes. Les développeurs peuvent désormais travailler sur le core du système sans être inconfortables avec les détails techniques de l'infrastructure. Par exemple, lorsqu'un nouveau fournisseur de paiement est intégré, il suffit d'implémenter un nouvel adapter pour IPayementGateway sans modifier le noyau du système.
Checklist ou plan d'action
- Identifier tous les ports nécessaires pour votre système.
- Implémenter des adapters pour chaque port en utilisant l'infrastructure technique appropriée.
- Connecter le core du système aux ports via les adpaters.
- Écrire des tests unitaires pour les adpaters.
- Réviser et tester le système en production pour s'assurer que tout fonctionne correctement.
En suivant ces étapes, vous pouvez transformer votre système en une architecture hexagonale plus robuste et évolutrice. N'oubliez pas que l'adaptation à cette architecture peut prendre du temps et des ressources, mais le résultat est une base de développement solide pour les systèmes futurs. ```