Où placer le code «demandant au monde» lorsque nous séparons le calcul des effets secondaires?

10

Selon le principe de séparation Command-Query , ainsi que les présentations Thinking in Data et DDD with Clojure , il convient de séparer les effets secondaires (modifiant le monde) des calculs et des décisions, afin qu'il soit plus facile de comprendre et de tester les deux parties.

Cela laisse une question sans réponse: où par rapport à la frontière devrions-nous mettre "demander au monde"? D'une part, la demande de données à des systèmes externes (comme la base de données, les API des services externes, etc.) n'est pas référentiellement transparente et ne doit donc pas être assortie d'un code informatique et décisionnel pur. D'un autre côté, il est problématique, ou peut-être impossible de les taquiner en dehors de la partie informatique et de les passer comme argument car nous ne savons peut-être pas à l'avance quelles données nous pouvons avoir besoin de demander.

Alexey
la source
1
C'est là qu'interviennent les concepts de rappels. Si vous ne savez pas à l'avance quelles données peuvent être nécessaires, fournissez un rappel au code de calcul où il peut spécifier les données dont il a besoin et demander aux autres couches d'effectuer la récupération et la fourniture proprement dites. . S'il doit être asynchrone, le rappel peut même spécifier une autre fonction à appeler avec les données extraites lorsqu'elles sont disponibles.
Marjan Venema
1
@MarjanVenema, c'est aussi la seule option qui me vient à l'esprit. Juste du point de vue théorique: si la méthode, sinon sans effet secondaire, invoque un rappel à effet secondaire, elle devient à effet secondaire. Mon problème ici est probablement que je suppose que le calcul de séparation des effets secondaires nécessite que le calcul soit référentiellement transparent. Bien que ce ne soit pas nécessairement vrai.
Alexey
1
Si tel est votre souci, votre calcul n'est tout simplement pas assez précis. Vous devez résumer la prise de décision quant aux autres données / étapes nécessaires. Donc, divisez le calcul complet en étapes en fonction de l'endroit où les décisions sont prises quant aux données nécessaires. Ensuite, ayez une sorte de "directeur" qui gère le flux de travail pour le calcul complet: démarrer chaque étape, récupérer les informations de chaque étape, l'utiliser pour décider de la prochaine étape et des données nécessaires, lancer un processus de récupération pour l'obtenir, puis passer les données extraites à l'étape suivante du calcul.
Marjan Venema

Réponses:

1

D'un autre côté, il est problématique, ou peut-être impossible de les taquiner en dehors de la partie informatique et de les passer comme argument car nous ne savons peut-être pas à l'avance quelles données nous pouvons avoir besoin de demander.

Il s'agit d'un cas où, comme indiqué dans les commentaires, transmettre la capacité de récupérer des données (par exemple, une fonction de première classe, un objet qui implémente une interface, etc.) fournit un mécanisme pratique pour isoler les effets secondaires.

Une fonction d'ordre supérieur dont le corps est pur a une pureté non fixée: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

J'ai écrit à ce sujet, appelant ce type de fonction une fonction potentiellement pure: http://adamjonrichardson.com/2014/01/13/potential-pure-functions/

Si vous combinez une fonction potentiellement pure avec des fonctions de substitution (qui manquent de constructions de branchement et en font le moins possible), une combinaison que j'appelle des ensembles d'isolement, vous pouvez isoler les effets secondaires assez efficacement et créer du code très testable: http: // adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/

Adam
la source
0

Vous stockez le résultat dans la classe, cela semble un peu étrange au début, mais cela donne un code plus simple. par exemple, aucune variable temporaire dans l'appelant.

class database_querier
    feature -- queries
        was_previous_query_ok : boolean is
            do
                Result = …
            end

        previous_query_result : string is 
            requires
                was_previous_query_ok
            do
                Result = query_result
            end

    feature -- commands
        query_db (…) is
            do
                …
                query_result = bla
            end

    feature {none} --data
        query_result : string
ctrl-alt-delor
la source
1
J'adore voir Eiffel dans la nature.
SBI
@sbi c'est juste du pseudo code. :-)
ctrl-alt-delor
Assez proche pour me faire plaisir;)
SBI