User Tools

Site Tools


programacion:paradigmas

Caracteristicas tecnicas de los lenguajes y paradigmas actuales de programacion

Definición

Un paradigma de programación es una propuesta tecnológica adoptada por una comunidad de programadores, y desarrolladores cuyo núcleo central es incuestionable en cuanto que únicamente trata de resolver uno o varios problemas claramente delimitados; la resolución de estos problemas debe suponer consecuentemente un avance significativo en al menos un parámetro que afecte a la ingeniería de software. Representa un enfoque particular o filosofía para diseñar soluciones. Los paradigmas difieren unos de otros, en los conceptos y la forma de abstraer los elementos involucrados en un problema, así como en los pasos que integran su solución del problema, en otras palabras, el cómputo. Tiene una estrecha relación con la formalización de determinados lenguajes en su momento de definición. Es un estilo de programación empleado.

https://es.wikipedia.org/wiki/Paradigma_de_programaci%C3%B3n

Programming paradigms are approaches based on a mathematical theory or particular set of principles, each paradigm supporting a set of concepts. There are a huge number of programming languages, but many fewer paradigms. But there are still a lot of paradigms. This chapter mentions 27 different paradigms that are actually used.

Programming paradigms for dummies: what every programmer should know

Familias de paradigmas: imperativo y declarativo

Una primera clasificación entre paradigmas de programación nos permite identificar dos grandes bloques: el paradigma imperativo y el declarativo.

paradigma imperativo

Los lenguajes que pertenecen al paradigma imperativo consisten en lo que podríamos llamar comandos o sentencias, es decir, órdenes que describen cómo debe funcionar el programa.

Las técnicas usadas en los lenguajes de programación imperativos suelen estar orientadas a encapsular funcionalidades en procedimientos, llamados también subrutinas o funciones. El código se suele organizar en formas denominadas programación estructurada, programación modular o programación orientada a objetos.

paradigma declarativo

Los programas que pertenecen al paradigma declarativo no detallan cómo debe funcionar el programa sino qué resultados debe obtener. El programa consiste en detallar la lógica computacional implicada pero sin entrar en detalle sobre cómo realizarla, por ello muchos programas de este paradigma consisten en la evaluación de expresiones, por ello se denomina a este tipo de programación funcional. Ejemplos de lenguajes encuadrados en este tipo de paradigma son los lenguajes de consulta de bases de datos como SQL, las expersiones regulares, los lenguajes de programación lógica (Prolog) o los lenguajes de programación funcional (Lisp, Clojure, Elixir, Kotlin, Swift, Haskell y también lenguajes de programación imperativa que pueden ser usados bajo el paradigma funcional, como Python, PHP 6, Ryby, etc)

En el paradigma declarativo encontramos técnicas como la programación con restricciones o la lógica matemática asociada al cálculo lambda, desarrollado por Alonzo Church a partir de 1930. El paradigma declarativo está muy diversificado en lo que se llama lenguajes de dominio específico, que es el concepto opuesto a “lenguajes de propósito general”, y por eso encontramos lenguajes del paradigma declarativo en el dominio de los analizadores linguísticos (yacc), de las búsquedas con patrones (expresiones regulares), de las consultas a base de datos (SQL), de generación de interfaces (HTML) o las restricciones que los backend deben hacer sobre las aplicaciones web para generar las páginas y que se han dado en llamar representational state transfer (REST) y SOAP.

https://www.toptal.com/software/declarative-programming

Programación funcional

Programación orientada a objetos

Cuestionamiento del paradigma

Allen Holub, uno de los editores de la revista JavaWorld cuenta en un artículo publicado en esta revista en agosto de 2013 titulado “Why extends is evil. Improve your code by replacing concrete base classes with interfaces” que estuvo presente en una reunión de un grupo de usuarios de Java a la que asistió James Gosling, padre del lenguaje Java cuando trabajaba en Sun Microsystems en 1995. Cuenta que en la sesión de preguntas alguien preguntó a Gosling qué cambiaría de Java si pudiera desarrollarlo de nuevo partiendo de cero a lo que él, en broma, contestó “quitaría las clases”, lo que provocó la risa del público ya que es un componente fundamental del lenguaje.

Sin embargo luego explicó la broma indicando, ya en serio, que había un problema con las clases que no era su existencia sino la herencia por implementación, también llamada herencia de código, es decir, la relación entre dos clases denominada en Java extends ya que esta relación produce lo que se ha dado en llamar el problema de fragilidad de las clases base, que consiste en que es posible modificar una clase de una forma sencilla pero nada garantiza que cuando este cambio se herede por clases derivadas siga funcionando. Para conseguir que el cambio siga funcionando en todas las clases derivadas habría que examinar el código de todas ellas. Este excesivo acoplamiento entre las clases base y las clases derivadas mediante extends hace que un cambio en una clase pueda provocar un fallo en una aplicación aunque el cambio esté correctamente efectuado en la clase.

Por ello Gosling aclaró que lo que cambiaría en Javaera esta relación entre clases y la sustruiría por la herencia por interfaces, que es la relación entre dos clases denominada en Java implements y basada en el concepto de interfaces.

Implementación en Go

Una de las características de Go es su ortogonalidad, es decir, la facilidad con la que podemos mezclar unos conceptos del lenguaje con otros para crear estructuras complejas pero consistentes. Uno de dichos ejemplos de ortogonalidad es la que sucede con tipos (type) y métodos (func), que pueden mezclarse para formar estructuras que se comportan como objetos sin necesidad de declarar objetos como tales. En Go un método que se asocia a un tipo recibe el nombre de receiver. Un “receiver” es, por tanto, un método asociados a una estructura de datos.

Como indica el desarrollador Ben Johnson en la entrada de su blog titulada The Go Object Lifecycle Go permite usar estructuras de 'objetos' de formas muy diversas pero propone una aproximación en 3 pasos al manejo de objetos en Go: instanciación, inicialización e iniciación:

  1. Instanciación, fase en la que se reserva la memoria para el objeto, se declara el constructor (mediante un receiver) que carga los valores por defecto en los datos del struct
  2. Inicialización, que es la fase de configuración del objeto para un uso específico. Se usan campos del struct exportados (primera letra mayúscula) para almacenat dichos valores de configuración (settings)
  3. Iniciación, que permite al objeto ya creado conectar con recurtsos remotos que necesite. Para ello se suelen usar funciones del tipo Open() o Start() que tendrán su equivalente probablemente en forma de Close() End() cuando el objeto deje de usarse.

Johnson también documenta otras dos propuestas metodológicas de uso de objetos:

  1. Opciones Funcionales, que fusiona las fases de Inicialización e Iniciación
  2. Instanciación de la Configuración

Why doesn't Go have "implements" declarations?

A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without needing to modify existing code. It enables a kind of structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, lightweight feel.

https://golang.org/doc/faq#implements_interface

Why is there no type inheritance?

Object-oriented programming, at least in the best-known languages, involves too much discussion of the relationships between types, relationships that often could be derived automatically. Go takes a different approach.

Rather than requiring the programmer to declare ahead of time that two types are related, in Go a type automatically satisfies any interface that specifies a subset of its methods. Besides reducing the bookkeeping, this approach has real advantages. Types can satisfy many interfaces at once, without the complexities of traditional multiple inheritance. Interfaces can be very lightweight—an interface with one or even zero methods can express a useful concept. Interfaces can be added after the fact if a new idea comes along or for testing—without annotating the original types. Because there are no explicit relationships between types and interfaces, there is no type hierarchy to manage or discuss.

It's possible to use these ideas to construct something analogous to type-safe Unix pipes. For instance, see how fmt.Fprintf enables formatted printing to any output, not just a file, or how the bufio package can be completely separate from file I/O, or how the image packages generate compressed image files. All these ideas stem from a single interface (io.Writer) representing a single method (Write). And that's only scratching the surface. Go's interfaces have a profound influence on how programs are structured.

It takes some getting used to but this implicit style of type dependency is one of the most productive things about Go.

https://golang.org/doc/faq#inheritance

Concurrencia

En su libro Seven Concurrency Models in Seven Weeks, Paul Butcher analiza los principales paradigmas para lograr la ejecución simultánea de procesos en un programa aprovechando las nuevas facilidades que otorga el hardware, tales como los múltiples núcleos en los procesadores que permiten dividir la ejecución de un programa en hilos o threads.

La concurrencia y el paralelismo son dos conceptos diferentes aunque muy relacionados entre sí. En una charla sobre el tema titulada Concurrency is not Paralelism Rob Pike indicó que “Concurrencia tiene que ver con procesar cosas que suceden a la vez. Paralelismo tiene que ver con ejecutar muchas cosas a la vez”.

Los siete modelos de concurrencia que, según Butler, componen este paradigma son:

  1. Hilos y Semáforos
  2. Programación funcional (eliminar estado)
  3. Clausura: separar identidad y estado (mezcla de programación imperativa y funcional posible en el lenguaje Clojure)
  4. Actores
  5. Communicating Sequential Processes (CSP), desarrollada por C.A.R Hoare y popularizada últimamente por el lenguaje de programación Go.
  6. Paralelismo de datos (entre CPU y GPU)
  7. Arquitectura Lambda (popular en procesos Big Data, que mezcla MapReduce con Stream Processing para conseguir la obtención de datos en tiempo real)

Clausura (cerraduras)

En lenguajes de programación, una clausura o cerradura2 (del inglés closure) es una técnica para implementar ámbitos léxicos en un lenguaje de programación con funciones de primera clase. Una cerradura es un registro que contiene una función junto con el ámbito donde fue declarada. La clausura permite que la función acceda a los valores de las variables declaradas en el mismo ámbito, aun cuando la invocación ocurra fuera de este. El uso de clausuras se asocia con el paradigma de programación funcional.

Clausura, Wikipedia

Es decir, la función está clausurada porque “recuerda” el ámbito en el que se ha creado.

Funciones de primera clase en Go

Go supports first class functions, higher-order functions, user-defined function types, function literals, closures, and multiple return values. This rich feature set supports a functional programming style in a strongly typed language.

—- Codewalk: First-Class Functions in Go

Clausura en Go

Reflection (reflexión)

En informática, reflexión (o reflexión computacional) es la capacidad que tiene un programa para observar y opcionalmente modificar su estructura de alto nivel. En un sentido más amplio, la reflexión es una actividad computacional que razona sobre su propia computación.

Normalmente, la reflexión es dinámica o en tiempo de ejecución, aunque algunos lenguajes de programación permiten reflexión estática do o en tiempo de compilación. Es más común en lenguajes de programación de alto nivel ejecutándose sobre una máquina virtual, como Smalltalk o Java, y menos común en lenguajes como C. Cuando el código fuente de un programa se compila, normalmente se pierde la información sobre la estructura del programa conforme se genera el código de bajo nivel (normalmente lenguaje ensamblador). Si un sistema permite reflexión, se preserva la estructura como metadatos en el código generado. Dependiendo de la implementación, el código con reflexión tiende a ser más lento que el que no lo tiene.

—- Reflexión, Wikipedia

Hay debate respecto a si se puede considerar la técnica de reflexión (la capacidad que tiene un programa para observar y opcionalmente modificar su estructura de alto nivel en tiempo de ejecución) usada en programación simbólica, como un paradigma diferente o como una característica adicional que puede añadirse al resto de paradigmas.

Behavioral Programming

JAM JavaScript, API, Markup

Conferencias

¿Qué demonios es la programación funcional?

En mi día a día, como fan reconocido de la programación funcional que soy, intento vender a mis compañeros desarrolladores el uso de este paradigma, obteniendo respuestas como “¿programación funcional? ya uso maps y filters” o “bua, ya está aquí otro con las mónadas esas”. Al escuchar este tipo de comentarios he llegado a una conclusión: la gente tiene un conocimiento muy estereotipado de la programación funcional.

Mi objetivo en esta charla es resumir algunas de estas características más importantes y útiles de la programación funcional desde un punto de vista pragmático, con los beneficios que pueden tener a la hora de programar incluso en otros paradigmas. #FunctionalProgrammingForThePeople

https://t3chfest.uc3m.es/2018/programa/que-demonios-es-la-programacion-funcional/

Programación funcional en Python 101

Si lambdas, aplicación parcial, funciones de orden superior, recursividad por la derecha o izquierda, generadores o currificación te suenan a chino, esta es tu charla. Trataré de darle sentido a todos estos conceptos y a otros también relacionados con el paradigna de la programación funcional. Además, intentaré demostrar por qué una visión más funcional puede ayudarte a mejorar la calidad de tu código haciéndolo más legible, más mantenible y más eficiente.

https://t3chfest.uc3m.es/2018/programa/programacion-funcional-python-101/

Referencias

programacion/paradigmas.txt · Last modified: 2021/11/26 18:26 by jherrero