Je dois faire un compromis: SEC, ou Commande-Requête-Séparation?


10

J'ai récemment refactorisé une méthode qui était à la fois une commande et une méthode de requête.

Après l'avoir séparée en une méthode de commande et une méthode de requête, j'ai trouvé qu'il y a maintenant plusieurs endroits dans le code où j'appelle la commande puis j'obtiens la valeur de la requête, ce qui semble être une violation du principe DRY.

Mais si je devais envelopper ce code commun dans une méthode, cette méthode serait à la fois une commande et une requête. Est-ce acceptable?


D'accord, je ne savais pas si la communauté était à un consensus et je n'ai trouvé aucune discussion sur ce sujet.
Kris Welsh

Il est plus communément appelé CQRS google.com.au/…
Daniel Little

@DanielLittle - non ce n'est pas. CQS et CQRS sont des sujets très différents. CQRS est un modèle architectural beaucoup plus impliqué tandis que CQS est plus un modèle de conception et beaucoup plus facile à saisir et à mettre en œuvre. Voir codebetter.com/gregyoung/2009/08/13/command-query-separation
Erik Funkenbusch

@Erik Funkenbusch Vous avez raison
Daniel Little

Réponses:


11

Il y a toujours des compromis à considérer entre des principes de conception contradictoires. La façon de le résoudre consiste à examiner les raisons sous-jacentes des principes. Dans ce cas, l'impossibilité d'exécuter une requête sans exécuter la commande est problématique, mais l'impossibilité d'exécuter une commande sans exécuter la requête est généralement inoffensive. Tant qu'il existe un moyen d'exécuter la requête de manière autonome, je ne vois aucune raison de ne pas ajouter le résultat de la requête à la commande, surtout si vous faites quelque chose comme ceci:

QueryResult command()
{
   // do command stuff
   return query();
}

4

Je n'ai jamais entendu parler de Command-Query-Separation (CQS) auparavant, mais il semble que cela se rapporte au principe de responsabilité unique (SRP), qui stipule qu'une fonction / classe devrait idéalement être responsable de faire une chose et une seule chose .

Si votre code de commande est de 20 lignes de code et que le code de requête est de 30 autres lignes et qu'elles sont toutes dans un corps de fonction, il est clair que vous violez SRP et je suppose également que CQS et ces deux éléments de logique doivent être séparés l'un de l'autre .

Cependant, en suivant votre exemple hypothétique, je créerais très probablement une méthode wrapper qui combinerait votre commande et votre requête afin que DRY ne soit pas violé à de nombreux endroits du code. Je ne considérerais pas non plus qu'il s'agit d'une violation SRP (et peut-être CQS), car l'encapsuleur n'a toujours qu'une seule responsabilité: combiner la commande avec une requête et créer une abstraction de niveau supérieur plus facile à consommer.

Je pense que la méthode wrapper est une solution parfaitement acceptable et pour illustrer cela, prenons votre exemple un peu plus loin. Et si vous deviez exécuter 2 requêtes au lieu de 1, puis exécuter une action de commande en fonction de cela. Donc, vos 2 lignes de code seraient 6 ou 8. Et s'il y avait une validation / vérification des données entre l'une et l'autre, alors maintenant vous avez 15 lignes de code. Souhaitez-vous réfléchir à deux fois pour créer un wrapper qui fait tout cela, plutôt que de saupoudrer ces 15 lignes dans plusieurs fichiers?


Je pense que le "principe unique" d'un wrapper devrait être de garder les autres méthodes qui nécessitent la commande et la requête ensemble DRY.
Droogans


Bien que la solution de Karl à ce problème soit meilleure, je trouve que votre élaboration sur des fonctions d'emballage plus longues est un très bon point.
Kris Welsh

-3

DRY est plus important, car il résout un besoin beaucoup plus fondamental - éviter les efforts redondants et efficacement gaspillés. C'est une chose fondamentale - il n'est pas nécessaire d'être programmeur pour le comprendre.

CQS est une réponse à la difficulté, dans les langages ne prenant pas en charge les effets de suivi, de comprendre le code qui est exécuté à la fois pour ses résultats et ses effets. Toutefois:

  1. La nécessité d'exécuter du code pour ses résultats ne peut être évitée, car c'est la base pour composer de grands programmes à partir de petites unités.

  2. La nécessité d'exécuter du code pour ses effets ne peut pas non plus être évitée, car, en dehors des mathématiques et de l'informatique théorique, la valeur de l'exécution d'un programme dépend de ce qu'il peut faire pour nous.

  3. La nécessité de provoquer des effets et de produire des résultats dans le même code ne peut être évitée, car, dans la pratique, nous avons besoin à la fois des effets et de la compositionnalité, et pas seulement l'un ou l'autre.

La véritable solution au problème des effets de suivi trop difficiles pour les humains sans aide est, bien sûr, que les ordinateurs nous aident les humains ! Une chose similaire peut être dite à propos du suivi des relations complexes entre les valeurs d'exécution (telles que la validité des indices de tableau), pour lesquelles les exceptions et les contrats exécutés à l'exécution constituent des (non) solutions.

En conclusion, des «solutions» comme CQS ne font qu'entraver la conception de programmes selon des principes solides basés sur la réalité. Optez pour SEC.


Parfois, vous devez éviter le couplage afin de réduire la complexité. Vous devriez jeter un œil au CQRS.
Daniel Little

@Lavinski: Le meilleur outil pour éviter la complexité (ne pas la diminuer, c'est futile) est l'abstraction - découplant l'essence générique des problèmes que nous résolvons des détails particuliers des instances de ces problèmes génériques. Des recettes magiques (ou «modèles de conception», d'après ce que j'entends dire) peuvent au mieux vous empêcher de causer trop de dégâts lorsque votre conception est mauvaise, mais elles ne peuvent pas transformer une mauvaise conception en la bonne.
pyon

@Lavinski: En ce qui concerne spécifiquement le CQRS, la solution alternative conceptuellement correcte est 1. comprendre le modèle de données (aucune quantité de couches d'objets ne peut en éliminer la nécessité), 2. encoder autant de propriétés d'exactitude que possible dans le schéma de base de données. (Malheureusement, les SGBDR les plus populaires fournissent un support assez limité pour ces derniers, sans parler de ceux de NoSQL, qui se trompent encore plus. Mes recherches actuelles fournissent une meilleure solution pour cela.)
pyon

Le CQRS fonctionne parfaitement en ligne avec la conception pilotée par domaine. Le domaine à l'intérieur de l'application doit appliquer l'exactitude et non votre magasin de données.
Daniel Little

1
@ EduardoLeón: Si vous voulez prouver que votre conception est correcte, essayez d'écrire des tests pour votre programme. Je peux vous garantir que jeter CQS ne fera qu'entraver vos efforts.
Stefan Billiet
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.