Wo setzen wir den Code "Fragen an die Welt" ein, wenn wir die Berechnung von den Nebenwirkungen trennen?

10

Nach dem Prinzip der Trennung von Befehlen und Abfragen sowie dem Denken in Daten und DDD mit Clojure- Präsentationen sollten Nebenwirkungen (die die Welt verändern) von Berechnungen und Entscheidungen getrennt werden, damit beide Teile leichter zu verstehen und zu testen sind.

Dies lässt eine unbeantwortete Frage offen: Wo sollten wir relativ zur Grenze "die Welt fragen" setzen? Einerseits ist das Anfordern von Daten von externen Systemen (wie Datenbanken, APIs von Extental Services usw.) nicht referenziell transparent und sollte daher nicht mit reinem Rechen- und Entscheidungscode zusammenpassen. Auf der anderen Seite ist es problematisch oder unmöglich, sie vom rechnerischen Teil zu trennen und als Argument zu übergeben, da wir möglicherweise nicht im Voraus wissen, welche Daten wir möglicherweise anfordern müssen.

Alexey
quelle
1
Hier kommen die Konzepte von Rückrufen ins Spiel. Wenn Sie nicht im Voraus wissen, welche Daten möglicherweise benötigt werden, geben Sie einen Rückruf an den Rechencode, in dem angegeben werden kann, welche Daten benötigt werden, und lassen Sie die anderen Ebenen das eigentliche Abrufen und Bereitstellen durchführen . Wenn es asynchron sein muss, kann der Rückruf sogar eine andere Funktion angeben, die mit den abgerufenen Daten aufgerufen werden soll, wenn sie verfügbar sind.
Marjan Venema
1
@ MarjanVenema, dies ist die einzige Option, die mir ebenfalls in den Sinn kommt. Nur aus theoretischer Sicht: Wenn die Methode, ansonsten ohne Nebenwirkungen, einen rückwirkenden Rückruf hervorruft, wird sie nebenwirkend. Wahrscheinlich ist mein Problem hier, dass ich davon ausgehe, dass die Berechnung der Trennung von Nebenwirkungen eine referenzielle Transparenz erfordert. Obwohl es nicht unbedingt wahr ist.
Alexey
1
Wenn das Ihre Sorge ist, ist Ihre Berechnung einfach nicht fein genug. Sie müssen die Entscheidungsfindung darüber abstrahieren, welche anderen Daten / Schritte benötigt werden. Teilen Sie die vollständige Berechnung in Schritte auf, je nachdem, wo Entscheidungen darüber getroffen werden, welche Daten benötigt werden. Dann haben Sie eine Art "Director", der den Workflow für die vollständige Berechnung verwaltet: Starten jedes Schritts, Abrufen von Informationen aus jedem Schritt, Entscheiden des nächsten Schritts und der benötigten Daten, Starten eines Abrufprozesses, um sie abzurufen, und Weitergeben die abgerufenen Daten zum nächsten Schritt in der Berechnung.
Marjan Venema

Antworten:

1

Auf der anderen Seite ist es problematisch oder unmöglich, sie vom rechnerischen Teil zu trennen und als Argument zu übergeben, da wir möglicherweise nicht im Voraus wissen, welche Daten wir möglicherweise anfordern müssen.

Dies ist ein Fall, in dem, wie in den Kommentaren erwähnt, die Übergabe der Fähigkeit zum Abrufen von Daten (z. B. erstklassige Funktion, ein Objekt, das eine Schnittstelle implementiert usw.) einen bequemen Mechanismus zum Isolieren von Nebenwirkungen bietet.

Eine Funktion höherer Ordnung, deren Körper rein ist, hat eine nicht festgelegte Reinheit: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

Ich habe darüber geschrieben und diese Art von Funktion als potenziell reine Funktion bezeichnet: http://adamjonrichardson.com/2014/01/13/potential-pure-functions/

Wenn Sie eine potenziell reine Funktion mit Fall-Through-Funktionen kombinieren (denen Verzweigungskonstrukte fehlen und die so wenig wie möglich tun), eine Kombination, die ich Isolationssätze nenne, können Sie Nebenwirkungen sehr effektiv isolieren und sehr testbaren Code erstellen: http: // adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/

Adam
quelle
0

Sie speichern das Ergebnis in der Klasse, dies scheint zunächst etwas seltsam, führt jedoch zu einfacherem Code. zB keine temporären Variablen im Aufrufer.

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
Strg-Alt-Delor
quelle
1
Ich liebe es, Eiffel in freier Wildbahn zu sehen.
SBI
@sbi es ist nur Pseudocode. :-)
Strg-Alt-Delor
Nah genug, um mich glücklich zu machen;)
SBI