Hay un artículo clásico llamado Sobre los criterios que se utilizarán en la descomposición de sistemas en módulos que acabo de leer por primera vez. Tiene mucho sentido para mí, y es probablemente uno de esos artículos en los que se basó OOP. Su conclusión:
Hemos tratado de demostrar con estos ejemplos que casi siempre es incorrecto comenzar la descomposición de un sistema en módulos sobre la base de un diagrama de flujo. ... Cada módulo está diseñado para ocultar tal decisión de los demás
En mi opinión inexperta e inexperta, la programación funcional toma exactamente el consejo opuesto de este artículo. Entiendo que la programación funcional hace que el flujo de datos sea idiomático. Los datos se pasan de una función a otra, cada función es íntimamente consciente de los datos y "los cambia" en el camino. Y creo que he visto una charla de Rich Hickey en la que habla sobre cómo la ocultación de datos está sobrevalorada o es innecesaria o algo así, pero no puedo recordarlo con certeza.
- Primero quiero saber si mi evaluación es correcta. ¿El paradigma FP y este artículo no están filosóficamente en desacuerdo?
- Suponiendo que no estén de acuerdo, ¿cómo FP "compensa" su falta de ocultación de datos? Quizás sacrifiquen la ocultación de datos pero obtienen X, Y y Z. Me gustaría saber el razonamiento de por qué X, Y y Z se consideran más beneficiosos que la ocultación de datos.
- O, suponiendo que no estén de acuerdo, quizás FP siente que ocultar datos es malo. Si es así, ¿por qué cree que la ocultación de datos es mala?
- Suponiendo que estén de acuerdo, me gustaría saber qué es la implementación de FP de la ocultación de datos. Es obvio ver esto en OOP. Puede tener un
private
campo al que nadie fuera de la clase pueda acceder. No hay una analogía obvia de esto para mí en FP. - Siento que hay otras preguntas que debería hacer, pero no sé si debería estar haciendo. Siéntase libre de responderlas también.
Actualizar
Encontré esta charla de Neal Ford que tiene una diapositiva muy relevante. Insertaré la captura de pantalla aquí:
fuente
Respuestas:
El artículo que menciona es sobre la modularidad en general, y se aplicaría igualmente a programas estructurados, funcionales y orientados a objetos. He oído hablar de ese artículo anteriormente de alguien que era un gran tipo de OOP, pero lo leí como un artículo sobre programación en general, no algo específico de OOP. Hay un famoso artículo sobre programación funcional, Por qué es importante la programación funcional , y la primera oración de la conclusión dice "En este artículo, hemos argumentado que la modularidad es la clave para una programación exitosa". Entonces la respuesta a (1) es no.
Las funciones bien diseñadas no asumen más sobre sus datos de lo que necesitan, por lo que la parte sobre "conocimiento íntimo de los datos" es incorrecta. (O al menos tan equivocado como sería de OOP. No se puede programar estrictamente a un alto nivel de abstracción e ignorar todos los detalles para siempre en cualquier paradigma. Al final, alguna parte del programa realmente necesita saber sobre el detalles específicos de los datos).
La ocultación de datos es un término específico de OOP, y no es exactamente lo mismo que la ocultación de información discutida en el artículo. La información que se esconde en el artículo trata sobre decisiones de diseño que fueron difíciles de tomar o que probablemente cambien. No todas las decisiones de diseño sobre un formato de datos son difíciles o susceptibles de cambiar, y no todas las decisiones que son difíciles o susceptibles de cambiar se refieren a un formato de datos. Personalmente, no puedo ver por qué los programadores de OO quieren que todo sea un objeto. A veces, una estructura de datos simple es todo lo que necesita.
Editar: encontré una cita relevante de una entrevista con Rich Hickey .
fuente
En realidad no, pero se agregó a la discusión, especialmente a los profesionales que, en ese momento, fueron entrenados para descomponer sistemas utilizando los primeros criterios que describe en el documento.
No. Además, a mis ojos, su descripción de cómo se ve un programa de FP no es diferente de cualquier otro que use procedimientos o funciones:
... excepto la parte de "intimidad", ya que puede (y a menudo lo hace) tener funciones que operan en datos abstractos, precisamente para evitar la intimidad. Por lo tanto, tiene cierto control sobre esa "intimidad" y puede regularla como quiera, configurando interfaces (es decir, funciones) para lo que desea ocultar.
Por lo tanto, no veo ninguna razón por la cual no podríamos seguir los criterios de ocultación de información de Parnas utilizando la programación funcional y terminar con una implementación de un índice KWIC con beneficios puntuales similares a su segunda implementación.
En lo que respecta a los datos, puede elaborar abstracciones de datos y abstracciones de tipo de datos utilizando FP. Cualquiera de estas estructuras de hormigón ocultas y manipulaciones de estas estructuras de hormigón utilizando funciones como abstracciones.
EDITAR
Aquí hay un número creciente de afirmaciones que afirman que "ocultar datos" en el contexto de FP no es tan útil (o OOP-ish (?)). Entonces, permítanme estampar aquí un ejemplo muy simple y claro de SICP:
Suponga que su sistema necesita trabajar con números racionales. Una forma de representarlos es como un par o una lista de dos enteros: el numerador y el denominador. Así:
Si ignora la abstracción de datos, lo más probable es que obtenga el numerador y el denominador usando
car
ycdr
:Siguiendo este enfoque, todas las partes del sistema que manipulan números racionales sabrán que un número racional es a
cons
: crearáncons
números para crear racionales y extraerlos utilizando operadores de lista.Un problema que puede enfrentar es cuando necesita tener una forma reducida de los números racionales: se requerirán cambios en todo el sistema. Además, si decide reducir en el momento de la creación, es posible que más tarde reduzca cuando acceder a uno de los términos racionales es mejor, produciendo otro cambio a escala completa.
Otro problema es si, hipotéticamente, se prefiere una representación alternativa para ellos y usted decide abandonar la
cons
representación - cambio de escala total nuevamente.Cualquier esfuerzo sensato al tratar estas situaciones probablemente comenzará a ocultar la representación de los racionales detrás de las interfaces. Al final, podrías terminar con algo como esto:
(make-rat <n> <d>)
devuelve el número racional cuyo numerador es el entero<n>
y cuyo denominador es el entero<d>
.(numer <x>)
devuelve el numerador del número racional<x>
.(denom <x>)
devuelve el denominador del número racional<x>
.y el sistema ya no sabrá (y ya no debería) saber de qué están hechos los racionales. Esto es porque
cons
,car
ycdr
no son intrínsecos a los racionales, peromake-rat
,numer
y lodenom
son . Por supuesto, esto podría ser fácilmente un sistema FP. Entonces, la "ocultación de datos" (en este caso, mejor conocida como abstracción de datos, o el esfuerzo de encapsular representaciones y estructuras concretas) se presenta como un concepto relevante y una técnica ampliamente utilizada y explorada, ya sea en el contexto de OO, programación funcional o lo que sea.Y el punto es ... aunque uno puede tratar de hacer distinciones entre qué "tipo de ocultamiento" o encapsulación están haciendo (ya sea que estén ocultando una decisión de diseño, o estructuras de datos o algoritmos, en el caso de abstracciones de procedimiento), Todos tienen el mismo tema: están motivados por uno o más puntos que Parnas hizo explícitos. Es decir:
El ejemplo anterior se tomó del libro SICP, por lo que, para la discusión y presentación completa de estos conceptos en el libro, recomiendo consultar el capítulo 2 . También recomiendo familiarizarse con los tipos de datos abstractos en el contexto de FP, que trae otros problemas a la mesa.
fuente
Su creencia de que la programación funcional carece de ocultación de datos es incorrecta. Simplemente toma un enfoque diferente para ocultar datos. Una de las formas más comunes de ocultar datos en la programación funcional es mediante el uso de funciones polimórficas que toman una función como argumento. Por ejemplo, esta función
solo puede ver la estructura más externa de los datos (es decir, que es una lista), no puede ver nada acerca de los datos que contiene la lista y solo puede operar en los datos a través de la única función que se le pasa.
La función que se pasa como argumento es análoga a un método público en el tipo de datos que contiene la lista. Proporciona una forma limitada de operar en los datos, pero no expone el funcionamiento interno del tipo de datos.
fuente
Voy a ponerme en peligro aquí y decir que el concepto simplemente no es relevante en FP como lo es en OO.
tl; dr; El objetivo de la ocultación de datos es garantizar que las responsabilidades se mantengan donde deberían estar, y que no haya actores externos jugando con datos para los que no tienen el conocimiento. En FP, los datos se generan mediante expresiones, y de esta manera no puedes meterte con los datos porque no son tanto las propiedades mutables como los cálculos componibles que cambian completamente las reglas del juego.
En mis experiencias con FP; que son ciertamente insignificantes, tiendo a encontrar un marcado contraste con OO en lo que denota un modelado de datos bueno / común.
Este contraste es que en OO en general, usted modela cosas para representar sus datos. Analogía obligatoria del automóvil:
OO
Lo que hay que tener en cuenta aquí es que cuando modela cosas en un formato OO, se trata de representar cosas como datos. Tiene objetos con propiedades, muchas de esas propiedades son objetos con más propiedades. Tiene un par de métodos adjuntos aquí y allá para esos objetos, pero todo lo que realmente hacen es activar las propiedades de los objetos de esta manera y, de nuevo, es un modelado muy centrado en los datos; es decir, modela sus datos para que interactúen centrándose en estructurarlos para que estén disponibles todos los puntos de sus datos para que los consumidores puedan cambiar los datos de una manera u otra.
FP
La gran diferencia entre OO y FP que constantemente me llama la atención es, como dije anteriormente, la forma en que modelas los datos. En OO como se mencionó anteriormente, modela datos como datos, en FP modela datos como cálculos, expresiones, algoritmos, se trata más de modelar las actividades de sus datos que de los hechos. Piense en el modelado de datos básicos en matemáticas, siempre se trata de obtener una ecuación que pueda generar sus datos, que modele sus datos como la actividad que los causa, a diferencia de OO, el modelado está creando una forma de representar los datos que tiene. Esa es gran parte de la distinción entre FP y OO.
Recuerde, durante mucho tiempo LISP, uno de los lenguajes FP básicos, vivió con una cantidad muy pequeña de tipos de datos primitivos. Esto funciona porque el enfoque no se trata de modelar representaciones complejas de sus datos, sino cálculos que generan y expresan los comportamientos de su sistema.
Cuando comienzo a escribir algún código en FP, comienzo escribiendo código que hace algo, mientras que cuando comienzo a escribir código en OO, comienzo escribiendo modelos que describen algo. El hacer cosas está oculto en FP por ser expresiones, el hacer cosas está expuesto en OO al describirse con datos, y ocultar estos datos limita dicha exposición.
Volviendo a la pregunta en cuestión, ¿qué dice FP sobre la ocultación de datos, lo aprecia o no está de acuerdo con eso o no?
Digo que no importa, en OO, sus datos son las agallas y las piezas importantes en su programa que deben ocultarse para que no se entrometan. En FP, las agallas y el conocimiento de su sistema están ocultos en los algoritmos y cálculos que expresan el sistema. Estos son, por definición, más o menos inmutables, la única forma de mutar las expresiones de cálculo son cosas como las macros, pero incluso entonces las definiciones de mutaciones son expresiones en sí mismas que no pueden entrometerse más.
fuente
Hay una pequeña paradoja aquí. Aunque la programación funcional se centra en, bueno, funciones, y con frecuencia tiene funciones que funcionan directamente en tipos de datos primitivos, tiende a tener más ocultación de datos que la programación orientada a objetos.
¿Cómo es esto así? Piense en una buena interfaz OO que oculta los datos subyacentes, tal vez colecciones (estoy tratando de elegir algo casi omnipresente). Es posible que no necesite conocer el tipo subyacente de los objetos en la colección o el tipo de objeto que implementa la colección, siempre que sepa que la colección implementa, por ejemplo, IEnumerable. Entonces tienes datos ocultos.
En la programación funcional, puede escribir una función que funcione efectivamente con una interfaz IEnumerable, pero que opere en un tipo de datos primitivo (o en cualquier tipo de datos). Pero, ¿qué pasa si el tipo nunca implementó los métodos IEnumerable? Aquí está la clave, siempre puede hacer que los "métodos" que forman las piezas necesarias de la "interfaz" se transfieran a su función. O puede juntar funciones con datos y hacer las cosas de forma similar a OO.
Tenga en cuenta que de cualquier manera no tiene menos datos ocultos que los que tiene en OO. Mi función general que funciona en cualquier tipo claramente no está accediendo a los datos en ese tipo, eso sucede dentro de las funciones pasadas como parámetros a la función general, pero la función general nunca se asoma dentro de esas funciones para ver los datos.
Entonces, en lo que respecta a su punto 1, no creo que FP y el artículo estén realmente en desacuerdo. No creo que su caracterización de FP no oculte datos es correcta. Uno podría implementar el diseño que el autor prefirió en FP, ciertamente.
En cuanto al punto 4 (2 y 3 no tiene sentido responder dado lo que he dicho para el punto 1), varía. También varía en los idiomas OO, y en muchos campos privados son privados por convención en lugar de exigidos por el idioma.
fuente
Primero, gracias por el enlace a este gran artículo, no lo sabía hasta ahora, y me dio una gran aportación sobre algunas cosas que estaba discutiendo con otros diseñadores de software de la comunidad en los últimos años. Aquí está mi opinión al respecto:
El diseño de FP se centra mucho en el flujo de datos (en mi humilde opinión, no es tan malo como el artículo puede implicar). Si esto es un completo "desacuerdo" es discutible.
En mi humilde opinión, no compensa. Vea abajo.
No creo que la mayoría de los usuarios o diseñadores de FP se sientan o piensen de esta manera, ver a continuación.
Aquí está el punto: probablemente haya visto tantos sistemas OOP implementados de una manera no funcional que cree que OOP no es funcional. Y eso es una falacia, IMHO OOP y FP son en su mayoría conceptos ortogonales, y puedes construir perfectamente sistemas OO funcionales, lo que te da una respuesta obvia a tu pregunta. La implementación clásica de "objetos" en FP se realiza mediante el uso de cierres , y si desea que los objetos se usen en un sistema funcional, el punto clave es diseñarlos inmutables.
Entonces, para crear sistemas más grandes, en mi humilde opinión, puede crear módulos, clases y objetos utilizando conceptos OO, exactamente de la manera descrita en "Modularización 2" en el artículo sin salir de la "ruta FP". Utilizará el concepto de módulo de su lenguaje FP favorito, hará que todos sus objetos sean inmutables y use "lo mejor de ambos mundos".
fuente
TL; DR : No
¿El paradigma FP y este artículo no están filosóficamente en desacuerdo?
No, no lo hace. La programación funcional es declarativa, que es "un estilo de construcción de la estructura y los elementos de los programas de computadora, que expresa la lógica de un cálculo sin describir su flujo de control". Se trata menos de seguir el diagrama de flujo y más como crear las reglas que permiten que el flujo surja por sí solo.
La programación de procedimientos está mucho más cerca de la codificación de un diagrama de flujo que la programación funcional. Se deduce que las transformaciones que ocurren, y las codifica en procedimientos que se ejecutan en orden, exactamente como lo describe el flujo en un diagrama de flujo.
Ocultar datos
fuente