image de chargement
Retour au glossaire

CQRS (Command Query Responsibility Segregation)

Pattern architectural séparant les opérations de lecture et d'écriture pour optimiser performance, scalabilité et maintenabilité des systèmes complexes.

Mis à jour le 9 janvier 2026

CQRS (Command Query Responsibility Segregation) est un pattern architectural qui sépare les opérations de modification des données (commandes) des opérations de lecture (requêtes). Cette séparation permet d'optimiser indépendamment chaque aspect du système, en utilisant des modèles de données et des stratégies de scalabilité adaptées à chaque type d'opération. Initialement popularisé par Greg Young, CQRS répond aux limitations des architectures CRUD traditionnelles dans les systèmes distribués à forte charge.

Fondements du pattern CQRS

  • Séparation stricte entre les opérations d'écriture (Commands) qui modifient l'état du système et les opérations de lecture (Queries) qui retournent des données
  • Utilisation de modèles de données distincts pour l'écriture (write model) optimisé pour la cohérence et la validation, et pour la lecture (read model) optimisé pour les performances
  • Synchronisation des modèles via des mécanismes de propagation d'événements, permettant une cohérence éventuelle (eventual consistency)
  • Découplage complet entre les responsabilités métier d'écriture et les besoins de consultation, facilitant l'évolution indépendante de chaque partie

Avantages stratégiques

  • Scalabilité optimale : possibilité de dimensionner indépendamment les infrastructures de lecture (souvent sollicitées à 90%) et d'écriture selon les besoins réels
  • Performance améliorée : les modèles de lecture peuvent être dénormalisés, pré-calculés et mis en cache pour des temps de réponse optimaux
  • Flexibilité des technologies : liberté d'utiliser des bases de données différentes (SQL pour l'écriture, NoSQL pour la lecture par exemple) selon les besoins spécifiques
  • Sécurité renforcée : séparation claire des responsabilités permettant des politiques d'accès granulaires entre opérations de lecture et d'écriture
  • Maintenabilité accrue : isolation des logiques métier complexes d'écriture des requêtes de consultation, réduisant la dette technique

Exemple concret d'implémentation

order-cqrs.ts
// ===== COMMANDES (Write Side) =====
interface CreateOrderCommand {
  customerId: string;
  items: OrderItem[];
  shippingAddress: Address;
}

class OrderCommandHandler {
  constructor(
    private eventStore: EventStore,
    private validator: OrderValidator
  ) {}

  async handle(command: CreateOrderCommand): Promise<string> {
    // Validation métier stricte
    await this.validator.validate(command);
    
    // Création de l'agrégat
    const order = Order.create(command);
    
    // Persistance des événements
    const events = order.getUncommittedEvents();
    await this.eventStore.save('order', order.id, events);
    
    return order.id;
  }
}

// ===== REQUÊTES (Read Side) =====
interface OrderSummaryQuery {
  customerId: string;
  page: number;
  pageSize: number;
}

interface OrderSummaryDto {
  orderId: string;
  orderDate: Date;
  totalAmount: number;
  status: string;
  itemCount: number;
}

class OrderQueryHandler {
  constructor(private readDb: ReadDatabase) {}

  async handle(query: OrderSummaryQuery): Promise<OrderSummaryDto[]> {
    // Lecture directe depuis le modèle dénormalisé
    return this.readDb.query(`
      SELECT 
        order_id,
        order_date,
        total_amount,
        status,
        item_count
      FROM order_summaries
      WHERE customer_id = $1
      ORDER BY order_date DESC
      LIMIT $2 OFFSET $3
    `, [query.customerId, query.pageSize, query.page * query.pageSize]);
  }
}

// ===== SYNCHRONISATION =====
class OrderProjection {
  async onOrderCreated(event: OrderCreatedEvent): Promise<void> {
    // Mise à jour du read model
    await this.readDb.insert('order_summaries', {
      order_id: event.orderId,
      customer_id: event.customerId,
      order_date: event.timestamp,
      total_amount: event.totalAmount,
      status: 'pending',
      item_count: event.items.length
    });
  }

  async onOrderShipped(event: OrderShippedEvent): Promise<void> {
    await this.readDb.update('order_summaries', 
      { order_id: event.orderId },
      { status: 'shipped' }
    );
  }
}

Mise en œuvre progressive

  1. Identifier les bounded contexts où CQRS apporte une vraie valeur (forte charge en lecture, logique métier complexe en écriture)
  2. Définir clairement les commandes métier avec leurs règles de validation et les requêtes avec leurs besoins de performance
  3. Implémenter le write model avec event sourcing ou persistance traditionnelle selon la complexité métier
  4. Créer les projections pour construire les read models optimisés, en utilisant des vues matérialisées ou bases dédiées
  5. Mettre en place les mécanismes de synchronisation (message bus, CDC, polling) avec gestion de la cohérence éventuelle
  6. Monitorer les délais de propagation et ajuster la stratégie de synchronisation selon les SLA métier
  7. Documenter les modèles de consistance pour que les équipes comprennent les garanties offertes

Conseil d'architecture

CQRS n'est pas un pattern à appliquer partout. Réservez-le aux parties du système où le ratio lecture/écriture est déséquilibré (>70% de lectures) ou où la logique métier d'écriture est complexe. Pour les CRUD simples, une architecture classique reste plus appropriée et maintenable.

Outils et frameworks associés

  • Axon Framework (Java) : framework complet pour CQRS et Event Sourcing avec support distribué
  • NestJS CQRS (TypeScript/Node.js) : module intégré offrant commands, queries et event handlers
  • MediatR (.NET) : bibliothèque légère pour implémenter le pattern mediator sous-jacent à CQRS
  • EventStore : base de données spécialisée pour l'event sourcing, souvent combinée à CQRS
  • Apache Kafka / RabbitMQ : message brokers pour la synchronisation entre write et read models
  • PostgreSQL avec LISTEN/NOTIFY : solution économique pour la propagation d'événements
  • Redis : cache pour les read models haute performance avec support de pub/sub

CQRS transforme radicalement la manière de concevoir les systèmes en reconnaissant que lecture et écriture ont des besoins fondamentalement différents. Bien que plus complexe qu'une architecture CRUD traditionnelle, ce pattern apporte des gains mesurables en termes de performance, scalabilité et évolutivité pour les systèmes à forte charge ou logique métier complexe.

L'argentestdéjàsurlatable.

En 1 heure, découvrez exactement combien vous perdez et comment le récupérer.