Origen de "un método debe devolver un valor o tener efectos secundarios, pero no ambos"

12

Una vez leí que un método debería tener un valor de retorno (y ser referencialmente transparente) o tener efectos secundarios, pero no ambos. No puedo encontrar ninguna referencia a esta regla, pero quiero obtener más información al respecto.

¿Cuál es el origen de este consejo? ¿De qué persona o comunidad surgió?

Crédito adicional: ¿Cuál es el beneficio reclamado de seguir este consejo?

Wayne Conrad
fuente
1
@gnat Sí, se trata principalmente de historia. Temía que la parte de crédito adicional fuera demasiado subjetiva para sostenerse por sí sola, y que la historia tenía una mejor oportunidad de escapar del cierre. Agregaré la etiqueta.
Wayne Conrad
algunas de las respuestas que se acumulan me hicieron preguntarme si usted pregunta sobre el beneficio reclamado por un autor de este consejo o por una lista de todos los beneficios que es posible reclamar.
mosquito
@gnat Pregunto sobre el beneficio reclamado por el autor (de nuevo, temiendo el cierre), pero seguro que no me importan los motivos acumulados: están respondiendo la pregunta que realmente quería hacer. Si tuviera que eliminar "reclamado" de mi pregunta, haciendo las respuestas sobre el tema, ¿empujaría la pregunta demasiado hacia lo subjetivo?
Wayne Conrad
Es probable que los "motivos acumulados" hagan que la pregunta se cierre como demasiado amplia . Si prefiere "permanecer en el lado abierto", creo que sería más seguro reducirlo en beneficio de lo que afirmó el autor
mosto
Un beneficio es que si le pagan por volumen de código, esto produce un extra. "doSomething; GetResultOfSomething; HandleErrorsFromSomething;"
En

Respuestas:

13

Según Greg Young, esta idea se originó a partir de Bertrand Meyer : separación entre comando y consulta .

Establece que cada método debe ser un comando que realiza una acción o una consulta que devuelve datos al llamante, pero no ambos. En otras palabras, hacer una pregunta no debería cambiar la respuesta . 1 Más formalmente, los métodos deberían devolver un valor solo si son referencialmente transparentes y, por lo tanto, no poseen efectos secundarios.

1: Eiffel: un lenguaje para la ingeniería de software diapositiva 43-48

En el diseño impulsado por dominio, esto es similar a la separación / segregación comando-consulta-lectura (CQRS), como lo nombra Greg Young.

Greg Young tomó la idea de CQS de Bertrand para nombrar CQRS como lo menciona Martin Fowler en este artículo de CQRS

Beneficios

  • La parte de lectura (consulta) se puede escalar / ajustar de manera diferente a la parte de escritura (comando). Separar los dos evitaría que cualquiera se interpusiera entre sí cuando la optimización / rendimiento es clave.

Lea el artículo en el enlace de Martin Fowler para más información.

tunmise fasipe
fuente
1
Naturalmente, en muchas situaciones, generar un resultado útil y realizar algunas modificaciones al mismo tiempo no es más costoso que hacer el más difícil de los dos por separado.
Deduplicador
1
@Deduplicator ¿Un ejemplo cliché es InterlockedCompareExchange?
En
1
Sin embargo, este consejo obviamente no se aplica cuando la devolución es alguna información sobre lo que se hizo en el comando; sin embargo, un método para eliminar filas de un conjunto de datos puede cambiar el estado del conjunto de datos, eliminando las filas indicadas de acuerdo con un criterio dado, y luego devuelve el número de filas eliminadas o incluso una lista con dichas filas.
T. Sar
4

No sé de dónde viene, pero es un buen consejo y bastante sencillo de entender.

Cualquier programa diseñado de manera sensata se dividirá en varias partes, combinadas y compuestas de varias maneras. Cuanto más difícil sea razonar sobre lo que hace una parte en particular, más difícil será asegurarse de que su programa reaccionará de manera predecible.

Aislar las partes que producen efectos secundarios hace que el resto sea más fácil de razonar, probar y depurar. Reducir el número de efectos secundarios en cada parte que genera un efecto secundario hará que esa parte sea más fácil de trabajar de la misma manera.

Si lo descompone aún más, un valor de retorno es un efecto. Los efectos secundarios son un efecto. Una función solo debería producir 1 efecto (si es posible) porque cuanto mayor sea el número de entradas y efectos que tenga una función, mayor será la dificultad de razonar sobre lo que realmente hace.

Morgen
fuente
esto ni siquiera intenta abordar la pregunta formulada, vea Cómo responder
mosquito
@gnat Mi pregunta se dividió en dos partes: la pregunta principal ("quién") y el crédito adicional ("por qué". ¿No aborda esto la parte de crédito adicional?
Wayne Conrad
según mi lectura (" beneficio reclamado "), se espera que la parte por qué sea una propuesta por el autor de la cita. Parece que la pregunta no es pedir una lista de todos los beneficios posibles
mosquito
2
@gnat Entendí la pregunta como un intento de entender este consejo, tanto la razón detrás como el contexto en el que se dio. No creo que fuera inapropiado abordar solo una parte de la pregunta.
Morgen
1

Crédito adicional: ¿Cuál es el beneficio originalmente reclamado de seguir este consejo?

Uno de los beneficios de separar el valor de retorno de los efectos secundarios es que elimina un problema potencial que puede ser causado por la evaluación de cortocircuito .

bool FooWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

bool BarWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

void BadShortCircuitEvaluation()
{
    // the programmer's intent is to have side effects of both functions
    if (FooWithSideEffect() && BarWithSideEffect() ) {
        // do something
    }

    // in case FooWithSideEffect() returns true, 
    // then BarWithSideEffect() is not called at all
    // because of short-circuit evaluation
}
Nick Alexeev
fuente
¿Es este un beneficio reclamado por el autor del consejo ?
mosquito
@gnat Tengo confusión histórica y práctica, me temo.
Nick Alexeev
1
el comentario y el código no coinciden, no se llama a BarWithSideEffects si FooWithSideEffects devuelve false
jk.