Referencia: Este artículo es una tradución al español de Why OO Sucks by Joe Armstrong.


(Nota: Esta es una copia del original que solía vivir en http://www.bluetail.com/~joe/vol1/v1_oo.html)

Introducción#

Cuando me presentaron por primera vez la idea de POO, era escéptico, pero no sabía por qué, simplemente me sentía “mal”. Después de su introducción, la POO se hizo muy popular (explicaré por qué más adelante) y criticar a la POO fue más bien como “jurar en la iglesia”. La orientación a objetos (OO) se convirtió en algo que todo lenguaje respetable debía tener.

Como Erlang se hizo popular, a menudo nos preguntaban “¿Es Erlang OO?” - bien, por supuesto que la respuesta verdadera era “No, por supuesto que no” - pero no lo dijimos en voz alta - así que inventamos una serie de formas ingeniosas de responder a la pregunta que estaban diseñadas para dar la impresión de que Erlang era una especie de OO (Si agitabas mucho las manos), pero no realmente (Si escuchabas lo que decíamos en realidad y leías la letra pequeña con cuidado).

En este punto, recuerdo el discurso de apertura del entonces jefe de IBM en Francia que se dirigió a la audiencia en la 7ª conferencia de programación de IEEE Logic en París. IBM Prolog había añadido un montón de extensiones OO, cuando se le preguntó por qué, él respondió:

“Nuestros clientes querían Prolog OO, así que hicimos Prolog OO”

Recuerdo que pensé: “qué simple, sin escrúpulos, sin reparos de conciencia, sin preguntar: ¿Es esto lo que hay que hacer?”…

Por qué OO apesta#

Mi principal objeción a la POO se remonta a las ideas básicas implicadas, esbozaré algunas de estas ideas y mis objeciones a ellas.

Objeción 1 - Las estructuras de datos y las funciones no deben estar vinculadas entre sí#

Los objetos enlazan funciones y estructuras de datos en unidades indivisibles. Yo creo que se trata de un error fundamental, ya que las funciones y las estructuras de datos pertenecen a mundos totalmente diferentes. ¿Por qué es esto así?

  • Las funciones hacen cosas. Tienen entradas y salidas. Las entradas y salidas son estructuras de datos que se modifican con las funciones. En la mayoría de los lenguajes de programación las funciones se construyen a partir de secuencias de imperativos: “Haz esto y luego aquello…” para entender las funciones hay que entender el orden en que se hacen las cosas (en los LPFs perezosos y en los lenguajes lógicos esta restricción es relajada).

  • Las estructuras de datos simplemente son eso. Ellos no hacen nada. Son intrínsecamente declarativos. “Entender” una estructura de datos es mucho más fácil que “entender” una función.

Las funciones se entienden como cajas negras que transforman las entradas en salidas. Si entiendo la entrada y la salida, entonces he entendido la función. Esto no quiere decir que yo podría haber escrito la función.

Por lo general, las funciones se “entienden” observando que ellos son las cosas en un sistema computacional cuyo trabajo es transferir estructuras de datos del tipo T1 a una estructura de datos del tipo T2.

Como las funciones y las estructuras de datos son tipos de animales completamente diferentes, es fundamentalmente incorrecto encerrarlos en la misma jaula.

Objeción 2 - Todo tiene que ser un objeto#

Considere el “tiempo”. En un lenguaje OO el “tiempo” tiene que ser un objeto. Pero en un lenguaje que no sea OO, el “tiempo” es una instancia de un tipo de dato. Por ejemplo, en Erlang hay muchas variedades de tiempo, que pueden especificarse de forma clara e inequívoca mediante declaraciones de tipo, como se indica a continuación:

1
2
3
4
5
6
7
8
9
-deftype day() = 1..31.
-deftype month() = 1..12.
-deftype year() = int().
-deftype hour() = 1..24.
-deftype minute() = 1..60.
-deftype second() = 1..60.
-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
-deftype hms() = {hms, hour(), min(), sec()}.
...

Tenga en cuenta que estas definiciones no pertenecen a ningún objeto en particular. Son ubicuas y las estructuras de datos que representan tiempos pueden ser manipuladas por cualquier función del sistema.

No hay métodos asociados.

Objeción 3 - En un LPOO, las definiciones de tipos de datos se extienden por todo el lugar#

En un LPOO, las definiciones de tipos de dato pertenecen a objetos. Así que no puedo encontrar toda la definición de tipos de dato en un solo lugar. En Erlang o C puedo definir todos mis tipos de datos en un solo archivo de inclusión o diccionario de datos. En un LPOO no puedo - las definiciones de tipos de dato están esparcidas por todas partes.

Permíteme dar un ejemplo de esto. Supongamos que quiero definir una estructura de datos ubicua. El tipo de dato ubicuo es un tipo de dato que ocurre “por todas partes” en un sistema.

Como los programadores de Lisp saben desde hace mucho tiempo, es mejor tener un pequeño número de tipos de dato ubicuos y un gran número de pequeñas funciones que trabajen en ellos, que tener un gran número de tipos de dato y un pequeño número de funciones que trabajen en ellos.

Una estructura de datos ubicua es algo así como una lista enlazada, una matriz, una tabla hash o un objeto más avanzado como la hora, fecha o nombre de archivo.

En un LPOO tengo que elegir algún objeto base en el que definiré la estructura de datos ubicua, todos los demás objetos que quieran utilizar esta estructura de datos deben heredar este objeto. Supongamos que ahora quiero crear un objeto “tiempo”, a dónde pertenece y en cual objeto…

Objeción 4 - Los objetos tienen estado privado#

El estado es la raíz de todo mal. En particular, deben evitarse las funciones con efectos secundarios.

Mientras que el estado en los lenguajes de programación es indeseable, en el mundo real el estado abunda. Por ejemplo, estoy muy interesado en el estado de mi cuenta bancaria y cuando deposito o retiro dinero de mi banco y espero que el estado de mi cuenta bancaria se actualice correctamente.

Teniendo en cuenta que el estado existe en el mundo real, ¿Qué facilidades debería proporcionar el lenguaje de programación para lidiar con el estado?

  • Los LPOO dicen “esconder el estado del programador”. Los estados están ocultos y visibles sólo a través de las funciones de acceso.
  • Los lenguajes de programación convencionales (C, Pascal) dicen que la visibilidad de las variables de estado está controlada por las reglas de alcance del lenguaje.
  • Los lenguajes declarativos puros dicen que no hay estado.

El estado global del sistema se lleva a cabo en todas las funciones y sale de todas ellas. Mecanismos como las mónadas (monads para los LPFs) y los DCGs (lenguajes lógicos) se utilizan para ocultar el estado al programador para que pueda programar “como si el estado no importara”, pero tener pleno acceso al estado del sistema debe ser necesario.

La opción “ocultar el estado al programador“ elegida por las LPOO es la peor opción posible. En lugar de revelar el estado y tratar de encontrar formas de minimizar las molestias del estado, lo ocultan.

  • Razón 1 - Se pensó que era fácil de aprender.
  • Razón 2 - Se pensó para facilitar la reutilización del código.
  • Razón 3 - Fue exagerado.
  • Razón 4 - Creó una nueva industria de software.

No veo evidencia de 1 y 2. Las razones 3 y 4 parecen ser la fuerza motriz detrás de la tecnología. Si una tecnología de lenguaje es tan mala que crea una nueva industria para resolver problemas de su propia creación, entonces debe ser una buena idea para los chicos que quieren ganar dinero.

Esta es la verdadera fuerza motriz detrás de los POOs.

Terminología utilizada#

  • POO/POOs: Programación orientada a objetos (OOP según sus siglas en inglés)
  • OO: Orientación a objetos o de diseño orientado a objetos (OO según sus siglas en inglés)
  • Prolog: Lenguaje de programación creado por IBM en los años noventa. Ver IBM Prolog.
  • Erlang: Es un lenguaje de programación creado por Joe Armstrong en los años ochenta. Ver la página oficial de Erlang.
  • LPFs: Lenguajes de programación funcional (Functional Programming Languages - FPLs según sus siglas en inglés)
  • LPOO: Lenguaje de programación orientado a objetos (OOPL según sus siglas en inglés).
  • Lisp: Es lenguaje de programación diseñado por John McCarthy a finales de los años cincuenta. Ver Lisp.