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.

11 KiB

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)

// API Gateway appelle directement le service (même process)
const availability = await inventoryService.checkAvailability({
  outilId,
  entrepotId,
  dateDebut,
  dateFin
})

Asynchrone (Events)

// 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


Validations

  • Bounded contexts identifiés
  • 6 microservices définis
  • Communication sync/async définie
  • Clean Architecture par service validée
  • Event Bus (Supabase Realtime) testé

Prochaine révision : Si complexité trop élevée lors du développement