Concepts clés d'architecture
Couplage, cohésion, séparation des responsabilités, principes SOLID appliqués à l'architecture et bounded contexts.
Construire un langage commun
Avant d’approfondir l’architecture distribuée, il convient de fixer un vocabulaire commun. Ces termes reviendront sans cesse tout au long de la plateforme.
Beaucoup de décisions techniques paraissent complexes uniquement parce qu’il manque des définitions partagées. Dans cette section, nous construirons ce langage commun ainsi que les principes qui guident les décisions architecturales.
Domaine
C’est le champ métier que le logiciel cherche à résoudre. Par exemple : utilisateurs, produits, commandes, paiements, inventaire.
Le domaine n’est pas un concept technique mais un concept métier. Comprendre le domaine est la première étape pour concevoir une bonne architecture.
Sous-domaine
Une partie spécifique au sein du domaine général du métier. Il aide à décomposer le problème en zones plus facilement gérables.
Bounded Context
Une frontière explicite à l’intérieur de laquelle certains termes, modèles et règles ont une signification concrète.
Pourquoi sont-ils importants ?
Dans un système de grande taille, un même mot peut désigner des choses différentes selon le contexte :
- « Utilisateur » dans l’authentification : email, mot de passe, rôles.
- « Utilisateur » dans la facturation : raison sociale, adresse, moyen de paiement.
- « Utilisateur » dans le support : historique des tickets, niveau de satisfaction.
Chaque bounded context possède son propre modèle avec les attributs dont il a besoin.
Mise en correspondance avec l’architecture
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Autenticación │ │ Facturación │ │ Soporte │
│ │ │ │ │ │
│ Usuario: │ │ Cliente: │ │ ContactoSoporte:│
│ - email │ │ - nombre_fiscal │ │ - historial │
│ - password_hash │ │ - dirección │ │ - satisfacción │
│ - roles │ │ - método_pago │ │ - prioridad │
└──────────────────┘ └──────────────────┘ └──────────────────┘
Communication entre contextes
- APIs bien définies : Des contrats explicites entre contextes.
- Événements de domaine : Un contexte publie des événements que d’autres consomment.
- Anti-Corruption Layer (ACL) : Couche de traduction qui protège un contexte des changements survenant dans un autre.
DTO (Data Transfer Object)
Objet utilisé pour transférer des données entre couches ou systèmes. Il ne représente pas nécessairement le modèle interne du domaine.
Contrat
Définition explicite de la façon dont deux parties communiquent. Il peut définir :
- La structure de la requête et de la réponse
- Les champs obligatoires et optionnels
- Les types de données
- Les erreurs possibles
- Les règles de versionnage
Un contrat réduit l’ambiguïté et aide à faire évoluer les systèmes sans casser les consommateurs.
Événement
Fait pertinent qui s’est déjà produit dans le système. Par exemple : OrderPlaced, UserCreated, PaymentConfirmed.
Les événements sont immuables et fondamentaux dans les architectures event-driven.
Intégration
Connexion entre des systèmes ou composants différents, qu’ils soient internes ou externes.
Cohérence
Degré selon lequel les données reflètent correctement l’état du système.
Cohérence forte
Tout le monde voit le même état immédiatement.
Cohérence à terme
Il peut y avoir des décalages temporaires jusqu’à ce que le système converge.
Idempotence
Capacité d’exécuter une opération plusieurs fois et d’obtenir le même résultat, sans effets dupliqués indésirables.
Couplage
Le couplage mesure à quel point un composant dépend d’un autre.
Types de couplage (du plus fort au plus faible)
- Couplage de contenu : Un module modifie directement les données internes d’un autre. C’est le pire type.
- Couplage commun : Deux modules partagent des variables globales ou un état mutable.
- Couplage de contrôle : Un module dit à un autre comment faire son travail (en passant des drapeaux de contrôle).
- Couplage de données : Les modules communiquent uniquement à travers des paramètres bien définis. C’est le type souhaitable.
Exemple pratique
// Alto acoplamiento: el servicio de pedidos conoce
// la estructura interna del servicio de usuarios
function crearPedido(usuarioId) {
const usuario = db.query('SELECT * FROM usuarios WHERE id = ?', usuarioId);
if (usuario.saldo_cuenta > 0) {
// Accede directamente a la tabla de otro dominio
}
}
// Bajo acoplamiento: comunicación a través de una interfaz
function crearPedido(usuarioId) {
const puedeComprar = await servicioUsuarios.verificarCapacidadCompra(usuarioId);
if (puedeComprar) {
// No conoce los detalles internos del servicio de usuarios
}
}
Recherchez un faible couplage entre les modules. Chaque composant doit pouvoir évoluer de façon indépendante.
Cohésion
La cohésion mesure à quel point les responsabilités au sein d’un même composant sont liées. Une cohésion élevée signifie que tout ce que fait un module est étroitement lié.
Types de cohésion (du plus faible au plus élevé)
- Coïncidentielle : Les fonctions sont regroupées par hasard, sans relation logique.
- Temporelle : Les fonctions sont regroupées parce qu’elles s’exécutent au même moment.
- Fonctionnelle : Toutes les fonctions contribuent à une unique responsabilité bien définie. C’est le type idéal.
Exemple pratique
// Baja cohesión: este módulo hace demasiadas cosas no relacionadas
const utils = {
formatearFecha(fecha) { /* ... */ },
calcularImpuesto(monto) { /* ... */ },
enviarEmail(destinatario, asunto) { /* ... */ },
validarRUT(rut) { /* ... */ },
};
// Alta cohesión: cada módulo tiene una responsabilidad clara
const formatoFechas = {
formatear(fecha, formato) { /* ... */ },
parsear(texto, formato) { /* ... */ },
diferencia(fechaA, fechaB) { /* ... */ },
};
La relation couplage-cohésion
Ces deux concepts sont inversement liés : lorsque vous augmentez la cohésion à l’intérieur d’un module, vous réduisez naturellement le couplage entre les modules.
Séparation des responsabilités (Separation of Concerns)
Chaque partie du système doit prendre en charge une seule préoccupation. En architecture, cela se traduit par des couches et des modules aux responsabilités claires.
Exemple en couches
┌─────────────────────────┐
│ Presentación (UI) │ → Cómo se muestra la información
├─────────────────────────┤
│ Lógica de negocio │ → Qué reglas aplican
├─────────────────────────┤
│ Acceso a datos │ → Dónde y cómo se almacenan los datos
└─────────────────────────┘
Principes SOLID en architecture
Les principes SOLID, formulés à l’origine pour la conception orientée objet, s’appliquent également au niveau architectural :
S — Single Responsibility (Responsabilité unique)
Chaque service ou module doit avoir une seule raison de changer. Si un changement dans les règles de facturation exige de modifier le service des utilisateurs, il y a un problème de conception.
O — Open/Closed (Ouvert/Fermé)
Le système doit être extensible sans modifier l’existant. Les plugins, les middlewares et les architectures event-driven facilitent cela.
L — Liskov Substitution (Substitution de Liskov)
Si un service implémente un contrat (API), toute implémentation alternative doit être interchangeable sans casser les consommateurs.
I — Interface Segregation (Ségrégation des interfaces)
Les consommateurs ne doivent pas dépendre d’interfaces qu’ils n’utilisent pas. Le patron BFF (Backend for Frontend) est un exemple direct de ce principe.
D — Dependency Inversion (Inversion des dépendances)
Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Les deux doivent dépendre d’abstractions.
// Violación: la lógica de negocio depende de PostgreSQL
class ServicioPedidos {
constructor() {
this.db = new PostgresClient();
}
}
// Correcto: depende de una abstracción
class ServicioPedidos {
constructor(repositorio) {
this.repositorio = repositorio; // Puede ser Postgres, Mongo, en memoria...
}
}
Résumé pratique
| Concept | Question clé | Objectif |
|---|---|---|
| Domaine | Quel problème métier résolvons-nous ? | Comprendre le contexte |
| Bounded Context | Où se situent les frontières du domaine ? | Modèles clairs et autonomes |
| Contrat | Comment les parties communiquent-elles ? | Communication explicite |
| Couplage | À quel point A dépend-il de B ? | Minimiser les dépendances |
| Cohésion | À quel point ce que fait A est-il lié ? | Maximiser la relation interne |
| Cohérence | Les données reflètent-elles l’état réel ? | Gérer les attentes |
| Idempotence | Puis-je répéter sans effets dupliqués ? | Opérations sûres |
| SOLID | La conception est-elle extensible et maintenable ? | Flexibilité à long terme |
Ces concepts ne sont pas des règles absolues mais des repères pour prendre de meilleures décisions. Plus ce vocabulaire est clair, plus il sera facile de comprendre des décisions de conception plus avancées.