Mutación incontrolada y efectos secundarios.
Veamos una línea de código de un carrito de compras en línea:
fin.finalizar
¿Puedes adivinar qué llamará este método? ¿Actualizará el objeto Order? ¿Actualizarlo en la base de datos? Crear más registros? ¿Seleccionará LineItems de la base de datos? ¿Actualizar un total en caché en el objeto Order? ¿Envía un correo electrónico al usuario que realizó el pedido? ¿Inicia trabajos en segundo plano, vacia cachés, importa un módulo? ¿Qué hace este método que ni siquiera hemos considerado?
- ¿Cuáles son algunos de los grandes hábitos de un joven indio de 22 años ideal?
- Como dejar de morderme las mejillas
- ¿Puedes enumerar los 10 hábitos que siguen los multimillonarios para enriquecerse?
- ¿Qué debe hacer un estudiante de secundaria para crear hábitos que serán útiles para la universidad y el resto de su vida?
- Mi padre come tobbaco. Yo, mi hermano y mi madre tratamos de cambiar su hábito, pero él todavía lo come. ¿Cómo puede dejar este hábito?
No podemos adivinar. Tenemos que buscar en el código para averiguarlo, y cada método llamado requiere más preguntas abiertas.
Las pruebas no nos salvarán. Son lentos, tal vez fallan o pasan cuando no deberían, y los cambios aparentemente triviales causan docenas de fallas. Es posible que las especificaciones aspiren a especificarse, pero nos estamos moviendo de un lado a otro entre las fábricas y las que intentan descubrir un doble de prueba en particular para acelerar una prueba o asegurarnos de que se envíe un correo electrónico. Y eso asumiendo que existen en absoluto; es una triste realidad que la mayoría de las veces las pruebas faltan en las funciones complejas para las que más las queremos.
Es imposible razonar acerca de un programa cuando no tiene una base sólida, ya que todo lo que haces puede rechazar un cambio en otra parte del sistema. La funcionalidad migra a devoluciones de llamada porque no hay control sobre los ciclos de vida de los objetos. Las pruebas se convierten en “demasiados problemas” cuando tiene que apagar la funcionalidad aparentemente desconectada para el rendimiento o para evitar la creación de instancias de docenas de objetos. Los objetos a menudo son “parcialmente válidos”, lo que desencadena un acoplamiento temporal o, lo que es peor, proporciona un caldo de cultivo para las dependencias cíclicas.
El control de la mutabilidad nos da valores para evitar la obsesión primitiva, valores que pueden pasarse de manera segura como argumentos sin ninguna posibilidad de que sean modificados por algún sub-sub-sub-método.
Controlar los efectos secundarios nos da una jerarquía. En el nivel más alto, describimos de dónde provienen los datos y sin tener que temer que algún objeto escondido actualizará el estado global. En los niveles más bajos escribimos lógica empresarial pura.
Entré en detalles sobre cómo lidiar con esto en mi charla de RailsConf 2015. La mayor parte del texto anterior es un extracto de mi libro de Ruby en progreso; puede unirse a la lista de correo electrónico en esa página para obtener más extractos y recursos a medida que la complete.