¿Dónde ponemos el código "preguntando al mundo" cuando separamos la computación de los efectos secundarios?

10

De acuerdo con el principio de Separación de consulta de comando , así como las presentaciones de Pensamiento en datos y DDD con Clojure , uno debe separar los efectos secundarios (modificar el mundo) de los cálculos y las decisiones, para que sea más fácil de entender y probar ambas partes.

Esto deja una pregunta sin respuesta: ¿en qué parte del límite deberíamos poner "preguntar al mundo"? Por un lado, solicitar datos de sistemas externos (como bases de datos, API de servicios externos, etc.) no es referencialmente transparente y, por lo tanto, no debe unirse a un código computacional y de toma de decisiones puro. Por otro lado, es problemático, o tal vez imposible, separarlos de la parte computacional y pasarlo como argumento porque puede que no sepamos de antemano qué datos podemos necesitar solicitar.

Alexey
fuente
1
Ahí es donde intervienen los conceptos de devoluciones de llamada. Si no sabe de antemano qué datos pueden necesitarse, proporcione una devolución de llamada al código computacional donde pueda especificar qué datos necesita, y haga que las otras capas se encarguen de proporcionar . Si necesita ser asíncrono, la devolución de llamada podría incluso especificar otra función para llamar con los datos recuperados cuando esté disponible.
Marjan Venema
1
@MarjanVenema, esta es la única opción que también me viene a la mente. Solo desde el punto de vista teórico: si el método, de lo contrario sin efectos secundarios, invoca la devolución de llamada con efecto secundario, se convierte en efecto secundario. Probablemente mi problema aquí es que supongo que el cálculo de separación de los efectos secundarios requiere que el cálculo sea referencialmente transparente. Aunque no es necesariamente cierto.
Alexey
1
Si esa es su preocupación, su cálculo simplemente no es lo suficientemente detallado. Debe resumir la toma de decisiones sobre qué otros datos / pasos se necesitan. Por lo tanto, divida el cómputo completo en pasos basados ​​en dónde se toman las decisiones sobre qué datos se necesitan. Luego, tenga algún tipo de "director" que gestione el flujo de trabajo para el cómputo completo: comenzar cada paso, recuperar la información de cada paso, usar eso para decidir el siguiente paso y los datos necesarios, comenzar un proceso de obtención para obtenerlo y luego pasar los datos obtenidos al siguiente paso en el cálculo.
Marjan Venema

Respuestas:

1

Por otro lado, es problemático, o tal vez imposible, separarlos de la parte computacional y pasarlo como argumento porque puede que no sepamos de antemano qué datos podemos necesitar solicitar.

Esta es una instancia en la que, como se señaló en los comentarios, pasar la capacidad de recuperar datos (por ejemplo, función de primera clase, un objeto que implementa una interfaz, etc.) proporciona un mecanismo conveniente para aislar los efectos secundarios.

Una función de orden superior cuyo cuerpo es puro tiene pureza no fija: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

He escrito sobre esto, llamando a este tipo de función una función potencialmente pura: http://adamjonrichardson.com/2014/01/13/potentially-pure-functions/

Si combina una función potencialmente pura con funciones de caída (que carecen de construcciones de ramificación y hacen lo menos posible), una combinación que llamo conjuntos de aislamiento, puede aislar los efectos secundarios de manera bastante efectiva y crear un código muy comprobable: http: // adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/

Adán
fuente
0

Almacena el resultado en la clase, esto parece un poco extraño al principio, pero da como resultado un código más simple. por ejemplo, no hay variables temporales en la persona que llama.

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
fuente
1
Me encanta ver a Eiffel en la naturaleza.
SBI
@sbi es solo un pseudocódigo. :-)
ctrl-alt-delor
Lo suficientemente cerca para hacerme feliz;)
SBI