Pregunta ¿La programación funcional reemplaza los patrones de diseño de GoF?


Desde que empecé a aprender F # y OCaml el año pasado, he leído una gran cantidad de artículos que insisten en que los patrones de diseño (especialmente en Java) son soluciones para las características que faltan en los idiomas imperativos. Un artículo que encontré hace un reclamo bastante fuerte:

La mayoría de las personas que he conocido han leído   Libro de patrones de diseño de la pandilla de   Cuatro. Cualquier programador que se precie   te dirá que el libro es   lenguaje agnóstico y los patrones   aplicar a la ingeniería de software en   general, independientemente de qué idioma   tu usas. Este es un noble reclamo.   Lamentablemente está muy lejos de   la verdad.

Los lenguajes funcionales son extremadamente   expresivo. En un lenguaje funcional   uno no necesita patrones de diseño   porque el lenguaje es muy probable   nivel, terminas programando en   conceptos que eliminan el diseño   patrones todos juntos.

Las principales características de la programación funcional incluyen funciones como valores de primera clase, currying, valores inmutables, etc. No me parece obvio que los patrones de diseño de OO se aproximen a cualquiera de esas características.

Además, en los lenguajes funcionales que soportan OOP (como F # y OCaml), me parece obvio que los programadores que usan estos lenguajes usarían los mismos patrones de diseño disponibles para cada otro lenguaje OOP. De hecho, en este momento utilizo F # y OCaml todos los días, y no hay diferencias notables entre los patrones que uso en estos lenguajes frente a los patrones que uso cuando escribo en Java.

¿Hay algo de cierto en la afirmación de que la programación funcional elimina la necesidad de patrones de diseño OOP? De ser así, ¿podría publicar o vincular un ejemplo de un patrón de diseño OOP típico y su equivalente funcional?


941
2017-11-29 20:08


origen


Respuestas:


La publicación de blog que citó exagera un poco su afirmación. FP no lo hace eliminar la necesidad de patrones de diseño. El término "patrones de diseño" simplemente no se usa ampliamente para describir lo mismo en lenguajes FP. Pero ellos existen. Los lenguajes funcionales tienen muchas reglas de mejores prácticas de la forma "cuando encuentras el problema X, usa un código que se parece a Y", que es básicamente lo que es un patrón de diseño.

Sin embargo, es correcto que la mayoría de los patrones de diseño específicos de OOP son prácticamente irrelevantes en los lenguajes funcionales.

No creo que deba ser particularmente controvertido decir que los patrones de diseño en general solo existe para arreglar defectos en el lenguaje. Y si otro idioma puede resolver el mismo problema trivialmente, ese otro idioma no necesitará un patrón de diseño para él. Los usuarios de ese idioma pueden incluso no ser conscientes de que el problema existeporque, bueno, no es un problema en ese idioma.

Esto es lo que The Gang of Four tiene que decir sobre este tema:

La elección del lenguaje de programación es importante porque influye en el punto de vista de uno. Nuestros patrones asumen características de lenguaje de nivel Smalltalk / C ++, y esa elección determina qué se puede implementar y qué no se puede implementar fácilmente. Si asumimos los lenguajes de procedimiento, podríamos haber incluido patrones de diseño llamados "Herencia", "Encapsulación" y "Polimorfismo". Del mismo modo, algunos de nuestros patrones son compatibles directamente con los lenguajes orientados a objetos menos comunes. CLOS tiene múltiples métodos, por ejemplo, que disminuyen la necesidad de un patrón como Visitor. De hecho, hay suficientes diferencias entre Smalltalk y C ++ para indicar que algunos patrones se pueden expresar más fácilmente en un idioma que en el otro. (Véase Iterador, por ejemplo).

(Lo anterior es una cita del libro Introducción a los patrones de diseño, página 4, párrafo 3)

Las principales características de funcional   la programación incluye funciones como   valores de primera clase, currying,   valores inmutables, etc. No parece   obvio para mí que los patrones de diseño OO   están aproximándose a cualquiera de esos   caracteristicas.

¿Cuál es el patrón de comando, si no es una aproximación de las funciones de primera clase? :) En un lenguaje FP, simplemente pasaría una función como argumento a otra función. En un lenguaje OOP, debe cerrar la función en una clase, la cual puede instanciar y luego pasar ese objeto a la otra función. El efecto es el mismo, pero en OOP se llama patrón de diseño y requiere mucho más código. ¿Y cuál es el patrón de fábrica abstracto, si no es currying? Pase los parámetros a una función de a poco a la vez, para configurar qué tipo de valor escupirá cuando finalmente lo llame.

Entonces sí, varios patrones de diseño de GoF se vuelven redundantes en los lenguajes de FP, porque existen alternativas más potentes y fáciles de usar.

Pero, por supuesto, todavía hay patrones de diseño que son no resuelto por los lenguajes FP. ¿Cuál es el equivalente FP de un singleton? (Ignorando por un momento que los singletons son generalmente un patrón terrible de usar)

Y funciona en ambos sentidos también. Como dije, FP también tiene sus patrones de diseño, las personas simplemente no suelen pensar en ellos como tales.

Pero es posible que haya encontrado mónadas. ¿Qué son, sino un patrón de diseño para "tratar con el estado global"? Ese es un problema tan simple en los lenguajes OOP que no existe un patrón de diseño equivalente allí.

No necesitamos un patrón de diseño para "incrementar una variable estática", o "leer de ese socket", porque es justo lo que hacer.

En los lenguajes funcionales (puros), los efectos secundarios y el estado mutable son imposibles, a menos que trabajes con el "patrón de diseño" de la mónada o con cualquiera de los otros métodos para permitir lo mismo.

Además, en lenguajes funcionales   que admiten OOP (como F # y   OCaml), me parece obvio que   programadores que usan estos lenguajes   usaría los mismos patrones de diseño   encontrado disponible para cada otro POO   idioma. De hecho, ahora mismo uso F #   y OCaml todos los días, y no hay   sorprendentes diferencias entre los   patrones que uso en estos idiomas vs   los patrones que uso cuando escribo   Java.

Tal vez porque todavía estás pensando imperativamente? Muchas personas, después de lidiar con idiomas imperativos durante toda su vida, tienen dificultades para renunciar a ese hábito cuando intentan un lenguaje funcional. (He visto algunos intentos bastante divertidos en F #, donde literalmente cada la función era solo una cadena de declaraciones 'let', básicamente como si hubieras tomado un programa C, y reemplazaste todos los puntos y comas por 'let'. :))

Pero otra posibilidad podría ser que simplemente no se haya dado cuenta de que está resolviendo problemas trivialmente, lo que requeriría patrones de diseño en un lenguaje OOP.

Cuando usa currying o pasa una función como argumento a otro, deténgase y piense cómo lo haría en un lenguaje OOP.

¿Hay algo de verdad en la afirmación de que   programación funcional elimina el   necesidad de patrones de diseño OOP?

Sí. :) Cuando trabaja en un lenguaje FP, ya no necesita los patrones de diseño específicos de OOP. Pero aún necesita algunos patrones de diseño generales, como MVC u otras cosas no específicas de OOP, y necesita un par de nuevos "patrones de diseño" específicos de FP. Todos los idiomas tienen sus defectos, y los patrones de diseño son generalmente la forma en que trabajamos a su alrededor.

De todos modos, puede que le resulte interesante probar con los lenguajes FP "más limpios", como ML (mi favorito personal, al menos para fines de aprendizaje), o Haskell, donde no tiene la muleta OOP para recurrir cuando se enfrentan a algo nuevo


Como era de esperar, algunas personas se opusieron a mi definición de patrones de diseño como "corregir fallas en un idioma", así que aquí está mi justificación: Como ya se dijo, la mayoría de los patrones de diseño son específicos de un paradigma de programación, o incluso de un lenguaje específico. A menudo, resuelven problemas que solo existe en ese paradigma (Ver mónadas para FP, o fábricas abstractas para OOP). ¿Por qué no existe el patrón abstracto de fábrica en FP? Porque el problema que trata de resolver no existe allí. Entonces, si existe un problema en los lenguajes de OOP, que no existe en los lenguajes de FP, entonces claramente eso es una deficiencia de los lenguajes de OOP. El problema puede ser resuelto, pero su lenguaje no lo hace, pero requiere un montón de código repetitivo para evitarlo. Idealmente, nos gustaría que nuestro lenguaje de programación haga mágicamente todas los problemas desaparecen Cualquier problema que todavía existe es, en principio, una deficiencia del lenguaje. ;)


950
2017-11-29 23:06



¿Hay algo de cierto en la afirmación de que la programación funcional elimina la necesidad de patrones de diseño OOP?

La programación funcional no es lo mismo que la programación orientada a objetos. Los patrones de diseño orientados a objetos no se aplican a la programación funcional. En cambio, tiene patrones de diseño de programación funcional.

Para la programación funcional, no leerá los libros de patrones de diseño de OO, leerá otros libros sobre patrones de diseño de PF.

lenguaje agnóstico

No totalmente. Solo es independiente del idioma con respecto a los lenguajes OO. Los patrones de diseño no se aplican a los lenguajes de procedimiento en absoluto. Apenas tienen sentido en un contexto de diseño de base de datos relacional. No se aplican al diseñar una hoja de cálculo.

un patrón de diseño de OOP típico y su equivalente funcional?

Lo anterior no debería existir. Es como pedir un trozo de código de procedimiento reescrito como código OO. Ummm ... Si traduzco el Fortran original (o C) a Java, no he hecho nada más que traducirlo. Si lo reescribo totalmente en un paradigma OO, ya no se verá como el Fortran o C original: será irreconocible.

No hay un mapeo simple desde OO Design hasta Functional Design. Son formas muy diferentes de ver el problema.

Programación funcional (como todas estilos de programación) tiene patrones de diseño. Las bases de datos relacionales tienen patrones de diseño, OO tiene patrones de diseño, la programación de procedimientos tiene patrones de diseño. Todo tiene patrones de diseño, incluso la arquitectura de los edificios.

Los patrones de diseño, como concepto, son una forma intemporal de construcción, independientemente de la tecnología o el dominio del problema. Sin embargo, los patrones de diseño específicos se aplican a dominios y tecnologías de problemas específicos.

Todos los que piensen en lo que están haciendo descubrirán patrones de diseño.


135
2017-11-29 20:15



Los comentarios de Brian sobre el estrecho vínculo entre el lenguaje y el patrón van al punto,

La parte que falta de esta discusión es el concepto de modismo. El libro de Coplien, "Advanced C ++" fue una gran influencia aquí. Mucho antes de que descubriera a Christopher Alexander y el Columna sin nombre (y tampoco puedes hablar con sensatez sobre los patrones sin leer a Alexander), habló sobre la importancia de dominar el idioma para aprender verdaderamente un idioma. Utilizó una copia de cadena en C como ejemplo, mientras que (* de ++ = * a ++); Puedes ver esto como una curita de una característica de idioma faltante (o característica de la biblioteca), pero lo que realmente importa es que es una unidad de pensamiento o expresión más grande que cualquiera de sus partes.

Eso es lo que intentan hacer los patrones y los lenguajes, para permitirnos expresar nuestras intenciones de manera más sucinta. Cuanto más ricas son las unidades de pensamiento, más complejos son los pensamientos que puedes expresar. Tener un vocabulario rico y compartido en una variedad de escalas -desde la arquitectura del sistema hasta la manipulación de bits- nos permite tener conversaciones más inteligentes y pensamientos sobre lo que deberíamos estar haciendo.

También podemos, como individuos, aprender. Cuál es el punto entero del ejercicio. Todos podemos entender y usar cosas que nunca podríamos pensar de nosotros mismos. Los idiomas, los marcos, las bibliotecas, los patrones, los modismos, etc. tienen su lugar en el intercambio de la riqueza intelectual.


40
2018-01-01 20:59



El libro GOF se vincula explícitamente a OOP - el título es Patrones de diseño - Elementos de reutilización Orientado a objetos Software (énfasis mío)


35
2017-11-24 15:49



Patrones de diseño en programación dinámica por Peter Norvig tiene una cobertura cuidadosa de este tema general, aunque sobre las lenguas "dinámicas" en lugar de "funcional" (hay superposición).


32
2017-11-29 20:23



Aquí hay otro enlace, discutiendo este tema: http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

En su publicación del blog, Edward describe los 23 patrones originales de GoF en términos de Haskell.


24
2017-10-19 08:15



Cuando intenta ver esto en el nivel de "patrones de diseño" (en general) y "FP versus OOP", las respuestas que encontrará serán turbias en el mejor de los casos.

Sin embargo, profundice en ambos ejes y considere patrones de diseño específicos y características específicas del lenguaje y las cosas se vuelven más claras.

Entonces, por ejemplo, algunos patrones específicos, como Visitante, Estrategia, Mandoy Observador definitivamente cambia o desaparece al usar un lenguaje con tipos de datos algebraicos y coincidencia de patrones, cierres, funciones de primera claseSin embargo, algunos otros patrones del libro de GoF aún se "quedan".

En general, diría que, con el tiempo, los patrones específicos se están eliminando con nuevas características del lenguaje (o simplemente creciente en popularidad). Este es el curso natural del diseño del lenguaje; a medida que los idiomas se vuelven de más alto nivel, las abstracciones que antes solo podían mencionarse en un libro utilizando ejemplos ahora se convierten en aplicaciones de una característica de idioma o biblioteca en particular.

(Aparte: aquí hay un blog reciente Escribí, que tiene otros enlaces a más discusión sobre FP y patrones de diseño.)


17
2017-11-29 23:15



La presentación de Norvig alude a un análisis que hicieron de todos los patrones de GoF, y dicen que 16 de los 23 patrones tenían implementaciones más simples en lenguajes funcionales, o simplemente eran parte del lenguaje. Entonces, presumiblemente, al menos siete de ellos eran a) igualmente complicados ob) no estaban presentes en el idioma. Desafortunadamente para nosotros, ¡no están enumerados!

Creo que está claro que la mayoría de los patrones "creacionales" o "estructurales" en GoF son simplemente trucos para hacer que los sistemas de tipos primitivos en Java o C ++ hagan lo que quieran. Pero el resto es digno de consideración sin importar en qué idioma programe.

Uno podría ser Prototipo; si bien es una noción fundamental de JavaScript, debe implementarse desde cero en otros idiomas.

Uno de mis patrones favoritos es el patrón Objeto nulo: representa la ausencia de algo como un objeto que hace un tipo apropiado de nada. Esto puede ser más fácil de modelar en un lenguaje funcional. Sin embargo, el verdadero logro es el cambio de perspectiva.


15
2017-11-30 07:11



Diría que cuando tienes un lenguaje como Lisp con su soporte para macros, entonces puedes construir tus propias abstracciones específicas de dominio, abstracciones que a menudo son mucho mejores que las soluciones de modismos generales.


15
2017-12-16 19:44