"With Effects" (o simplemente "Effects") es un concepto en programación funcional y concurrente que permite a las funciones declarar explícitamente los tipos de efectos secundarios que pueden producir, en lugar de ocultarlos. Tradicionalmente, una función pura no tiene efectos secundarios, lo que simplifica su razonamiento. Sin embargo, las aplicaciones del mundo real requieren I/O, mutación de estado, manejo de errores, etc. Los sistemas "With Effects" proporcionan un mecanismo para modelar estos efectos como parte de la firma de tipo de una función o a través de construcciones de lenguaje específicas, permitiendo al compilador o al runtime verificar y gestionar su uso. Esto transforma los efectos implícitos en explícitos, facilitando la composición, la optimización y la depuración.

Este patrón se implementa en varios lenguajes y frameworks. En Scala, las librerías como ZIO y Cats Effect utilizan tipos de datos como `IO` o `Task` para encapsular y componer operaciones con efectos, declarando explícitamente si una operación es asíncrona, puede fallar, o interactúa con el sistema de archivos. En TypeScript, el proyecto Effect (anteriormente conocido como ts-effect) ofrece un sistema similar para gestionar efectos de manera tipada y segura. Otros ejemplos incluyen el uso de monads en Haskell para I/O (la `IO` monad) o el concepto de "capabilities" en lenguajes como Koka, donde las funciones declaran las capacidades (efectos) que requieren. Estos sistemas permiten la construcción de programas robustos donde los efectos son gestionados de forma determinista y segura.

Para un Arquitecto de Sistemas, la adopción de un enfoque "With Effects" es crucial para construir sistemas complejos, concurrentes y distribuidos. Permite diseñar APIs donde los efectos secundarios son transparentes, reduciendo la probabilidad de errores sutiles en entornos concurrentes y facilitando la refactorización. Los trade-offs incluyen una curva de aprendizaje inicial más pronunciada y, en algunos casos, una verbosidad de código ligeramente mayor debido a la explicitud. Sin embargo, los beneficios superan con creces estos inconvenientes: mejora la testabilidad (mocking de efectos), la observabilidad (trazabilidad de efectos), la resiliencia (manejo de errores y reintentos declarativos) y la escalabilidad (gestión de concurrencia y recursos). Un arquitecto debe evaluar si el overhead de adoptar un framework de efectos se justifica por la complejidad del dominio y los requisitos de fiabilidad del sistema.