You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
11 KiB
Markdown
329 lines
11 KiB
Markdown
|
2 months ago
|
# ADR-004 : Architecture Microservices Hybride
|
||
|
|
|
||
|
|
**Statut** : ✅ Accepté
|
||
|
|
**Date** : Octobre 2025
|
||
|
|
**Décideurs** : Équipe Architecture
|
||
|
|
**Tags** : `architecture`, `microservices`, `patterns`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Contexte
|
||
|
|
|
||
|
|
Le système BricoLoc peut être architecturé de plusieurs façons :
|
||
|
|
- Architecture **monolithique** (comme le legacy)
|
||
|
|
- Architecture **en couches** (layered)
|
||
|
|
- Architecture **microservices**
|
||
|
|
- Architecture **hexagonale**
|
||
|
|
|
||
|
|
L'objectif est de démontrer la maîtrise de l'architecture logicielle en appliquant des **patterns modernes**.
|
||
|
|
|
||
|
|
### Options considérées
|
||
|
|
1. **Monolithe modulaire** (architecture en couches uniquement)
|
||
|
|
2. **Microservices purs** (services déployés séparément)
|
||
|
|
3. **Microservices hybride** (logiquement séparés, physiquement colocalisés)
|
||
|
|
4. **Architecture hexagonale** (ports & adapters)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Décision
|
||
|
|
|
||
|
|
✅ **Nous adoptons une architecture Microservices Hybride avec Clean Architecture interne**
|
||
|
|
|
||
|
|
**Hybride** signifie :
|
||
|
|
- **Logiquement** : 6 microservices distincts avec responsabilités claires
|
||
|
|
- **Physiquement** : Colocalisés dans le même déploiement Next.js (simplicité)
|
||
|
|
- **Évolutif** : Possibilité de séparer les déploiements si besoin
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Justification
|
||
|
|
|
||
|
|
### Pourquoi Microservices ?
|
||
|
|
|
||
|
|
#### 1. **Décomposition par Domaine Métier** 📦
|
||
|
|
|
||
|
|
Chaque microservice correspond à un **bounded context** :
|
||
|
|
|
||
|
|
| Microservice | Responsabilité | Bounded Context |
|
||
|
|
|--------------|----------------|-----------------|
|
||
|
|
| **Auth Service** | Authentification, autorisation | Identity & Access Management |
|
||
|
|
| **Catalogue Service** | Gestion outils, catégories, recherche | Product Catalog |
|
||
|
|
| **Reservation Service** | Réservations, planning | Booking Management |
|
||
|
|
| **Inventory Service** | Stocks, entrepôts, disponibilité | Inventory Management |
|
||
|
|
| **Payment Service** | Paiements, transactions | Payment Processing |
|
||
|
|
| **Notification Service** | Emails, notifications | Communication |
|
||
|
|
|
||
|
|
**Avantage** : Séparation claire des responsabilités (Single Responsibility Principle)
|
||
|
|
|
||
|
|
#### 2. **Autonomie** 🚀
|
||
|
|
|
||
|
|
Chaque microservice :
|
||
|
|
- A sa propre logique métier (domaine)
|
||
|
|
- Gère ses propres données (database per service - logique)
|
||
|
|
- Peut être développé indépendamment
|
||
|
|
- Peut évoluer sans impacter les autres
|
||
|
|
|
||
|
|
**Exemple** : Changement de la logique de pricing → uniquement Reservation Service touché
|
||
|
|
|
||
|
|
#### 3. **Scalabilité Ciblée** 📈
|
||
|
|
|
||
|
|
Possibilité de scaler uniquement les services sous charge :
|
||
|
|
- **Inventory Service** (beaucoup d'accès en temps réel) → scale horizontal
|
||
|
|
- Les autres restent à 1 instance
|
||
|
|
|
||
|
|
**Comparaison Legacy** : Monolithe = scale tout ou rien (coûteux)
|
||
|
|
|
||
|
|
#### 4. **Isolation des Pannes** 🛡️
|
||
|
|
|
||
|
|
Si un service tombe en panne, les autres continuent :
|
||
|
|
- **Payment Service down** → Catalogue et Recherche fonctionnent toujours
|
||
|
|
- **Graceful degradation** possible
|
||
|
|
|
||
|
|
**Comparaison Legacy** : Monolithe = single point of failure
|
||
|
|
|
||
|
|
#### 5. **Évolutivité Technologique** 🔧
|
||
|
|
|
||
|
|
Chaque microservice pourrait utiliser une techno différente :
|
||
|
|
- Catalogue Service → Node.js (si besoin d'ElasticSearch)
|
||
|
|
- Payment Service → Python (si ML pour fraude detection)
|
||
|
|
- Etc.
|
||
|
|
|
||
|
|
**Note** : Dans notre cas, tout est Next.js API Routes (simplicité), mais l'architecture permet l'évolution.
|
||
|
|
|
||
|
|
#### 6. **Démonstration Architecturale** 🏛️
|
||
|
|
|
||
|
|
C'est un **projet d'architecture logicielle** :
|
||
|
|
- Microservices = pattern architectural majeur
|
||
|
|
- Démontre la maîtrise de la décomposition
|
||
|
|
- Impressionnant pour un portfolio
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Pourquoi "Hybride" ? (Pas microservices purs)
|
||
|
|
|
||
|
|
#### Microservices Purs (Rejeté)
|
||
|
|
|
||
|
|
**Avantages** :
|
||
|
|
- Déploiement indépendant par service
|
||
|
|
- Technologies hétérogènes possibles
|
||
|
|
- Scaling précis
|
||
|
|
|
||
|
|
**Inconvénients** :
|
||
|
|
- ❌ **Complexité opérationnelle** (6 déploiements séparés)
|
||
|
|
- ❌ **Coûts** (6 instances minimum)
|
||
|
|
- ❌ **Latence réseau** (appels HTTP inter-services)
|
||
|
|
- ❌ **Debugging complexe** (logs distribués)
|
||
|
|
- ❌ **Overkill** pour projet académique
|
||
|
|
|
||
|
|
#### Microservices Hybride (Choisi)
|
||
|
|
|
||
|
|
**Principe** :
|
||
|
|
- Services logiquement séparés (code organisé en microservices)
|
||
|
|
- Physiquement colocalisés (même déploiement Next.js)
|
||
|
|
- Communication intra-process (pas HTTP externe)
|
||
|
|
|
||
|
|
**Avantages** :
|
||
|
|
- ✅ **Simplicité opérationnelle** (1 seul déploiement)
|
||
|
|
- ✅ **Performance** (pas de latence réseau)
|
||
|
|
- ✅ **Coûts réduits** (1 seule instance)
|
||
|
|
- ✅ **Debugging facile** (logs centralisés)
|
||
|
|
- ✅ **Démontre l'architecture** sans overhead
|
||
|
|
|
||
|
|
**Possibilité d'évolution** :
|
||
|
|
- Si besoin de scale → extraire un service en déploiement séparé
|
||
|
|
- Architecture prête pour ça (faible couplage)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Clean Architecture Interne
|
||
|
|
|
||
|
|
Chaque microservice implémente **Clean Architecture** :
|
||
|
|
|
||
|
|
```
|
||
|
|
microservice/
|
||
|
|
├── domain/ # Couche Domaine
|
||
|
|
│ ├── entities/ # Entités métier
|
||
|
|
│ ├── value-objects/ # Value Objects
|
||
|
|
│ ├── repositories/ # Interfaces repositories
|
||
|
|
│ └── rules/ # Règles métier
|
||
|
|
│
|
||
|
|
├── application/ # Couche Application
|
||
|
|
│ ├── use-cases/ # Cas d'usage
|
||
|
|
│ ├── services/ # Services applicatifs
|
||
|
|
│ └── dtos/ # Data Transfer Objects
|
||
|
|
│
|
||
|
|
└── infrastructure/ # Couche Infrastructure
|
||
|
|
├── repositories/ # Implémentations (Supabase)
|
||
|
|
├── external-apis/ # APIs externes (Stripe)
|
||
|
|
└── events/ # Event Bus
|
||
|
|
```
|
||
|
|
|
||
|
|
**Bénéfices** :
|
||
|
|
- ✅ Testabilité maximale
|
||
|
|
- ✅ Indépendance des frameworks
|
||
|
|
- ✅ Maintenabilité
|
||
|
|
- ✅ Respect de SOLID
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Architecture Proposée
|
||
|
|
|
||
|
|
### Vue d'Ensemble
|
||
|
|
|
||
|
|
```
|
||
|
|
┌───────────────────────────────────────────────────┐
|
||
|
|
│ Client (Browser) - Next.js SSR │
|
||
|
|
└─────────────────────┬─────────────────────────────┘
|
||
|
|
│
|
||
|
|
┌─────────────────────▼─────────────────────────────┐
|
||
|
|
│ API Gateway / BFF (Next.js API) │
|
||
|
|
│ Orchestration & Aggregation │
|
||
|
|
└─┬──────┬───────┬───────┬───────┬────────┬────────┘
|
||
|
|
│ │ │ │ │ │
|
||
|
|
│ │ │ │ │ │
|
||
|
|
▼ ▼ ▼ ▼ ▼ ▼
|
||
|
|
┌─────┐┌─────┐┌──────┐┌──────┐┌──────┐┌──────┐
|
||
|
|
│Auth ││Cata-││Reser-││Inven-││Pay- ││Noti- │
|
||
|
|
│Svc ││logue││vation││tory ││ment ││fica- │
|
||
|
|
│ ││Svc ││Svc ││Svc ││Svc ││tion │
|
||
|
|
│ ││ ││ ││ ││ ││Svc │
|
||
|
|
└──┬──┘└──┬──┘└───┬──┘└───┬──┘└───┬──┘└───┬──┘
|
||
|
|
│ │ │ │ │ │
|
||
|
|
│ │ │ │ │ │
|
||
|
|
└──────┴───────┴───────┴───────┴────────┘
|
||
|
|
│
|
||
|
|
┌──────▼──────┐
|
||
|
|
│ Event Bus │ (Supabase Realtime)
|
||
|
|
└──────┬──────┘
|
||
|
|
│
|
||
|
|
┌──────▼──────┐
|
||
|
|
│ Supabase │ (PostgreSQL + Auth + Storage)
|
||
|
|
└─────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### Communication
|
||
|
|
|
||
|
|
#### Synchrone (REST-like)
|
||
|
|
```typescript
|
||
|
|
// API Gateway appelle directement le service (même process)
|
||
|
|
const availability = await inventoryService.checkAvailability({
|
||
|
|
outilId,
|
||
|
|
entrepotId,
|
||
|
|
dateDebut,
|
||
|
|
dateFin
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Asynchrone (Events)
|
||
|
|
```typescript
|
||
|
|
// Service émet un event via Event Bus (Supabase Realtime)
|
||
|
|
await eventBus.publish('reservation.confirmed', {
|
||
|
|
reservationId,
|
||
|
|
outilId,
|
||
|
|
entrepotId
|
||
|
|
})
|
||
|
|
|
||
|
|
// Autre service écoute l'event
|
||
|
|
eventBus.subscribe('reservation.confirmed', async (data) => {
|
||
|
|
await inventoryService.reserveStock(data)
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Conséquences
|
||
|
|
|
||
|
|
### ✅ Avantages
|
||
|
|
|
||
|
|
1. **Architecture claire** : Décomposition fonctionnelle évidente
|
||
|
|
2. **Maintenabilité** : Chaque service est focalisé et petit
|
||
|
|
3. **Testabilité** : Tests unitaires isolés par service
|
||
|
|
4. **Évolutivité** : Possibilité d'extraire un service si besoin
|
||
|
|
5. **Démonstration** : Montre la maîtrise de patterns avancés
|
||
|
|
6. **Simplicité opérationnelle** : 1 seul déploiement
|
||
|
|
7. **Performance** : Pas de latence réseau
|
||
|
|
|
||
|
|
### ⚠️ Complexités
|
||
|
|
|
||
|
|
1. **Structure du code** : Plus de dossiers et fichiers
|
||
|
|
2. **Communication** : Gérer Event Bus pour async
|
||
|
|
3. **Transactions distribuées** : Saga pattern si nécessaire
|
||
|
|
4. **Tests d'intégration** : Plus complexes
|
||
|
|
|
||
|
|
### 🛠️ Mitigations
|
||
|
|
|
||
|
|
- **Structure** : Documentation claire (README par service)
|
||
|
|
- **Communication** : Event Bus simple (Supabase Realtime)
|
||
|
|
- **Transactions** : Éviter si possible, ou Saga simplifié
|
||
|
|
- **Tests** : Focus sur tests unitaires par service
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Alternatives Rejetées
|
||
|
|
|
||
|
|
### ❌ Monolithe Modulaire (Couches uniquement)
|
||
|
|
|
||
|
|
**Raisons du rejet** :
|
||
|
|
- Moins impressionnant architecturalement
|
||
|
|
- Pas de décomposition fonctionnelle
|
||
|
|
- Moins adapté pour démonstration d'architecture
|
||
|
|
- Scaling "tout ou rien"
|
||
|
|
|
||
|
|
### ❌ Microservices Purs (Déploiements séparés)
|
||
|
|
|
||
|
|
**Raisons du rejet** :
|
||
|
|
- Trop complexe pour projet académique
|
||
|
|
- Coûts hébergement (6 instances)
|
||
|
|
- Overhead opérationnel
|
||
|
|
- Debugging distribué difficile
|
||
|
|
|
||
|
|
### ❌ Architecture Hexagonale Seule
|
||
|
|
|
||
|
|
**Raisons du rejet** :
|
||
|
|
- Pattern complémentaire (on l'utilise en interne)
|
||
|
|
- Moins "visible" que microservices
|
||
|
|
- Moins adapté pour comparaison avec legacy
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Migration vers Microservices Purs (Futur)
|
||
|
|
|
||
|
|
L'architecture permet d'extraire un service facilement :
|
||
|
|
|
||
|
|
**Étape 1** : Extraire Inventory Service (le plus sollicité)
|
||
|
|
```
|
||
|
|
Avant : Next.js (tout colocalisé)
|
||
|
|
Après : Next.js + Inventory Service (Node.js séparé)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Changement minimal** :
|
||
|
|
- Remplacer appel direct par appel HTTP
|
||
|
|
- Déployer Inventory Service séparément
|
||
|
|
- Event Bus déjà en place (pas de changement)
|
||
|
|
|
||
|
|
**Couplage faible** ✅ → Migration facile
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Références
|
||
|
|
|
||
|
|
- [Microservices Pattern](https://microservices.io/)
|
||
|
|
- [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
|
||
|
|
- [Domain-Driven Design](https://martinfowler.com/bliki/DomainDrivenDesign.html)
|
||
|
|
- [Bounded Context](https://martinfowler.com/bliki/BoundedContext.html)
|
||
|
|
- [Database per Service](https://microservices.io/patterns/data/database-per-service.html)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Validations
|
||
|
|
|
||
|
|
- [x] Bounded contexts identifiés
|
||
|
|
- [x] 6 microservices définis
|
||
|
|
- [x] Communication sync/async définie
|
||
|
|
- [x] Clean Architecture par service validée
|
||
|
|
- [x] Event Bus (Supabase Realtime) testé
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Prochaine révision** : Si complexité trop élevée lors du développement
|