Composición funcional en JavaScript
14 Dec 2016Vamos a tomar un ejemplo bastante simple, para comenzar a refactorearlo con el patrón de composición funcional. Aviso desde ya todo el código estará en ES6.
En el ejemplo tenemos algunas funciones que reciben un argumento y generan un resultado, todo muy simple.
En este código hay algo que no cierra del todo, por ejemplo tenemos a la variable numero reasignada una y otra vez, ademas que no es claro al momento de leerlo. Podríamos refactorearlo de esta forma:
Ahora estaríamos metiendo funciones dentro de funciones, continua siendo problemático de leer y si quisiéramos agregar otras funciones terminaríamos con una cantidad de paréntesis infernal.
Podriamos refactorear los métodos de arriba para que el retorno sea encadenable, es decir que return
sea el mismo objeto y se le pueda llamar otro método inmediatamente. Un patrón de diseño conocido como Builder
En este ejemplo usamos el patrón Builder para aplicar un esquema de azucar sintactica como forma de reasignar el valor a la variable num. Todavía no se ve del todo correcto, ya que ahora tenemos que generar una instanciación del builder para asignar el valor inicial.
Nuestras funciones están ahora todas juntas dentro del Builder, podríamos abstraerlas pero sería sumar aun mas complejidad. Además tenemos ahora una función con un poco de estado también (num), ya que iniciamos el constructor con el valor de partida, quitando legibilidad a nuestro código y haciendo que nuestra solución inicial parezca mucho más simple (aunque mucho menos escalable).
El siguiente ejemplo es composición funcional en JavaScript, muchas librerías de JS incluyen la misma funcionalidad, por ejemplo lodash tiene un método llamado _.flow
. El procedimiento técnico es conocido como pipe (tubería), que reduce las funciones de izquierda a derecha (en donde el resultado de una es el valor inicial de la próxima). Se puede usar también reduceRight para que nuestro operador aplique las funciones de derecha a izquierda de una forma mas funcional.
Cada función simplemente pasará el return de la anterior y dará el resultado a la siguiente, así hasta que se obtenga el valor final.
Vamos de a parte, en el inicio declaramos nuestras funciones como lo hicimos en el primer ejemplo, sin embargo también declaramos una llamada componer
. Analicemos que es lo que hace:
Para finalizar, llamamos a la función componer, pasamos todas las funciones que queremos que formen parte y obtenemos como resultado otra función a la que solo hay que pasarle el valor que tomará la primera de la funciones a ser ejecutada.
La composición funcional no afecta la testeabilidad ya que es puramente genérica y no afecta ningún detalle especifico de la implementación. Otorga un código mas claro para leer sin sobrecargar de complejidad.