La programación en la década de 1960 tenía un gran problema: las computadoras aún no eran tan poderosas y de alguna manera necesitaban dividir las capacidades entre estructuras de datos y procedimientos.
Esto significaba que si tuvieras un gran conjunto de datos, no podrías hacer tanto con ellos sin llevar una computadora al límite. Por otro lado, si necesitara hacer muchas cosas, no podría usar demasiados datos o la computadora tardaría una eternidad.
Entonces Alan Kay se acercóD en 1966 o 1967 y teorizó que se podían usar miniordenadores encapsulados que no compartían sus datos, sino que se comunicaban a través de mensajes. De esta forma, los recursos informáticos podrían utilizarse de forma mucho más económica.
A pesar del ingenio de la idea, se necesitaría hasta 1981 hasta que la programación orientada a objetos llegó a la corriente principal. Desde entonces, sin embargo, no ha dejado de atraer tanto a desarrolladores de software nuevos como a experimentados. El mercado para los programadores orientados a objetos está tan ocupado como siempre.
Pero en los últimos años, el paradigma de una década ha recibido cada vez más crítica. ¿Podría ser que, cuatro décadas después de que la programación orientada a objetos llegara a las masas, la tecnología esté superando este paradigma?
¿Es tan estúpido acoplar funciones con datos?
La idea principal detrás de la programación orientada a objetos es tan simple como puede ser: intentas dividir un programa en partes que son tan poderosas como el todo. De ello se deduce que empareja piezas de datos y esas funciones que solo se utilizan en los datos en cuestión.
Tenga en cuenta que esto solo cubre la noción de encapsulación, es decir, los datos y las funciones que se encuentran dentro de un objeto son invisibles para el exterior. Uno solo puede interactuar con el contenido de un objeto a través de mensajes, típicamente llamados funciones getter y setter.
Lo que no está contenido en la idea inicial, pero se considera esencial para la programación orientada a objetos en la actualidad, son la herencia y el polimorfismo. La herencia básicamente significa que los desarrolladores pueden definir subclases que tienen todas las propiedades que tiene su clase principal. Esto no se introdujo en la programación orientada a objetos hasta 1976, una década después de su concepción.
El polimorfismo llegó a la programación orientada a objetos otra década después. En términos básicos, significa que un método o un objeto pueden servir como plantilla para otros. En cierto sentido, es una generalización de la herencia, porque no todas las propiedades del método u objeto original deben transmitirse a la nueva entidad; en su lugar, puede optar por anular las propiedades.
Lo que tiene de especial el polimorfismo es que incluso si dos entidades dependen entre sí en el código fuente, una entidad llamada funciona más como un complemento. Esto facilita la vida de los desarrolladores porque no tienen que preocuparse por las dependencias en tiempo de ejecución.
Vale la pena mencionar que la herencia y el polimorfismo no son exclusivos de la programación orientada a objetos. El diferenciador real es encapsular piezas de datos y los métodos que les pertenecen. En una época en la que los recursos informáticos eran mucho más escasos que en la actualidad, esta fue una idea genial.
Los cinco grandes problemas de la programación orientada a objetos
Una vez que la programación orientada a objetos llegó a las masas, transformó la forma en que los desarrolladores ven el código. Lo que prevaleció antes de la década de 1980, la programación procedimental, estaba muy orientada a las máquinas. Los desarrolladores necesitaban saber bastante sobre cómo funcionan las computadoras para escribir un buen código.
Al encapsular datos y métodos, la programación orientada a objetos hizo que el desarrollo de software estuviera más centrado en el ser humano. Coincide con la intuición humana de que el método drive()
pertenece al grupo de datos car
, pero no al grupo teddybear
.
Cuando apareció la herencia, eso también fue intuitivo. Tiene perfecto sentido que Hyundai
es un subgrupo de car
y comparte las mismas propiedades, pero PooTheBear
no.
Esto suena como una maquinaria poderosa. El problema, sin embargo, es que los programadores que solo conocen el código orientado a objetos forzarán esta forma de pensar en todo lo que hacen. Es como cuando la gente ve clavos en todas partes porque todo lo que tienen es un martillo. Como veremos a continuación, cuando su caja de herramientas contiene solo un martillo, eso puede provocar problemas fatales.
El problema de la jungla del gorila bananero
Imagina que estás configurando un nuevo programa y estás pensando en diseñar una nueva clase. Luego, piensa en una pequeña clase ordenada que ha creado para otro proyecto y se da cuenta de que sería perfecta para lo que está tratando de hacer actualmente.
¡No hay problema! Puede reutilizar la clase del proyecto anterior para el nuevo.
Excepto por el hecho de que esta clase puede ser en realidad una subclase de otra clase, por lo que ahora también debe incluir la clase principal. Entonces te das cuenta de que la clase padre también depende de otras clases y terminas incluyendo montones de código.
El creador de Erlang, Joe Armstrong, famoso proclamado:
El problema con los lenguajes orientados a objetos es que tienen todo este entorno implícito que llevan consigo. Querías un plátano, pero lo que obtuviste fue un gorila sosteniendo el plátano y toda la jungla.
Eso lo dice todo! Está bien reutilizar las clases; de hecho, puede ser una de las principales virtudes de la programación orientada a objetos.
Pero no lo lleve al extremo. A veces es mejor escribir una nueva clase en lugar de incluir una gran cantidad de dependencias por el bien de DRY (no lo repita).
El frágil problema de la clase base
Imagina que has reutilizado con éxito una clase de otro proyecto para tu nuevo código. ¿Qué pasa si cambia la clase base?
Puede dañar todo su código. Puede que ni siquiera lo hayas tocado. Pero un día tu proyecto funciona de maravilla, al día siguiente no porque alguien cambió un pequeño detalle en la clase base que termina siendo crucial para tu proyecto.
Cuanto más use la herencia, más mantenimiento tendrá que hacer. Entonces, aunque reutilizar código parece muy eficiente a corto plazo, puede resultar costoso a largo plazo.
El problema del diamante
La herencia es esta cosita linda en la que podemos tomar propiedades de una clase y transferirlas a otras. Pero, ¿y si desea mezclar las propiedades de dos clases diferentes?
Bueno, no puedes hacerlo. Al menos no de una manera elegante. Considere, por ejemplo, la clase Copier
. (Tomé prestado este ejemplo, así como algo de información sobre los problemas presentados aquí, de Charles Scalfani historia viral Adiós, Programación Orientada a Objetos.) Una fotocopiadora escanea el contenido de un documento y lo imprime en una hoja vacía. Entonces, ¿debería ser la subclase de Scanner
, o de Printer
?
Simplemente no hay una buena respuesta. Y aunque este problema no va a romper su código, aparece con la suficiente frecuencia como para ser frustrante.
El problema de la jerarquía
En el problema de los diamantes, la pregunta era qué clase Copier
es una subclase de. Pero te mentí, hay una buena solución. Dejar Copier
ser la clase padre, y Scanner
y Printer
ser subclases que solo hereden un subconjunto de las propiedades. ¡Problema fijo!
Está muy bien. Pero y si tu Copier
es solo en blanco y negro, y tu Printer
también puede manejar el color? No es Printer
en ese sentido una generalización de Copier
? Y si Printer
está conectado a WiFi, pero Copier
¿no es?
Cuantas más propiedades acumule en una clase, más difícil será establecer las jerarquías adecuadas. Realmente, se trata de grupos de propiedades, donde Copier
comparte algunas, pero no todas las propiedades de Printer
, y viceversa. Y si intentas poner eso en jerarquías y tienes un proyecto grande y complejo, esto podría llevarte a un desastre desordenado.
El problema de referencia
Podría decir, está bien, entonces solo haremos programación orientada a objetos sin jerarquías. En su lugar, podríamos usar grupos de propiedades y heredar, extender o anular propiedades según sea necesario. Claro, eso sería un poco complicado, pero sería una representación precisa del problema en cuestión.
Solo hay un problema. El objetivo de la encapsulación es mantener los datos a salvo unos de otros y, por lo tanto, hacer que la informática sea más eficiente. Esto no funciona sin jerarquías estrictas.
Considere lo que sucede si un objeto A
anula la jerarquía al interactuar con otro objeto B
. No importa la relación A
tiene con B
, excepto eso B
no es la clase padre directo. Luego A
debe contener una referencia privada a B
, porque de lo contrario, no podría interactuar.
Pero si A
contiene la información que los hijos de B
también tienen, entonces esa información se puede modificar en múltiples lugares. Por tanto, la información sobre B
ya no es seguro y la encapsulación está rota.
Aunque muchos programadores orientados a objetos crean programas con este tipo de arquitectura, esta no es programación orientada a objetos. Es solo un desastre.
El peligro del paradigma único
Lo que estos cinco problemas tienen en común es que implementan la herencia donde no es la mejor solución. Dado que la herencia ni siquiera se incluyó en la forma original de programación orientada a objetos, no llamaría a estos problemas inherentes a la orientación a objetos. Son solo ejemplos de un dogma llevado demasiado lejos.
Sin embargo, no solo la programación orientada a objetos puede exagerarse. En puro programación funcional, es extremadamente difícil procesar la entrada del usuario o imprimir mensajes en una pantalla. La programación orientada a objetos o procedimental es mucho mejor para estos propósitos.
Aún así, hay desarrolladores que intentan implementar estas cosas como funciones puras y amplían su código a docenas de líneas que nadie puede entender. Usando otro paradigma, podrían haber reducido fácilmente su código a un par de líneas legibles.
Los paradigmas se parecen un poco a las religiones. Son buenos con moderación; posiblemente, Jesús, Mohamed y Buda dijeron algunas cosas muy interesantes. Pero si los sigues hasta el último detalle, podrías terminar haciendo la vida de ti y de las personas que te rodean bastante miserables.
Lo mismo ocurre con los paradigmas de programación. No hay duda de que la programación funcional es ganando tracción, mientras que la programación orientada a objetos ha atraído a algunos dura crítica en los últimos años.
Tiene sentido informarse sobre los nuevos paradigmas de programación y utilizarlos cuando sea apropiado. Si la programación orientada a objetos es el martillo que hace que los desarrolladores vean clavos dondequiera que vayan, ¿es esa una razón para tirar el martillo por la ventana? No. Agrega un destornillador a su caja de herramientas, y tal vez un cuchillo o un par de tijeras, y elige su herramienta según el problema que tenga entre manos.
Tanto los programadores funcionales como los orientados a objetos, dejen de tratar sus paradigmas como una religión. Son herramientas y todas tienen su uso en alguna parte. Lo que use solo debe depender de los problemas que esté resolviendo.
La gran pregunta: ¿estamos en la cúspide de una nueva revolución?
Al final del día, el debate, ciertamente bastante acalorado, de la programación funcional frente a la programación orientada a objetos se reduce a esto: ¿podríamos estar llegando al final de la era de la programación orientada a objetos?
Cada vez surgen más problemas en los que la programación funcional suele ser la opción más eficiente. Piense en el análisis de datos, el aprendizaje automático y la programación paralela. Cuanto más se adentre en esos campos, más le encantará la programación funcional.
Pero si observa el status quo, hay una docena de ofertas para programadores orientados a objetos a una oferta para codificadores funcionales. Eso no significa que no obtendrá un trabajo si prefiere lo último; los desarrolladores funcionales todavía son bastante escasos en estos días.
El escenario más probable es que la programación orientada a objetos se mantenga durante una década más o menos. Claro, la vanguardia es funcional, pero eso no significa que debas deshacerte de la orientación a objetos todavía. Todavía es increíblemente bueno tenerlo en tu repertorio.
Así que no tire la programación orientada a objetos de su caja de herramientas en los próximos años. Pero asegúrese de que no sea la única herramienta que tiene.
Este artículo fue escrito por Rhea Moutafis y fue publicado originalmente en Hacia la ciencia de datos. Puedes leerlo aquí.