¿Por qué los efectos secundarios se consideran malos en la programación funcional?

69

Siento que los efectos secundarios son un fenómeno natural. Pero es algo así como un tabú en lenguajes funcionales. ¿Cuales son las razones?

Mi pregunta es específica del estilo de programación funcional. No todos los lenguajes / paradigmas de programación.

Gulshan
fuente
66
Un programa sin efectos secundarios es inútil, por lo que los efectos secundarios no son ni malos ni tabú. Pero FP encierra delimitando el código con efectos secundarios, por lo que una parte del código tan grande como sea posible son funciones libres de efectos secundarios. Esto se recomienda porque las funciones y subsistemas libres de efectos secundarios son más fáciles de entender, más fáciles de analizar, más fáciles de probar y más fáciles de optimizar.
JacquesB
@JacquesB Sería una buena respuesta explicar por qué son más fáciles de entender, más fáciles de analizar, más fáciles de probar y más fáciles de optimizar.
ceving

Respuestas:

72

Escribir sus funciones / métodos sin efectos secundarios, por lo que son funciones puras , hace que sea más fácil razonar sobre la corrección de su programa.

También facilita la composición de esas funciones para crear un nuevo comportamiento.

También hace posibles ciertas optimizaciones, donde el compilador puede, por ejemplo, memorizar los resultados de las funciones o usar la Eliminación de subexpresión común.

Editar: a pedido de Benjol: debido a que gran parte de su estado está almacenado en la pila (flujo de datos, no flujo de control, como Jonas lo ha llamado aquí ), puede paralelizar o reordenar la ejecución de aquellas partes de su cálculo que son independientes de El uno al otro. Puede encontrar fácilmente esas partes independientes porque una parte no proporciona entradas a la otra.

En entornos con depuradores que le permiten revertir la pila y reanudar la computación (como Smalltalk), tener funciones puras significa que puede ver muy fácilmente cómo cambia un valor, porque los estados anteriores están disponibles para inspección. En un cálculo con mucha mutación, a menos que agregue explícitamente acciones de hacer / deshacer a su estructura o algoritmo, no podrá ver el historial del cálculo. (Esto se relaciona con el primer párrafo: escribir funciones puras facilita la inspección de la corrección de su programa).

Frank Shearar
fuente
44
¿Quizás considere agregar algo sobre concurrencia en su respuesta?
Benjol
55
Las funciones libres de efectos secundarios son más fáciles de probar y reutilizar.
LennyProgrammers
@ Lenny222: reutilizar era lo que estaba insinuando al hablar sobre la composición de funciones.
Frank Shearar
@ Frank: Ah, está bien, navegación demasiado superficial. :)
LennyProgrammers
@ Lenny222: Está bien; Probablemente sea bueno explicarlo.
Frank Shearar
23

De un artículo sobre programación funcional :

En la práctica, las aplicaciones deben tener algunos efectos secundarios. Simon Peyton-Jones, uno de los principales contribuyentes al lenguaje de programación funcional Haskell, dijo lo siguiente: "Al final, cualquier programa debe manipular el estado. Un programa que no tiene efectos secundarios es una especie de recuadro negro. Todo lo que puede decir es que la caja se calienta ". ( http://oscon.blip.tv/file/324976 ) La clave es limitar los efectos secundarios, identificarlos claramente y evitar dispersarlos por todo el código.

Peter Stuifzand
fuente
23

Se equivocó, la programación funcional promueve la limitación de los efectos secundarios para que los programas sean fáciles de entender y optimizar. Incluso Haskell te permite escribir en archivos.

Esencialmente, lo que digo es que los programadores funcionales no piensan que los efectos secundarios sean malos, simplemente piensan que limitar el uso de los efectos secundarios es bueno. Sé que puede parecer una distinción tan simple, pero hace toda la diferencia.

ChaosPandion
fuente
Es por eso que son "algo así como un tabú": los FPL lo alientan a limitar los efectos secundarios.
Frank Shearar
+1 para el enfoque. Los efectos secundarios todavía existen. de hecho, son limitados
Belun
Para aclarar, no he dicho "por qué los efectos secundarios no están permitidos en la programación funcional" o "por qué no se necesitan efectos secundarios". Sé que está permitido en lenguajes funcionales y, a veces, es imprescindible. Pero está muy desanimado en la programación funcional. ¿Por qué? Esa fue mi pregunta.
Gulshan
@Gulshan: porque los efectos secundarios hacen que los programas sean más difíciles de comprender y optimizar.
ChaosPandion
en el caso de haskell, el punto principal no es "limitar los efectos secundarios". los efectos secundarios son imposibles de expresar en el IDIOMA. lo que las funciones readFileestán haciendo es definir una secuencia de acciones. esta secuencia es funcionalmente pura y es como un árbol abstracto que describe QUÉ hacer. los efectos secundarios sucios reales son llevados a cabo por el tiempo de ejecución.
sara
13

Algunas notas

  • Las funciones sin efectos secundarios se pueden ejecutar triviamente en paralelo, mientras que las funciones con efectos secundarios generalmente requieren algún tipo de sincronización.

  • Las funciones sin efectos secundarios permiten una optimización más agresiva (p. Ej., Usando transparentemente un caché de resultados), porque mientras obtengamos el resultado correcto, ni siquiera importa si la función se ejecutó realmente o no.

usuario281377
fuente
Punto muy interesante: ni siquiera importa si la función se ejecutó realmente o no . Sería interesante terminar con un compilador que pueda deshacerse de las llamadas posteriores a funciones libres de efectos secundarios dados parámetros equivalentes.
Noel Widmer el
1
@NoelWidmer Algo así ya existe. El PL / SQL de Oracle ofrece una deterministiccláusula para funciones sin efectos secundarios, por lo que no se ejecutan más de lo necesario.
user281377
¡Guauu! Sin embargo, creo que los lenguajes deberían ser semánticamente expresivos para que el compilador pueda resolverlo por sí mismo sin tener que especificar un indicador explícito (no estoy seguro de qué es una cláusula). Una solución podría ser especificar parámetros para que sean mutables / inmutables. En términos generales, esto requeriría un sistema de tipo fuerte en el que el compilador pueda hacer suposiciones sobre los efectos secundarios. Y la función debería poder desactivarse si se desea. Opt-out en lugar de opt-in. Esa es solo mi opinión, basada en el conocimiento limitado que tengo desde que leí tu respuesta :)
Noel Widmer
La deterministiccláusula es solo una palabra clave que le dice al compilador que esta es una función determinista, comparable a cómo la finalpalabra clave en Java le dice al compilador que la variable no puede cambiar.
usuario281377
11

Principalmente trabajo en código funcional ahora, y desde esa perspectiva parece cegadoramente obvio. Los efectos secundarios crean una enorme carga mental para los programadores que intentan leer y comprender el código. No notas esa carga hasta que te liberas de ella por un tiempo, luego de repente tienes que leer el código con efectos secundarios nuevamente.

Considere este simple ejemplo:

val foo = 42
// Several lines of code you don't really care about, but that contain a
// lot of function calls that use foo and may or may not change its value
// by side effect.

// Code you are troubleshooting
// What's the expected value of foo here?

En un lenguaje funcional, que footodavía es 42. Ni siquiera tengo que mirar el código intermedio, mucho menos entenderlo, o mirar las implementaciones de las funciones que llama.

Todo lo relacionado con la concurrencia, la paralelización y la optimización es bueno, pero eso es lo que los científicos informáticos ponen en el folleto. No tener que preguntarme quién está mutando su variable y cuándo es lo que realmente disfruto en la práctica diaria.

Karl Bielefeldt
fuente
6

Pocos idiomas o ninguno hacen que sea imposible causar efectos secundarios. Los idiomas que eran completamente libres de efectos secundarios serían prohibitivamente difíciles de usar (casi imposibles), excepto en una capacidad muy limitada.

¿Por qué los efectos secundarios se consideran malvados?

Porque hacen que sea mucho más difícil razonar sobre exactamente lo que hace un programa y demostrar que hace lo que usted espera que haga.

A un nivel muy alto, imagine probar un sitio web completo de 3 niveles con solo pruebas de recuadro negro. Claro, es factible, dependiendo de la escala. Pero ciertamente hay mucha duplicación. Y si no es un error (que se relaciona con un efecto secundario), entonces se podría potencialmente romper todo el sistema para su análisis posterior, hasta que el fallo se diagnostica y fija, y la solución se implementa en el entorno de prueba.

Beneficios

Ahora, reduzca eso. Si fuera bastante bueno escribiendo código libre de efectos secundarios, ¿cuánto más rápido sería razonando sobre lo que hizo algún código existente? ¿Cuánto más rápido podrías escribir pruebas unitarias? ¿Qué tan seguro se sentiría que el código sin efectos secundarios se garantiza libre de errores, y que los usuarios podrían limitar su exposición a cualquier error que no tiene?

Si el código no tiene efectos secundarios, el compilador también puede tener optimizaciones adicionales que podría realizar. Puede ser mucho más fácil implementar esas optimizaciones. Puede ser mucho más fácil incluso conceptualizar una optimización para el código libre de efectos secundarios, lo que significa que el proveedor del compilador podría implementar optimizaciones que son difíciles de imposibles en el código con efectos secundarios.

La concurrencia también es drásticamente más simple de implementar, generar automáticamente y optimizar cuando el código no tiene efectos secundarios. Esto se debe a que todas las piezas se pueden evaluar de forma segura en cualquier orden. Permitir que los programadores escriban código altamente concurrente se considera ampliamente el próximo gran desafío que la Ciencia de la Computación debe enfrentar, y uno de los pocos coberturas restantes contra la Ley de Moore .

Merlyn Morgan-Graham
fuente
1
Ada hace que sea muy difícil causar efectos secundarios. Sin embargo, no es imposible, pero claramente sabes lo que haces entonces.
Mouviciel
@mouviciel: Creo que hay al menos algunos lenguajes útiles que hacen que los efectos secundarios sean muy difíciles, y trato de relegarlos a las mónadas.
Merlyn Morgan-Graham
4

Los efectos secundarios son como "filtraciones" en su código que deberán ser manejadas más tarde, ya sea por usted o por algún compañero desprevenido.

Los lenguajes funcionales evitan las variables de estado y los datos mutables como una forma de hacer que el código sea menos dependiente del contexto y más modular. La modularidad asegura que el trabajo de un desarrollador no afectará / socavará el trabajo de otro.

Escalar la tasa de desarrollo con el tamaño del equipo es hoy un "santo grial" del desarrollo de software. Cuando se trabaja con otros programadores, pocas cosas son tan importantes como la modularidad. Incluso el más simple de los efectos secundarios lógicos hace que la colaboración sea extremadamente difícil.

Ami
fuente
+1 - "o algún compañero desprevenido"
Merlyn Morgan-Graham
1
-1 para los efectos secundarios como "fugas que deben manejarse". La creación de "efectos secundarios" (código no funcional puro) es el propósito completo de escribir cualquier programa de computadora no trivial.
Mason Wheeler
Este comentario llega seis años después, pero hay efectos secundarios y luego hay efectos secundarios. El tipo de efectos secundarios deseables, hacer E / S, etc., son realmente necesarios para cualquier programa, porque de alguna manera debe proporcionar sus resultados al usuario , pero el otro tipo de efectos secundarios, donde su código cambia de estado sin un buen razones como hacer E / S, de hecho, son una "fuga" que deberá manejarse más tarde. La idea básica es la separación comando-consulta : una función que devuelve un valor no debería tener un efecto secundario.
rmunn
4

Bueno, en mi humilde opinión, esto es bastante hipócrita. A nadie le gustan los efectos secundarios, pero todos los necesitan.

Lo que es tan peligroso acerca de los efectos secundarios es que si llama a una función, esto posiblemente tenga un efecto no solo en la forma en que se comporta la función la próxima vez, sino que posiblemente tenga este efecto en otras funciones. Por lo tanto, los efectos secundarios introducen comportamientos impredecibles y dependencias no triviales.

Los paradigmas de programación como OO y funcional abordan este problema. OO reduce el problema al imponer una separación de preocupaciones. Esto significa que el estado de la aplicación, que consta de muchos datos mutables, se encapsula en objetos, cada uno de los cuales es responsable de mantener solo su propio estado. De esta forma, se reduce el riesgo de dependencias y los problemas están mucho más aislados y son más fáciles de rastrear.

La programación funcional adopta un enfoque mucho más radical, donde el estado de la aplicación es simplemente inmutable desde la perspectiva del programador. Esta es una buena idea, pero hace que el lenguaje sea inútil por sí solo. ¿Por qué? Porque CUALQUIER operación de E / S tiene efectos secundarios. Tan pronto como lea de cualquier flujo de entrada, es probable que cambie el estado de su aplicación, porque la próxima vez que invoque la misma función, es probable que el resultado sea diferente. Puede estar leyendo datos diferentes o, también una posibilidad, la operación podría fallar. Lo mismo es cierto para la salida. Incluso la salida es una operación con efectos secundarios. Esto no es nada de lo que se dé cuenta a menudo hoy en día, pero imagine que solo tiene 20K para su salida y si sale más, su aplicación se bloquea porque no tiene espacio en el disco o lo que sea.

Entonces, sí, los efectos secundarios son desagradables y peligrosos desde la perspectiva de un programador. La mayoría de los errores provienen de la forma en que ciertas partes del estado de la aplicación están entrelazadas de una manera casi oscura, a través de efectos secundarios no considerados y muchas veces innecesarios. Desde la perspectiva de un usuario, los efectos secundarios son el objetivo de usar una computadora. No les importa lo que sucede dentro o cómo está organizado. Hacen algo y esperan que la computadora CAMBIE en consecuencia.

back2dos
fuente
Curiosamente, la programación lógica no solo no tiene efectos secundarios funcionales; pero ni siquiera puede cambiar el valor de una variable una vez asignada.
Ilan
@Ilan: Esto también es cierto para algunos lenguajes funcionales y es un estilo fácil de adoptar.
back2dos
"La programación funcional adopta un enfoque mucho más radical, donde el estado de la aplicación es simplemente inmutable desde la perspectiva del programador. Esta es una buena idea, pero hace que el lenguaje sea inútil por sí mismo. ¿Por qué? Porque CUALQUIER operación de E / S tiene un lado efectos ": FP no prohíbe los efectos secundarios, sino que los restringe cuando no es necesario. Por ejemplo (1) E / S -> los efectos secundarios son necesarios; (2) calcular una función agregada a partir de una secuencia de valores -> no es necesario el efecto secundario (por ejemplo, para el bucle con variable de acumulador).
Giorgio
2

Cualquier efecto secundario introduce parámetros adicionales de entrada / salida que deben tenerse en cuenta al realizar la prueba.

Esto hace que la validación del código sea mucho más compleja ya que el entorno no puede limitarse solo al código que se valida, sino que debe incorporar parte o la totalidad del entorno circundante (el global que se actualiza vive en ese código allí, lo que a su vez depende de eso código, que a su vez depende de vivir dentro de un servidor Java EE completo ...)

Al tratar de evitar los efectos secundarios, limita la cantidad de externalismo necesario para ejecutar el código.


fuente
1

En mi experiencia, un buen diseño en la programación orientada a objetos exige el uso de funciones que tienen efectos secundarios.

Por ejemplo, tome una aplicación de escritorio de IU básica. Es posible que tenga un programa en ejecución que tenga en su montón un gráfico de objetos que represente el estado actual del modelo de dominio de mi programa. Los mensajes llegan a los objetos en ese gráfico (por ejemplo, a través de llamadas a métodos invocadas desde el controlador de capa UI). El gráfico de objeto (modelo de dominio) en el montón se modifica en respuesta a los mensajes. Los observadores del modelo son informados de cualquier cambio, la interfaz de usuario y tal vez otros recursos son modificados.

Lejos de ser malo, la disposición correcta de estos efectos secundarios que modifican el montón y la pantalla son el núcleo del diseño OO (en este caso, el patrón MVC).

Por supuesto, eso no significa que sus métodos deban tener efectos secundarios arbitrarios. Y las funciones libres de efectos secundarios tienen un lugar para mejorar la lectura y, a veces, el rendimiento de su código.

flamingpenguin
fuente
1
Los observadores (incluida la interfaz de usuario) deben conocer las modificaciones suscribiéndose a los mensajes / eventos que envía su objeto. Esto no es un efecto secundario a menos que el objeto modifique directamente al observador, lo que sería un mal diseño.
ChrisF
1
@ChrisF Definitivamente es un efecto secundario. El mensaje pasado al observador (en un lenguaje OO muy probablemente una llamada a un método en una interfaz) conducirá al estado del componente de la interfaz de usuario en el cambio del montón (y estos objetos del montón son visibles para otras partes del programa). El componente UI no es un parámetro del método ni el valor de retorno. En un sentido formal, para que una función esté libre de efectos secundarios debe ser idempotente. La notificación en el patrón MVC no es, por ejemplo, la interfaz de usuario puede mostrar una lista de mensajes que ha recibido (consola), llamarla dos veces da como resultado un estado de programa diferente.
flamingpenguin
0

El mal es un poco exagerado ... todo depende del contexto del uso del lenguaje.

Otra consideración para los ya mencionados es que hace que las pruebas de corrección de un programa sean mucho más simples si no hay efectos secundarios funcionales.

Ilan
fuente
0

Como las preguntas anteriores han señalado, los lenguajes funcionales no impiden tanto que el código tenga efectos secundarios , sino que nos proporcionan herramientas para administrar qué efectos secundarios pueden ocurrir en un determinado código y cuándo.

Esto resulta tener consecuencias muy interesantes. Primero, y más obviamente, hay numerosas cosas que puede hacer con el código libre de efectos secundarios, que ya se han descrito. Pero también hay otras cosas que podemos hacer, incluso cuando trabajamos con código que sí tiene efectos secundarios:

  • En código con estado mutable, podemos administrar el alcance del estado de tal manera que garanticemos estáticamente que no se pueda filtrar fuera de una función determinada, lo que nos permite recolectar basura sin contar el esquema de referencia o marcar y barrer. , sin embargo, asegúrese de que no sobrevivan las referencias. Las mismas garantías también son útiles para mantener información sensible a la privacidad, etc. (Esto se puede lograr usando la mónada ST en Haskell)
  • Al modificar el estado compartido en varios subprocesos, podemos evitar la necesidad de bloqueos al rastrear los cambios y realizar una actualización atómica al final de una transacción, o revertir la transacción y repetirla si otro subproceso realizó una modificación conflictiva. Esto solo se puede lograr porque podemos asegurarnos de que el código no tenga más efectos que las modificaciones de estado (que podemos abandonar felizmente). Esto lo realiza la mónada STM (Software Transactional Memory) en Haskell.
  • podemos rastrear los efectos del código y trivialmente encerrarlo, filtrando cualquier efecto que deba realizar para asegurarnos de que sea seguro, permitiendo así (por ejemplo) que el código ingresado por el usuario se ejecute de forma segura en un sitio web
Jules
fuente
0

En bases de código complejas, las interacciones complejas de los efectos secundarios son lo más difícil de lo que encuentro para razonar. Solo puedo hablar personalmente dada la forma en que funciona mi cerebro. Los efectos secundarios y los estados persistentes y las entradas de mutaciones, etc., me hacen pensar en "cuándo" y "dónde" suceden las cosas para razonar sobre la corrección, no solo "qué" está sucediendo en cada función individual.

No puedo concentrarme solo en "qué". No puedo concluir, después de probar exhaustivamente una función que causa efectos secundarios, que se extenderá un aire de confiabilidad a lo largo del código que lo usa, ya que las personas que llaman pueden usarlo incorrectamente al llamarlo en el momento incorrecto, desde el hilo incorrecto, en el incorrecto orden. Mientras tanto, una función que no causa efectos secundarios y solo devuelve una nueva salida dada una entrada (sin tocar la entrada) es prácticamente imposible de usar de manera incorrecta.

Pero creo que soy un tipo pragmático, o al menos trato de serlo, y no creo que necesariamente tengamos que eliminar todos los efectos secundarios al mínimo para razonar sobre la corrección de nuestro código (al menos Me resultaría muy difícil hacerlo en lenguajes como C). Donde encuentro muy difícil razonar sobre la corrección es cuando tenemos la combinación de flujos de control complejos y efectos secundarios.

Los flujos de control complejos para mí son de naturaleza gráfica, a menudo recursiva o recursiva (colas de eventos, por ejemplo, que no llaman directamente a eventos recursivamente pero son de naturaleza "recursiva"), tal vez haciendo cosas en el proceso de atravesar una estructura de gráfico vinculada real, o procesar una cola de eventos no homogénea que contiene una mezcla ecléctica de eventos para procesar que nos lleva a todo tipo de diferentes partes de la base de código y todos desencadenan diferentes efectos secundarios. Si intentara dibujar todos los lugares en los que finalmente terminará en el código, se parecería a un gráfico complejo y potencialmente con nodos en el gráfico que nunca esperó que hubieran estado allí en ese momento dado, y dado que están todos causando efectos secundarios,

Los lenguajes funcionales pueden tener flujos de control extremadamente complejos y recursivos, pero el resultado es tan fácil de comprender en términos de corrección porque no hay todo tipo de efectos secundarios eclécticos en el proceso. Es solo cuando los flujos de control complejos se encuentran con efectos secundarios eclécticos que encuentro que induce dolor de cabeza tratar de comprender la totalidad de lo que está sucediendo y si siempre hará lo correcto.

Entonces, cuando tengo esos casos, a menudo me resulta muy difícil, si no imposible, sentirme muy seguro acerca de la corrección de dicho código, y mucho menos muy seguro de que puedo hacer cambios a ese código sin tropezar con algo inesperado. Entonces, la solución para mí es simplificar el flujo de control o minimizar / unificar los efectos secundarios (al unificar, quiero decir que solo causo un tipo de efecto secundario a muchas cosas durante una fase particular del sistema, no dos o tres o un docena). Necesito que suceda una de esas dos cosas para permitir que mi cerebro simplón se sienta seguro acerca de la corrección del código que existe y la corrección de los cambios que introduzco. Es bastante fácil confiar en la exactitud del código que introduce efectos secundarios si los efectos secundarios son uniformes y simples junto con el flujo de control, de la siguiente manera:

for each pixel in an image:
    make it red

Es bastante fácil razonar sobre la corrección de dicho código, pero principalmente porque los efectos secundarios son muy uniformes y el flujo de control es muy simple. Pero digamos que teníamos un código como este:

for each vertex to remove in a mesh:
     start removing vertex from connected edges():
         start removing connected edges from connected faces():
             rebuild connected faces excluding edges to remove():
                  if face has less than 3 edges:
                       remove face
             remove edge
         remove vertex

Entonces, este es un pseudocódigo ridículamente simplificado que típicamente implicaría muchas más funciones y bucles anidados y muchas más cosas que tendrían que continuar (actualizar múltiples mapas de textura, pesos óseos, estados de selección, etc.), pero incluso el pseudocódigo hace que sea tan difícil razón sobre la corrección debido a la interacción del flujo de control complejo tipo gráfico y los efectos secundarios que están ocurriendo. Entonces, una estrategia para simplificar eso es diferir el procesamiento y solo enfocarse en un tipo de efecto secundario a la vez:

for each vertex to remove:
     mark connected edges
for each marked edge:
     mark connected faces
for each marked face:
     remove marked edges from face
     if num_edges < 3:
          remove face

for each marked edge:
     remove edge
for each vertex to remove:
     remove vertex

... algo en este sentido como una iteración de simplificación. Eso significa que estamos pasando por los datos varias veces, lo que definitivamente está incurriendo en un costo computacional, pero a menudo encontramos que podemos multiprocesar dicho código resultante más fácilmente, ahora que los efectos secundarios y los flujos de control han adquirido esta naturaleza uniforme y más simple. Además, cada bucle se puede hacer más amigable con el caché que atravesar el gráfico conectado y causar efectos secundarios a medida que avanzamos (por ejemplo: use un conjunto de bits paralelos para marcar lo que debe atravesarse para que luego podamos hacer los pases diferidos en orden secuencial ordenado usando máscaras de bits y FFS). Pero lo más importante, encuentro que la segunda versión es mucho más fácil de razonar en términos de corrección y cambio sin causar errores. Así que eso'

Y después de todo, necesitamos que ocurran efectos secundarios en algún momento, o de lo contrario solo tendríamos funciones que generarán datos sin ningún lugar a donde ir. A menudo necesitamos grabar algo en un archivo, mostrar algo en una pantalla, enviar los datos a través de un socket, algo de este tipo, y todas estas cosas son efectos secundarios. Pero definitivamente podemos reducir la cantidad de efectos secundarios superfluos que ocurren, y también reducir la cantidad de efectos secundarios que ocurren cuando los flujos de control son muy complicados, y creo que sería mucho más fácil evitar errores si lo hiciéramos.


fuente
-1

No es malo En mi opinión, es necesario distinguir los dos tipos de funciones, con efectos secundarios y sin ellos. La función sin efectos secundarios: - devuelve siempre lo mismo con los mismos argumentos, por lo que, por ejemplo, dicha función sin ningún argumento no tiene sentido. - Eso también significa que el orden en el que se llaman algunas de estas funciones no juega ningún papel: debe poder ejecutarse y puede depurarse solo (!), Sin ningún otro código. Y ahora, lol, mira lo que JUnit hace. Una función con efectos secundarios: - tiene una especie de "fugas", lo que se puede resaltar automáticamente - es muy importante al depurar y buscar errores, lo que generalmente es causado por los efectos secundarios. - Cualquier función con efectos secundarios también tiene una "parte" de sí misma sin efectos secundarios, que también se puede separar automáticamente. Tan malvados son esos efectos secundarios,

usuario225623
fuente
Esto no parece ofrecer nada sustancial sobre los puntos hechos y explicados en las 12 respuestas anteriores
mosquito