30 noviembre 2012

La programación funcional y los patrones de diseño

Hola a tod@s,
como desarrollador de software creo que todos tenemos que hacer nuestro trabajo lo mejor posible. Una de las herramientas que me han ayudado más en el desarrollo OO ha sido la aplicación de patrones de diseño para solventar problemáticas concretas que se dan de forma recurrente en el desarrollo de sistemas software
“Un patrón de diseño define una posible solución correcta para un problema de diseño dentro de un contexto dado, describiendo las cualidades invariantes de todas las soluciones”
Cómo parte de mi inmersión inicial en el paradigma de programación funcional me pregunte lo siguiente:
  • ¿Tiene sentido hablar de patrones de diseño en el entorno de la programación funcional?
  • ¿Los patrones de diseño clásicos que aplicamos en programación OO (por ejemplo, los patrones GoF) son igualmente válidos para programación funcional?
  • ¿Existe un catálogo de patrones de patrones de diseño específico para programación funcional o se aplican los mismos que aplicamos en programación OO?
Estaba en estas tesituras cuando tropecé con la siguiente reflexión en StackOverflow: Does Functional Programming Replace GoF Design Patterns?, en este hilo de discusión aparecen varias ideas y reflexiones muy interesantes sobre la relación entre la programación funcional y los patrones de diseño. Os recomiendo encarecidamente que lo leáis con atención porqué la discusión es sumamente interesante y algunas de las ideas/opiniones son, cuando menos, sorprendentes para los que venimos del paradigma OO.
En este artículo intentaré enumerar algunas de ellas y, des de la mas absoluta modestia de un neófito en el excitante mundo de la programación funcional, daré mi opinión al respecto.

Patrones de diseño en programación funcional

La discusión inicial del hilo arranca del siguiente parágrafo del artículo Functional Programming For The Rest of Us (otro “must read”!):
“Most people I've met have read the Design Patterns book by the Gang of Four. Any self respecting programmer will tell you that the book is language agnostic and the patterns apply to software engineering in general, regardless of which language you use. This is a noble claim. Unfortunately it is far removed from the truth.
Functional languages are extremely expressive. In a functional language one does not need design patterns because the language is likely so high level, you end up programming in concepts that eliminate design patterns all together.”
el autor argumenta pues que en programación funcional, debido a que se trata de un paradigma en el que se desarrolla y trabaja en un nivel de abstracción más alto que en el paradigma OO, NO tiene sentido aplicar patrones de diseño porqué las capacidades de los lenguajes de programación funcionales los hacen innecesarios.
En este sentido me sorprendió especialmente, que se definiera un patrón de diseño como un “parche” que soluciona un problema o una deficiencia del paradigma o, si somos más específicos, del lenguaje.
Los patrones de diseño evolucionan junto a las capacidades y niveles de abstracción que proporcionan los paradigmas y lenguajes de programación para los que se definen. Un el hilo se pone un ejemplo bastante tonto pero que expresa esta idea:
Supongamos que los lenguajes de programación no proporcionaran una construcción para iterar sobre una colección de elementos, ¿se consideraría una solución que definiera como iterar sobre un conjunto de elementos de una colección un patrón de diseño? Pues posiblemente si, ya que se estaría dando una solución correcta a un problema dado… pero, ¿tiene sentido considerar actualmente esto como un patrón de diseño? No, ya que esta es una capacidad existente en todos los lenguajes de programación y, por tanto, el patrón proporcionaría una solución a un problema inexistente.
Pienso que el nivel de abstracción superior de los lenguajes funcionales hace que, lo que en otros paradigmas era un problema recurrente (i, por tanto, requería un patrón de diseño que proporcionara una solución) simplemente no suponga un problema por qué ya se dispone de una abstracción “de serie” que la soluciona.
¿Quiere decir esto que en programación funcional no tiene sentido hablar de patrones de diseño? para mi no, simplemente los patrones de diseño en programación funcional serán diferentes a los patrones de diseño de otros paradigmas (por ejemplo, los patrones de diseño para programación OO que se define en GoF).

Patrones GoF y la programación funcional

En el hilo se discute bastante sobre si tienen sentido en programación funcional los patrones de diseño definidos en el libro Design Patterns: Elements of Reusable Object-Oriented Software.
Bajo mi punto de vista, la respuesta la tenemos precisamente en el título del libro, concretamente en esta parte: “… of Reusable Object-Oriented Software” => el libro de cabecera sobre patrones de diseño define 23 patrones de diseño bajo un paradigma OO NO bajo un paradigma funcional, lo primordial es que los patrones de diseño lo son para un determinado paradigma, es decir, no son independientes del paradigma bajo el que se aplican. Muchas veces incluso, aunque se promulgue lo contrario, tampoco son independientes del lenguaje de programación que se esté usando.
Sirva como ejemplo el patrón Singleton en un lenguaje “medio OO-medio funcional” como Scala, en el no tiene sentido aplicar este patrón de la forma en que lo describe GoF simplemente porqué el lenguaje tiene soporte directo para ello.
Lo que en programación OO es un problema recurrente que requería un patrón de diseño para su resolución,  en programación funcional simplemente no es un problema, o el problema resulta tan trivial que no requiere la definición de un patrón de diseño para su resolución. El mayor nivel de abstracción y los conceptos presentes en programación funcional como: High Order Functions, Currying, Closures, Data Types algebraicos, Pattern Matching, etc… proporcionan soluciones “de serie” o “embeded” para la mayoría de patrones que describe GoF.
Con los patrones tradicionales en programación funcional pueden pasar tres cosas:
    • el patrón desaparece debido a que el lenguaje ya proporciona esa funcionalidad.
    • el patrón sigue existiendo pero la solución es radicalmente diferente.
    • el patrón sigue existiendo pero la solución se implementa usando nuevas capacidades del lenguaje o del paradigma.
Parece claro pues que NO se requieren los mismos patrones en programación OO que en programación funcional y no es una buena idea intentar aplicar los patrones OO dentro de un paradigma funcional. De hecho la manera de diseñar software en programación funcional es muy diferente a la que estamos acostumbrados en OO, esto hace que los problemas a resolver muchas veces tengan poco a ver con los problemas a los que nos enfrentamos en OO.
Si estáis interesados en saber como se resuelve en programación funcional la problemática que describen los patrones GoF en el enlace Design Patterns in Haskell hay una interesante correspondencia entre estos patrones y su resolución en Haskell y Peter Norvig tiene una presentación con soluciones triviales a 16 de los 23 patrones en lenguajes dinámicos. Hay algunas de estas soluciones que merecen un análisis un poco mas detallado, pero esto lo dejaremos para otras entradas Guio.

Conclusión

Las ideas principales con las que me quedo después de escribir el artículo son:
  • Los patrones de diseño sirven para solucionar problemas existentes, si no hay problema a resolver no tiene sentido hablar de patrón de diseño para resolverlo.
  • La naturaleza de los paradigmas de programación y las capacidades de los lenguajes de programación marcan los patrones de diseño aplicables en cada caso.
  • El mayor nivel de abstracción del paradigma funcional hace que muchos de los problemas que hay en OO no sean problemas y, por tanto, no tenga sentido plantear un patrón de diseño para ellos.
  • En programación funcional se tiende a hablar de reglas o de buenas prácticas para resolver problemas concretos que de patrones de diseño.
  • En programación funcional SI necesitamos patrones de diseño pero son distintos a los que necesitamos en programación OO.
y con la tarea de conocer mucho mas a fondo la programación funcional y los patrones, reglas o buenas prácticas que se aplican en este paradigma.

18 octubre 2012

Programación funcional

Hola a tod@s,
después de mucho tiempo sin escribir nada en el bloc voy a retomar, en la medida de lo posible, la escritura regular de artículos. Últimamente me ha entrado el gusanillo de aprender de que va esto de la programación funcional y para ello he estado haciendo mis primeros pinitos con Scala aprovechando el curso Functional Programming Principles in Scala que imparte el mismísimo Martin Odersky en la plataforma on-line Coursera.
Con el objetivo de afianzar los conocimientos adquiridos en el curso y a modo de recordatorio personal voy a escribir una serie de artículos breves con los conceptos básicos de programación funcional.
Para que no perdáis el tiempo, os comento lo que creo que debéis hacer, en función de vuestro background, si os topáis con un artículo de esta serie:
  • Alguien que no tenga demasiada experiencia en programación funcional pero le interese el tema: no os toméis lo que digo en los artículos “a pies juntillas”, contrastadlo y corregidme las partes que creáis que no son correctas. Tomaros los artículos como un primera toma de contacto y, si os interesa el tema, leed artículos de gente con más experiencia y contrastad lo que se comenta. Después de eso, todo el feedback que podáis aportar a los artículos en forma de comentarios será muy bienvenido. Ah! y apuntaros al curso de programación funcional.
  • Alguien experto en programación funcional: tenéis dos opciones, o bien obviarlos por completo ya que seguro que no os aportarán nada nuevo o bien leer los post con detalle y comentar los posibles errores e inexactitudes que encontréis. Lógicamente os animo a hacer lo segundo!
  • Alguien al quien no le interesa la programación funcional: Obviad los artículos por completo Sonrisa
En esta serie de artículos breves voy a intentar plasmar las dificultades y sorpresas que me encuentro en el proceso de aprendizaje del paradigma de programación funcional (FP) desde la perspectiva de un desarrollador de software OO, que es el paradigma con el que me desenvuelvo bien. El objetivo último es asentar los conocimientos adquiridos sobre programación funcional y hacerlo estableciendo paralelismos con la programación OO.
Para ello voy a resumir los conceptos mas relevantes del curso e intentaré plantear y resolver algunos problemas sencillos de varias formas, usando paradigmas OO, funcionales e híbridos con el propósito de hacer comparaciones y analizar las ventajas y desventajas de cada una de ellas. Para los ejemplos usaré indistintamente Java, C#, JavaScript y Scala.
En el curso se usa Scala como lenguaje de programación pero el verdadero objetivo del curso no es aprender Scala si no aprender a programar siguiendo un paradigma funcional. Pensar la resolución de un problema mediante un paradigma funcional te hace replantear tus esquemas mentales y…, cuesta, para que engañarnos, cuesta mucho. La primera sensación, en la resolución del primer Homework del curso, fue: ¿por donde empiezo? La programación funcional es un paradigma bastante diferente al paradigma usado en programación imperativa y te quedas bastante bloqueado inicialmente!
En esta primera entrada voy a poner en contexto la programación funcional y sus principios básicos, resumiendo partes de la primera semana del curso. También intentaré responder a LA PREGUNTA en mayúsculas, ¿POR QUÉ programación funcional ahora?.

¿Qué es la programación funcional?

Los principales paradigmas de programación existentes son:
  • Programación funcional (FP)
  • Programación imperativa
  • Programación lógica
el paradigma OO lo podemos considerar como un paradigma ortogonal a los tres anteriores ya que se puede combinar con cualquiera de los tres paradigmas anteriores (lo que estamos mas acostumbrados a hacer es a combinar programación imperativa con OO pero veremos que también es posible combinar elementos de FP con elementos OO)
Las ideas principales en las que se basa la programación imperativa son:
  • Modificación de variables mutables usando asignaciones
  • Uso masivo de estructuras de control: bucles, if-then-else, etc…
Las ideas principales en las que se basa la programación funcional son:
  • Se basa en definir teorías para operadores expresadas como funciones
  • Evita, en la medida de lo posible, el uso de mutaciones usando asignaciones (en sentido estricto las prohíbe)
  • Evita, en la medida de lo posible, el uso de estructuras de control (en sentido estricto las prohíbe)
  • Se basa en la abstracción y composición de funciones.
La programación funcional se basa en teorías matemáticas como el lambda-calculus y estas teorías no se pueden aplicar a la programación imperativa ya que su principio básico (la modificación de variables mutables) NO tiene cabida en las teorías matemáticas. Es decir, cuando introducimos la mutación de variables ya no podemos aplicar las leyes por las que se rigen las teorías matemáticas ya que en ellas no está permitida la mutación.
Mi primera sorpresa… ¿en programación funcional no se pude modificar una variable y se deben evitar las estructuras de control? Pues en sentido estricto SI… Es especialmente interesante ver como en el libro Structure and Interpretation of Computer Programs , uno de los libros de clásicos, de cabecera, de la introducción a la programación en los cursos del MIT, no se habla de mutación de variables hasta el capítulo 3…
Pero, ¿porqué es importante usar los conceptos de las teorías matemáticas un un paradigma de programación? Según Odersky sin el uso de teorías matemáticas un paradigma de programación tiene problemas para implementar conceptos de alto nivel y, por tanto, tiene problemas de escalabilidad conceptual. El uso de teorías proporciona formas muy potentes de abstraer y componer funciones y proporciona una escalabilidad conceptual que nos permite dejar atrás la correspondencia uno a uno entre las instrucciones de un lenguaje imperativo y secuencia de instrucciones para una máquina de Von Neumann.
En este punto, después de la primera toma de contacto con la programación funcional, me asaltó una pregunta realmente importante y su análisis me llevo a pensar que la programación funcional tomará mucha relevancia y será clave en el desarrollo de software: ¿Porqué programación funcional?

¿Porqué programación  funcional?

Si hacemos un poco de historia, la programación funcional lleva con nosotros mas de 50 años. Apareció con Lisp a finales de los 50 y, hasta la actualidad, era un paradigma de programación que se usaba casi exclusivamente en el ámbito académico y en algunas aplicaciones de Inteligencia Artificial, su presencia en el mundo de la industria era prácticamente nula. ¿Qué hace pues que ahora parezca que la programación funcional se abre hueco con fuerza en el mundo de la industria?
Para intentar responder a esta pregunta veamos primero las ventajas que nos ofrece la programación funcional. Cuando hablamos de las ventajas de la programación funcional respecto a la programación más clásica aparecen siempre estos argumentos:
  • Alto nivel de abstracción: La programación funcional proporciona un nivel de abstracción mucho más alto.
  • Productividad: Un programa funcional tiene muchas menos líneas de código => menos bugs => menos mantenimiento. En este sentido se argumenta que la programación funcional puede llegar a ser un orden de magnitud más
Si bien los argumentos anteriores son importantes, creo que el porqué de la programación funcional en nuestros días tiene mucho mas que ver con estos dos hechos que con las ventajas comentadas anteriormente:
  • Actualmente las aplicaciones se ejecutan en ordenadores multicore con una capacidad de procesamiento y de paralelización muy grande.
  • Cada vez mas se tiende a desplegar las aplicaciones usando Cloud Computing donde, por temas de escalabilidad, es muy importante que las aplicaciones sean altamente paralelizables.
Estamos pues de acuerdo que la paralelización es un concepto clave para las aplicaciones actuales pero, ¿tiene esto algo que ver con la programación funcional? pues parece que si, y mucho!
En este punto os aconsejo que vais el vídeo O'Reilly OSCON Java 2011: Martin Odersky, "Working Hard to Keep It Simple" que fue el que cambió mi percepción sobre la programación funcional hacia algo mas mundano y realmente necesario. En el vídeo Odersky argumenta que las aplicaciones de hoy son altamente concurrentes por definición y deben ser altamente paralelizables y que esto se puede conseguir más fácilmente siguiendo un paradigma funcional ya que se basa en la inmutabilidad de las variables (bien, realmente promulga el uso de Scala, que estrictamente es un lenguaje híbrido OO-funcional, pero creo que los argumentos que expone se pueden extrapolar a cualquier lenguaje que admita un paradigma funcional).
Del vídeo también encuentro interesante también la asociación que hace entre “programación imperativa = focalización en el tiempo” y “programación funcional => focalización en el espacio” y como lo enlaza con la dificultad de gestionar la concurrencia.
Fijaros que uno de los principios básicos de la pro
Etiquetas de Technorati: ,
gramación funcional es la inmutabilidad de las variables, esto implica que la ejecución del código no tiene “side-effects”, es decir, la ejecución de una función con los mismos argumentos proporciona siempre el mismo resultado => el orden de ejecución de un programa funcional es irrelevante. Ummmm, un código con estas características parece que será altamente parelelizable ¿no?
Para mi esta es la motivación real del auge hoy en día de la programación funcional, ya que soluciona un problema tangible y muy actual como es la paralelización y además lo hace de la mano de un conjunto de teorías muy sólidas (basadas en teorías matemática) y un nivel de abstracción superior a los lenguajes imperativos.

Conclusiones

De mi  primera toma de contacto con la programación funcional me quedo con lo siguiente:
  • La programación funcional se basa en un paradigma muy diferente al que he usado hasta ahora y abre nuevas formas de plantear los problemas mucho mas naturales.
  • La clave del auge actual de la programación funcional es que la escalabilidad y la parelelización son imprescindibles en las aplicaciones actuales y paralelizar con mutación de estado es muy complejo.
  • Quiero aprender mucho más sobre programación funcional!!!