El hecho de tener mucho tiempo en mi fin de semana, contribuye a que me dedique a aprender cosas nuevas, ya sea una receta de cocina, un nuevo truco o en este caso: un nuevo paradigma de programación.

La programación funcional puede ayudarnos a crear software más robusto, mantenible y fácil de testear. Quizás hayas empezado a oír hablar de lenguajes de programación funcional como Scala, Haskell o Lisp, pero quizá no sepas todavía que Java en su versión 8 permite usar la potencia de la programación funcional sin abandonar su orientación a objetos.

Desde que empiezas a programar con Java te enseñan qué es un lenguaje de programación orientado a objetos y que Java es uno de ellos. Te enseñan a programar de manera imperativa y es como has programado desde entonces. Con estas herramientas tienes que crear la mejor solución posible y hasta hoy no ha ido mal. Pero, ¿y si te digo que hay una forma mejor de llegar a esas soluciones?

En el más estricto sentido, los lenguajes de programación puramente funcionales tienen algunas características que los hacen tan únicos:

  • No hay ciclos. La programación funcional hace uso de la recursividad, que como ya vimos, es una herramienta muy poderosa cuando de expresar problemas se trata.
  • No hay variables ni asignaciones… o bueno, mejor dicho: inmutabilidad. Una vez que un valor ha sido establecido y almacenado este no puede ser cambiado a lo largo de la ejecución del programa del bloque del programa en el que fue definido.
  • No tienen estados, evita los efectos colaterales. En la programación funcional, el llamar a una función multiples veces con las mismas entrdas siempre devolverá los mismos resultados, estos no se verán influenciados por condiciones externas o estados almacenados previamente

A esto último también se le llega a conocer como transparencia referencial, que básicamente significa que podemos reemplazar cualquier referencia a una función por el valor que regresa sin que se altere el resultado o el comportamiento del programa.

La realidad es que muchos de los lenguajes que seguramente conoces, o conoceras, no son puramente funcionales. Muchos de ellos retienen nociones de otros paradigmas, como los ciclos, y las variables y a mi modo de ver las cosas, me parece algo bastante bueno, al menos para facilitar la transición y el aprendizaje para los desarrolladores que estamos acostumbrados a la forma de programar con lenguajes como Java que son más orientados a objetos.

En la programación declarativa no definimos cómo queremos resolver un problema, sino que definimos cuál es el problema. Un ejemplo sencillo para comparar estas dos formas de programar es encontrar en una lista de formas si tenemos la forma “cuadrado”:

boolean esCuadrado = false;
for (String forma: formas{
   if (forma.equals("cuadrado")) {
      esCuadrado = true;
      break;
   }
}
System.out.println("Existe un cuadrado? " + esCuadrado);

Aquí vemos cómo estamos definiendo la manera de resolver el problema. Esta forma de hacerlo es muy verbosa y nos hace tener que definir una variable hasRed para marcar si se ha encontrado o no, lo que hace que este código sea un poco “feo”.

Hasta aquí nada nuevo, todo es lo mismo de toda la vida pero te voy a contar un secreto. Si has usado java durante un tiempo prudencial, sabes (al menos en concepto) lo que es una declaración funcional. ¿No me crees?. Mira el siguiente fragmento de código que hace lo mismo que hicimos en el bloque anterior:

System.out.println(“Existe un cuadrado?:” + formas.contains(“cuadrado”));

Esta solución es más concisa, más clara y más fácil de entender por cualquier persona. No sabemos la implementación que estamos usando ya que eso es cosa del código que hay por debajo. Lo que sí sabemos es exactamente lo que hace ese código: nos dice si formas contiene “cuadrado”. Por suerte, para este ejemplo el API de Java nos provee del método contains, que nos ayuda a hacer nuestro código más legible, pero no siempre tendremos esa suerte.

En los casos en los que tengamos que crear nuestros propios métodos podemos usar la programación funcional, que es declarativa y por tanto nos puede ayudar a hacer nuestro código más limpio. Veamos un ejemplo de cómo podemos mejorar nuestro código usando programación funcional.

Dada una lista de números decimales queremos descontar un 20% a todos los que sean mayores de 25 y sumarlos:

BigDecimal sum = BigDecimal.ZERO;
for (BigDecimal number : numbers) {
   if (number.compareTo(BigDecimal.valueOf(25)) > 0) {
      sum = sum.add(number.multiply(BigDecimal.valueOf(0.8)));
   }
}
System.out.println("Total: " + sum);

Seguro que ese código es muy familiar para todos. Como vemos, estamos creando una variablesum donde vamos cambiando su valor en función de las condiciones que hemos definido en el enunciado.

Veamos ahora cómo escribir ese código de una manera mucho más clara de forma funcional en Java 8:

final BigDecimal sum =
   numbers.stream()
      .filter(number -> number.compareTo(BigDecimal.valueOf(25)) > 0)
      .map(number -> number.multiply(BigDecimal.valueOf(0.8)))
      .reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println("Total: " + sum);

Este código se puede “leer”. Cualquier persona que se ponga delante de él puede leerlo de la siguiente forma:

  • Filtrar los números mayores de 25.
  • Asignar a cada número un número igual a su 80%.
  • Usar el método add para reducir esa lista.

Estamos declarando el problema mientras escribimos su implementación en el código. Lo único que tenemos que hacer es coger los requisitos de la funcionalidad que queremos implementar y escribirlos. De esta manera si alguna vez cambian o si algún otro compañero tiene que mirar nuestro código será muy sencillo saber qué es lo que está haciendo ahora y, por lo tanto, añadir las nuevas especificaciones.

Esta es una pequeña introducción a la programación funcional. Te aconsejo que sigas buscando más acerca de las novedades en Java 8 sobre este paradigma de programación y verás cómo tu código se vuelve más simple y más conciso, haciendo que tenga menos fallos y que los que tenga sean más sencillos de encontrar y corregir.

Espero que hayas disfrutado con este enfoque un tanto distinto a la programación funcional. En el futuro añadiré más entradas a este nuevo paradigma e iré tocando temas más a fondo.

Si te gusta lo que lees no dudes en dejarme tu mensaje.

import Html
main = Html.text "Esto es un hola mundo en ELM. ¡Hasta la próxima!"