Séparation commande-requête

Un article de Wikipédia, l'encyclopédie libre.

La séparation commande-requête (Command–query separation, CQS) est un principe de la programmation impérative. Elle a été conçue par Bertrand Meyer dans le cadre de ses travaux pionniers sur le langage de programmation Eiffel.

Elle stipule que chaque méthode doit être une commande qui effectue une action ou une requête qui renvoie des données à l'appelant, mais pas les deux. En d'autres termes, Poser une question ne devrait pas changer la réponse[1]. Plus formellement, les méthodes ne devraient retourner une valeur que si elles sont référentiellement transparentes et ne possèdent donc pas d'effets de bord.

Connexion avec la conception par contrat[modifier | modifier le code]

La séparation commande-requête est particulièrement bien adaptée à une méthodologie de conception par contrat (DbC), dans laquelle la conception d'un programme est exprimée sous la forme d'assertions intégrées dans le code source, décrivant l'état du programme à certains moments critiques. Dans la DbC, les assertions sont considérées comme des annotations de conception – et non comme une logique de programme – et en tant que telles, leur exécution ne devrait pas affecter l'état du programme. La CQS est bénéfique pour la DbC parce que la valeur de retour de la méthode (toute requête) peut être appelée par n'importe quelle assertion sans crainte de modifier l'état du programme.

En termes théoriques, cela établit une mesure de cohérence, par laquelle on peut raisonner sur l'état d'un programme sans modifier simultanément cet état. Concrètement, la CQS permet de contourner tous les contrôles d'assertions dans un système fonctionnel pour améliorer ses performances sans modifier involontairement son comportement. La CQS peut également prévenir l'apparition de certains types de heisenbugs.

Impact plus large sur le génie logiciel[modifier | modifier le code]

Même au-delà du lien avec la conception par contrat, la CQS est considérée par ses adhérents comme ayant un effet simplificateur sur un programme, rendant ses états (via des requêtes) et les changements d'états (via des commandes) plus compréhensibles. [réf. nécessaire]

La CQS est bien adaptée à la méthodologie orientée objet, mais peut également être appliquée en dehors de la programmation orientée objet. Comme la séparation des effets secondaires et des valeurs de retour n'est pas intrinsèquement orientée objet, la CQS peut être appliquée de façon rentable à tout paradigme de programmation qui exige un raisonnement sur les effets secondaires.[réf. nécessaire]

Inconvénients[modifier | modifier le code]

La CQS peut rendre plus difficile à mettre en œuvre correctement des logiciels réentrants et multithread. Cela se produit généralement lorsqu'un patron de conception non thread-safe est utilisé pour mettre en œuvre la séparation commande–requête.

Voici un exemple simple d'un modèle qui casse les principes CQS mais qui est utile pour les logiciels multi-threaded. Il casse les principes CQS parce que la fonction à la fois mute l'état et le renvoie :

private int x;
public int increment_and_return_x() {
  lock x;   // by some mechanism
  x = x + 1;
  int x_copy = x;
  unlock x; // by some mechanism
  return x_copy;
}

Voici un modèle conforme à la CQS. Cependant, il n'est utilisable en toute sécurité que dans des applications mono-thread. Dans un programme multithreadé, il y a une situation de compétition dans l'appelant, entre le moment où seraient appelés increment() et value() :

private int x;
public int value() {
  return x;
}
void increment() {
  x = x + 1;
}

Même dans les programmes mono-thread, il est parfois beaucoup plus pratique d'avoir une méthode qui est une requête et une commande combinées. Martin Fowler cite la méthode pop() d'une pile comme exemple[2].

Voir aussi[modifier | modifier le code]

Références[modifier | modifier le code]

  1. (en) Bertrand Meyer, « Eiffel: a language for software engineering » [PDF] (consulté le ), p. 22
  2. (en) Martin Fowler, « CommandQuerySeparation » (consulté le )

Liens externes[modifier | modifier le code]