Programación Funcional en Dart
Con dartz
Cerrá tus ojos un momento.
Estás en primer año de tu carrera de TI, la que sea, acá no se discrimina. Vas a tu primera clase de programación y tu profesor empieza a explicarte qué es un algoritmo y cómo existen en todas partes aunque no se noten a simple vista.
De pronto introduce esta palabra de “programación” y te menciona que existen varios tipos, estilos o como suena más intelectual: paradigmas. Te dice que van a aprender el paradigma estructurado, porque es tu primera clase. Escuchas que también menciona el paradigma orientado a objetos, y tranquilo/a, eso lo vas a ver un semestre más adelante.
Hay varios que menciona que probablemente no te van a enseñar en la universidad, al menos así me pasó a mí. Una de esas fue programación -o el paradigma- funcional. Este paradigma a veces se deja de lado porque no todos los lenguajes permiten implementarlo al pie de la letra.
⚠️ Como dice el título, este artículo es enfocado en el lenguaje Dart y además en el paquete dartz. Existen otros paquetes para programar funcionalmente en Dart pero no tienen la amplitud ni uso de dartz.
El paradigma funcional
Por esa introducción podrás intuir que no soy un experto en este paradigma, pero vamos a centrarnos en lo base para que puedan entender los trucos geniales que se pueden lograr con él.
La programación funcional tiene como características ser declarativa y además tratar a las funciones como un tipo de datos primitivos, o como suena más bonito, ciudadanos de primera clase.
Los que ya conocen bien a Dart saben que calza muy bien con estas características. Nosotros podemos mandar una función a una clase u otra función como propiedad o argumento.
Ahí creamos un objeto que es una función y lo podemos ejecutar si lo pasamos como argumento a otra. Compatibilidad con el paradigma, chequeada.
En sí, la programación funcional tiene un origen muy ligado a la matemática ya que usa este fundamento científico para ser capaz de procesar tareas más complejas computacionalmente gracias al reemplazo de ciclos, que aumentan muchas veces la complejidad, por funciones que aceptan funciones como argumento o devuelven como resultado una función. A esas últimas se les llama funciones de orden superior o higher order functions, para los/as bilingües.
Ventajas
La gran pregunta es: ¿cuál es la ventaja que nos trae incorporar este paradigma a nuestro código?
Lo resumiría en que nos permite hacer código más conciso, reduce la complejidad al leerlo al no tener varias sentencias de control en él. Facilita mucho el hacerle pruebas ya que tenemos resultados específicos de funciones. Lo más genial, se puede combinar fácilmente con otros paradigmas.
Desventajas
No todo es bueno, hay algunos problemas cuando necesitamos un estado de variables ya que se devuelven resultados, aquí es donde combinarlo con otros paradigmas es muy útil. Puede ser lento cuando se entra en muchas recursiones.
En general, no es la mejor alternativa para todas las tareas.
Dartz
Este paquete contiene muchas herramientas que nos facilitan incorporar la programación funcional en nuestro proyecto. Vamos por partes ejemplificando.
Primero, como base, vamos a tener una entidad de persona para ejemplificar algunos casos de uso donde podamos utilizar herramientas de programación funcional.
Either
La primera clase que es súper útil es Either
. Es una clase abstracta que admite dos tipos de datos como valores de retorno, es decir, puede retornar un entero y una cadena, por ejemplo.
En este caso, definimos una función que retorna un Either
que puede contener un valor de int
o String
. Entonces nuestra función recibe un objeto de persona y en base a un valor aleatorio que generamos, enviamos una respuesta.
Si notan, no regresamos el nombre o la edad de una vez, si no que los envolvemos en una clase Right
o Left
. El primer valor que definimos en el Either
debe ser regresado envuelto en Right
y el segundo valor en Left
. Estas son las clases que implementan Either
y las formas de retornar el resultado del mismo.
Ahora que instanciamos la clase y la pasamos como argumento a nuestra función, pasa algo interesante. Ya que nuestra variable puede adoptar dos posibles valores del Either
, tenemos un método muy útil llamado fold
que nos da acceso a dos funciones que retornan un tipo de dato cada una para realizar alguna acción en específico, como asignaciones o la ejecución de otra función que necesite el argumento que nos devuelve.
Si les parece un poco confuso, vean fold
como un if-else
para los dos posibles tipos de datos que puede regresar la función.
Esta clase es muy útil cuando hacemos algún llamado un API de terceros que no conozcamos muy bien para poder atrapar cualquier error desconocido y retornarlo en la función.
Option
Uno muy similar a Either
es Option
. A veces no queremos retornar dos posibles valores, y aquí dirán "ah, eso es una función normal" pero Option
nos permite más que eso.
Empezando porque nos permite adaptar esa lógica del if
para decidir qué se hace en base al resultado obtenido. Se puede utilizar para devolver una validación de la ejecución de alguna operación.
Tenemos las nuevas clases que la implementan: None
y Some
. None
nos permite devolver un objeto que representa que no se puede efectuar la acción esperada y Some
contiene el valor que se esperaba que devolviera la operación efectuada.
Considera None
como un valor perdido que no se pudo enviar. Esto nos ayuda a manejar errores generales y la composición de nuestro código de una manera más expresiva.
Ah, sí…
Either
y Option
son estructuras que se llaman mónadas. Estas pueden ser aplicadas a los tipos de datos para que sigan una secuencia de pasos específicas. Como cuando obtenemos uno de dos valores específicos y ejecutamos alguna acción en base a lo que recibimos.
Hay mónadas mucho más complejas como Evaluation
que comprenden distintos tipos de mónadas y se le conoce como la navaja suiza de estas estructuras pero las que hemos visto creo que son suficientes para no complejizar tanto nuestro código.
Pueden adentrarse mucho más en este paquete si quieren, contiene mucha funcionalidad que viene bien si se te dan bastante las matemáticas y teorías de categorización. Yo me considero más pragmático, me gusta bastante este estilo y les comparto esta pequeña parte porque considero que viene bien en cualquier tipo de proyecto.
Igualmente las mónadas que vimos tienen más métodos que les pueden ser de utilidad. Me recuerdan bastante los métodos que tenemos en las clases que hacemos con Freezed pero aplicados a funciones -claro, programación funcional- y a sus valores de retorno.
Muy útil para manejar distintos escenarios en tus proyectos, más que nada posibles errores o resultados imprevistos.
También hay versiones inmutables de las colecciones de datos ya existentes en Dart. Por si van a usar datos que no cambian en este tipo de estructura, en el paradigma funcional se ocupan mucho ya que los cambios de variables se hacen a través de las funciones.
Estas incluyen IList
, IMap
, IVector
, IHashMap
... entre otras variantes.
Lo de siempre…
Si aprendiste algo nuevo y te fue de utilidad, podés compartir este artículo para ayudar a otro/a desarrollador(a) a seguir mejorando su productividad y calidad al escribir aplicaciones con Flutter.
También hay una versión de este mismo artículo en inglés publicado en dev.to. De nada. 🇺🇸
Además, si te gustó este contenido, podés encontrar aún más y seguir en contacto conmigo en mis redes sociales:
Originally published at http://github.com.