Dependency Breakers: Identifier et Briser les Dépendances Problématiques
🔗 Dependency Breakers: Identifier et Briser les Dépendances Problématiques
Introduction
Toute architecture complexe accumule des dépendances. Mais pas toutes les dépendances sont bonnes. Certaines deviennent problématiques : elles ralentissent, bloquent, créent du risque, ou violent l’autonomie des équipes.
Ce guide vous aide à :
- Identifier les dépendances problématiques
- Comprendre pourquoi elles posent problème
- Appliquer des patterns pour les “briser” (dependency breakers)
Partie 1: Diagnostiquer les Dépendances Problématiques
Qu’est-ce qu’une Dépendance Problématique?
Une dépendance est problématique si elle a une ou plusieurs de ces caractéristiques:
🔴 CRITÈRE 1: Trop Fréquente
└─ Appels synchrones constants
└─ Blocage : "A attend B"
└─ Exemple: API appelée 100x par jour
🔴 CRITÈRE 2: Non Documentée
└─ Personne ne sait vraiment qu'elle existe
└─ Découverte à la production
└─ Exemple: Lecture directe de la DB d'une autre équipe
🔴 CRITÈRE 3: Unidirectionnelle Implicite
└─ Il y a une hiérarchie cache (qui dépend de qui?)
└─ Pas de gouvernance claire
└─ Exemple: "On appelle le legacy quand on a besoin"
🔴 CRITÈRE 4: Synchrone & Critique
└─ Si la dépendance casse, tout casse
└─ Pas de fallback
└─ Exemple: "Si Catalog n'est pas up, rien ne marche"
🔴 CRITÈRE 5: Risque Élevé
└─ Changements in dépendance cassent tout
└─ Long cycle de troubleshooting
└─ Exemple: Changement model upstream = jours de debugging
🔴 CRITÈRE 6: Equipe Bloquée
└─ Une équipe ne peut pas progresser sans l'autre
└─ Calendriers forcés de se synchroniser
└─ Exemple: Deploy impossible sans approval de l'autre équipe
Matrice de Sévérité
Classifiez chaque dépendance sur 2 axes:
Impact Élevé | Impact Moyen | Impact Bas
Fréquence | CRITIQUE | ÉLEVÉ | ACCEPTABLE
Élevée | | |
-----------|-----------------|-----------------|------------
Fréquence | ÉLEVÉ | MOYEN | ACCEPTABLE
Moyenne | | |
-----------|-----------------|-----------------|------------
Fréquence | MOYEN | MOYEN | ACCEPTABLE
Basse | | |
-----------|-----------------|-----------------|------------
CRITICAL = Dépendance synchrone, fréquente, non documentée
= HIGHEST PRIORITY pour un dependency breaker
ÉLEVÉ = Fréquente OU impactful
= À adresser rapidement
ACCEPTABLE = Peut exister comme est
Exercice: Audit de Vos Dépendances
Pour chaque paire d’équipes, posez-vous:
1. Existe-t-il une dépendance?
└─ OUI → Continuer
└─ NON → Rien à faire
2. C'est synchrone ou asynchrone?
└─ Synchrone (blocage immédiat) = PLUS problématique
└─ Asynchrone (peut attendre) = MOINS problématique
3. Combien de fois par jour?
└─ >50 fois = Très fréquent
└─ 10-50 fois = Fréquent
└─ <10 fois = Pas très souvent
4. Qu'arrive-t-il si la dépendance casse?
└─ Tout casse = CRITIQUE
└─ Service degraded = Élevé
└─ Quelques users affectés = Acceptable
5. Comment la dépendance est documentée?
└─ Bien documentée = Bon
└─ Pas documentée = ROUGE FLAG
6. Y a-t-il une équipe qui attend l'autre?
└─ OUI = Problème d'équipe
└─ NON = Problème seulement technique
Partie 2: Les Types de Dependency Breakers
Type 1: Le “Decoupling Pattern”
Objectif: Transformer dépendance synchrone → asynchrone
Pattern: Event-Driven Communication
AVANT (synchrone, bloquant):
Order Service
↓ (HTTP call)
↓ (wait for response)
Inventory Service
PROBLÈME:
❌ Order Service bloquée si Inventory n'est pas up
❌ Inventory bottleneck
❌ Tightly coupled
APRÈS (event-driven, asynchrone):
Order Service
↓ (publie event: OrderPlaced)
↓
Event Queue (Kafka)
↓
Inventory Service (écoute asynchrone)
BÉNÉFICES:
✓ Order Service pas bloquée
✓ Inventory peut être down, va rattraper
✓ Loosely coupled
✓ Chacun peut évoluer indépendamment
Pattern à appliquer: Published Language avec events
Pattern: Cache & Async Sync
AVANT (synchrone):
Recommendation Service
↓ (appelle Catalog à chaque request)
Catalog Service
PROBLÈME:
❌ 1000 calls/min si 1000 users
❌ Latence: Chaque reco attendait Catalog
❌ Catalog surchargé
APRÈS (cache + async sync):
Recommendation Service
├─ Cache local de Product data
├─ Répond depuis cache (instant!)
└─ Sync background thread met à jour le cache
↓
Catalog publishes ProductUpdated events
Recommendation recharge le cache
BÉNÉFICES:
✓ 0 latency pour reco
✓ Pas de load sur Catalog
✓ Eventual consistency acceptable
Quand utiliser:
- Données qui changent lentement (products, config)
- Eventual consistency acceptable (reco peut être 1h old)
- Lecture intensive
Pattern: Batch Processing
AVANT (synchrone):
Analytics Service
↓ (pulls data from every service)
10 services
PROBLÈME:
❌ Centaines de queries par jour
❌ Touts les services affectés
❌ Trop de dépendances
APRÈS (batch):
10 services
↓ (nightly batch export)
↓
Data Lake
↓ (Analytics lit le next day)
Analytics Service
BÉNÉFICES:
✓ Prévisible (tous les soirs)
✓ Bulk efficient
✓ Services indépendants pendant le jour
✓ Analytics peut être en maintenance
Quand utiliser:
- Reporting/Analytics (delay acceptable)
- Batch operations
- Heavy data imports
Type 2: Le “Bubble Context” (Isolation Layer)
Objectif: Protéger votre contexte de dépendance external/legacy
AVANT (exposé au chaos):
Your Service (propre)
↓ (appelle directement)
Legacy System (Big Ball Of Mud)
PROBLÈME:
❌ Legacy peut casser votre service
❌ Vous devez gérer la complexité legacy
❌ Vous ne pouvez pas évoluer indépendamment
APRÈS (bubble context):
Your Service (propre)
↓ (API propre)
Bubble Context (adapts your model ↔ legacy)
├─ ACL (Anticorruption Layer)
├─ Traduction
└─ Abstraction des détails
↓
Legacy System (Big Ball Of Mud)
BÉNÉFICES:
✓ Votre code reste propre
✓ Legacy isolé
✓ Vous pouvez remplacer legacy sans impact
✓ Progression possible
Pattern à appliquer: Anticorruption Layer
Type 3: Le “Domain Decoupling”
Objectif: Si deux domaines sont trop couplés, séparer
AVANT (couplé):
Order Context = Order + Billing entrelacées
├─ Create Order
├─ Create Invoice
├─ Process Payment
└─ Update Shipment
PROBLÈME:
❌ Si Payment change, Order casse
❌ Si Invoice format change, Order impact
❌ Complexité monolithe
APRÈS (séparation):
Order Context
├─ Order aggregate
├─ Publishe events: OrderPlaced, OrderPaid
└─ Zéro connaissance du Billing
Billing Context
├─ Invoice aggregate
├─ Écoute OrderPlaced
├─ Crée la facture
└─ Zéro couplage avec Order logic
Payment Context
├─ Payment aggregate
└─ Asynchrone
BÉNÉFICES:
✓ Contextes indépendants
✓ Chacun peut évoluer
✓ Testable indépendamment
✓ Réutilisable (Payment pour autres contextes)
Pattern à appliquer: Separate Ways ou event-driven
Type 4: Le “Organizational Alignment”
Objectif: Aligner la structure d’équipe avec les contextes
AVANT (misaligned):
Backend Team (Order + Billing + Inventory)
↓ (3 domaines, 1 équipe)
Frontend Team (UI)
↓ (depends strongly on Backend)
PROBLÈME:
❌ Backend bottleneck (3 domaines complexes)
❌ Frontend bloquée par Backend
❌ Pas d'ownership clair
APRÈS (aligned):
Order Team owns Order Service
↓
Billing Team owns Billing Service
↓
Inventory Team owns Inventory Service
↓
Frontend Team (consomme APIs)
Dépendance: Frontend ← Order/Billing/Inventory
(Mais Frontend ne connaît que les APIs, pas l'implémentation)
BÉNÉFICES:
✓ Ownership clair
✓ Chaque équipe pas surchargée
✓ Frontend peut avancer parallèlement
✓ Faster deployment cycles
Pattern à appliquer: Team Topologies + alignment
Type 5: Le “API Versioning & Stability”
Objectif: Briser la dépendance à “breaking changes”
AVANT (breaking changes):
V1 of Catalog API
↓
3 consumers, tous cassés si Catalog change
PROBLÈME:
❌ Pas de stabilité
❌ Coordination ncessaire pour chaque change
❌ Lent à déployer
APRÈS (versioning):
V1 of Catalog API (deprecated in 3 months)
V2 of Catalog API (new)
↓
Consumers migrer progressivement
↓
Each consumer peut choisir quand migrer
Timing:
- Month 1: V2 launched, V1 still working
- Month 2: V2 recommended, V1 still works
- Month 3: V2 required, V1 EOL
BÉNÉFICES:
✓ Consumers pas forcés
✓ Graduelle migration
✓ Breaker des breaking changes
✓ More autonomy per team
Pattern à appliquer: Published Language avec versioning
Type 6: Le “Strangler Pattern”
Objectif: Briser les dépendances progressivement du Legacy
AVANT (tightly coupled au Legacy):
Legacy Monolith
↓ (everything inside)
↓ (hard to extract)
APRÈS (Strangler):
Year 1:
└─ Extract Service A → Strangler routes A → New Service
Legacy still handles B, C, D, E
Year 2:
├─ Extract Service B
├─ Extract Service C
└─ Legacy now handles D, E
Year 3:
├─ Extract Service D
├─ Extract Service E
└─ Legacy completely replaced!
BÉNÉFICES:
✓ Graduelle, no big bang
✓ Low risk
✓ Continuous value delivery
✓ Lernen along the way
Pattern à appliquer: Separate Ways + Anticorruption Layer
Partie 3: Sélectionner le Bon Dependency Breaker
Decision Tree
Q1: La dépendance est synchrone ou asynchrone?
├─ SYNCHRONE (bloquante)
│ └─ Q2: Peut-elle devenir asynchrone?
│ ├─ OUI → Event-Driven (Type 1)
│ │ ou Batch (Type 1)
│ │
│ └─ NON (vraiment besoin synchrone)
│ └─ Q3: C'est un appel fréquent ou rare?
│ ├─ FRÉQUENT → Cache + Async Sync (Type 1)
│ └─ RARE → Acceptable, laisser synchrone
│
└─ ASYNCHRONE (ok)
└─ Q2: C'est du chaos ou du chaos isolé?
├─ CHAOS GLOBAL (Big Ball Of Mud)
│ └─ Bubble Context + ACL (Type 2)
│
└─ CHAOS ISOLÉ (Legacy, specific service)
└─ ACL ou Strangler (Type 2 + 6)
Partie 4: Mise en Pratique - Exemples Complets
Example 1: E-commerce - Réduire Load Catalog
Situation:
- Catalog Service surcharges (5000 req/min)
- Pricing, Inventory, Search, Recommendation tous appellent Catalog synchrone
- Latency: 500ms par request
Diagnostic:
Dépendance: Synchrone, très fréquente, critique
Sévérité: CRITIQUE
Cause: Tout appelle Catalog directement
Dependency Breaker: Cache + Event Sync (Type 1)
Avant:
Pricing Service → [HTTP] → Catalog (5000 req/min)
Inventory Service → [HTTP] → Catalog
Recommendation Service → [HTTP] → Catalog
Search Service → [HTTP] → Catalog
Après:
Pricing Service
├─ Cache local de Products
├─ Consulte cache (instant!)
└─ Background thread écoute ProductUpdated events
Inventory Service
├─ Cache local de Products
└─ Async sync via events
Recommendation Service
├─ Cache local de Products
└─ Lazy refresh
Catalog Service
├─ Publie ProductUpdated events
└─ Load reduit de 80%!
Résultats:
✓ Catalog: 5000 → 1000 req/min
✓ Latency: 500ms → 0ms (cache hit)
✓ Resilience: Si Catalog down, tout continue
Example 2: Frontend Blockade Breaking
Situation:
- Frontend Team bloquée par Backend Team
- Chaque feature Frontend attend Backend API
- Deploy impossible sans coordination
Diagnostic:
Dépendance: Synchrone, fréquente, organizational blocker
Sévérité: ÉLEVÉ + ORGANIZATIONAL
Cause: Tight coordination requirement
Dependency Breaker: Organizational Alignment (Type 4)
BEFORE:
Frontend Team → Waits → Backend Team (Order+Billing+Inventory)
↓
Backend overloaded (3 domains)
↓
Frontend blocked
AFTER:
Frontend Team → Consumes APIs from:
├─ Order Team (Order Service)
├─ Billing Team (Billing Service)
└─ Inventory Team (Inventory Service)
Each Backend Team:
├─ Owns ONE domain
├─ Deploys independently
└─ Faster iterations
Dependency still exists (Frontend needs Order),
but it's not a blocker anymore (Order Service API stable, versioned)
Example 3: Legacy System Strangling
Situation:
- 10 year old monolith
- Everything tightly coupled
- Want to extract services progressively
Diagnostic:
Dépendance: Everything depends on Legacy
Sévérité: CRITICAL (but known, not emergency)
Cause: Monolith over time
Dependency Breaker: Strangler + ACL (Type 2 + 6)
PHASE 1 (Month 1-3):
Identify Service A (e.g., Payment Processing)
Create Payment Service (new, clean)
Create Strangler (router):
├─ New requests → Payment Service
└─ Old requests → Legacy
Deploy new architecture
Monitor, verify
PHASE 2 (Month 4-6):
Extract Service B (e.g., Catalog)
Same pattern: New Service + Strangler
PHASE 3 (Month 7-12):
Extract Service C, D, E...
END STATE:
All services extracted
Legacy completely bypassed
Old monolith = archived data only
Partie 5: Checklist d’Implementation
Avant d’Implémenter un Dependency Breaker
Diagnostic
├─ [ ] Identifié la dépendance problématique
├─ [ ] Mesuré: fréquence, impact, sévérité
├─ [ ] Compris la racine cause
├─ [ ] Impliqué l'équipe dépendante
└─ [ ] Documenté le problème
Design
├─ [ ] Sélectionné le dependency breaker (type 1-6)
├─ [ ] Validé avec les deux équipes
├─ [ ] Estimé l'effort et la complexité
├─ [ ] Identifié les risques
└─ [ ] Planifié les étapes
Implementation
├─ [ ] Créé un prototype
├─ [ ] Testé avec un petit sous-ensemble
├─ [ ] Vérifié la performance améliorée
├─ [ ] Mesuré l'impact réel
└─ [ ] Documenté pour les mainteneurs
Rollout
├─ [ ] Migré progressivement (pas big bang)
├─ [ ] Gardé l'ancienne dépendance en fallback
├─ [ ] Monitored la stabilité
├─ [ ] Alertes en place
└─ [ ] Support team éducated
Post-Implementation
├─ [ ] Mesuré les améliorations (latency, throughput, autonomy)
├─ [ ] Collecté le feedback des équipes
├─ [ ] Documenté les leçons apprises
├─ [ ] Célébré le succès!
└─ [ ] Planifié le prochain dependency breaker
Ressources
- Event-Driven Architecture - Patterns vidéo
- API Versioning Best Practices
- Strangler Pattern - Martin Fowler
- Anticorruption Layer - Carte #2
- Separate Ways - Carte #6
- Team Topologies - Org Design
Créé pour: Architectes et facilitateurs aidant à briser des dépendances problématiques
Version: 1.0
Licence: CC-BY-SA