• facebook
  • flickr
  • google
  • instagram
  • lastfm
  • linkedin
  • spotify
  • twitter
  • Goodreads
  • GitHub
  • juanignaciosl.github.io
  • Medium
La Programación Orientada al Objeto debe morir

La Programación Orientada al Objeto debe morir

La Programación Orientada al Objeto debe morir” es el llamativo título de una mesa redonda a la que he sido invitado por Pablo Santos Luaces, y con tal tema y tal anfitrión no podía decir que no. Pero vaya por delante que mi CV es infinitamente más modesto que el de los otros invitados, los auténticos expertos de la jornada. Estas son mis notas preparatorias, y al final, el vídeo de la jornada.

Empezaré diciendo que lo primero que se me vino a la cabeza es algo semejante a lo que dijo el maestro Acero al comentar la charla en Twitter:

Screen Shot 2014-11-27 at 17.38.16

… pero la respuesta de Pablo tampoco le va a la zaga. No es menos cierto que queremos herramientas y procesos lo menos susceptibles al fallo humano posibles, así que el ejercicio me parece interesante aunque el culpable (probablemente) no sea la OO, de la que incluso la definición es un objeto de discusión. Dicho esto…

En el propio planteamiento se dejan abiertas unas cuantas preguntas interesantes de las que daré mi opinión, personal e intransferible:

¿por qué hay una tendencia tan acusada de escribir código complicadísimo y auténticos castillos que acaban siendo innecesarios?

Creo que esto puede tener su origen en que a menudo se nos enseña (tanto durante los estudios como en las jerarquías del trabajo diario) a desarrollar con “Big Design Up Front” (no sé cómo traducir la idea del BDUF), lo cual lleva a matar moscas a cañonazos. En otras ocasiones, aunque no estemos en un desarrollo en cascada (más o menos disfrazado) trabajamos de forma iterativa, que va poniendo trozos del castillo poco a poco, con lo que se puede perder la idea global. O, incluso, haciendo desarrollo incremental, que creo que es la forma más adecuada, no aprovechamos el conocimiento adquirido y, en lugar de refactorizar y rediseñar, continuamos en una patada hacia delante.

Incremental vs. Iterativo

También podemos analizar el motivo desde un punto de vista conductista: ¿”castigamos” la complejidad? En el corto alcance, ¿revisamos el diseño/código que proponemos/hacemos y lo refinamos para simplificar? A menudo uno mismo está tan cerca del problema o cede a la urgencia y, aún teniendo ese conocimiento, no lo aplica correctamente. En el largo alcance, ¿reconstruimos las partes de la aplicación que se convierten en problemáticas? Ya sea por errores iniciales o por cambios en el entorno una solución adoptada puede resultar inadecuada. Y, hablando de refuerzo positivo, ¿”recompensamos” la simplicidad? Históricamente incluso hay metodologías que miden costes (y, con ello, productividad) en base a líneas de código, por no hablar de empresas que cobran por la resolución de sus propios bugs (directamente o disfrazados en bolsas de mantenimiento correctivo)…

Por otra parte, a veces se intenta explicar la orientación al objeto con la metáfora del mundo real (quizá por simplicidad, quizá por su origen en la simulación), lo cual no tiene por qué ser correcto, ya que se centra en los detalles en lugar de en la esencia y la abstracción. Un ejemplo de esto es el problema de la cafetera de Robert C. Martin.

Probablemente la OO no está detrás de estos problemas, que pueden ser más relevantes ya que afectan al proceso y son neutros respecto al paradigma. Hablando en concreto de la orientación al objeto… ¿Cuánto vigilamos los smells de que lo que estamos haciendo es “buena OO”? Al hilo de esto Javier Garzas, uno de los auténticos expertos convocados, recomienda el “Object Oriented Design Heuristics”, de Riel, que puede ser de gran utilidad para educar esos mecanismos de “detección de que algo estamos haciendo mal”.

¿Impide la OO construir castillos? Claramente no porque sucede (al menos si hablamos de los lenguajes que usamos a diario). ¿Contribuye a no construirlos? Si consideramos la sobrecarga (tanto mental como en ejecución) que supone, por ejemplo, un elevado número de clases o de dependencias, quizá sí. Pero por otro lado, a través de la ocultación de información, a veces hace fácil gestionar estos “castillos”, y es fácil confundir esto con abstracción, generalización…

Cuando aprendemos orientación a objeto asentamos una serie de conceptos de “lo que está bien” y “lo que está mal” que luego se tardan mucho en superar. Un ejemplo es el abuso de la herencia: usar herencia de forma extensa es un buen signo para demostrar que dominas OOP cuando cursas las asignaturas correspondientes, sin embargo lo que sirve para aprobar un examen (lógico, por otro lado, para demostrar que se conocen las técnicas esenciales con casos de laboratorio) no tiene por qué aplicar en el mundo real

Estoy en profundo desacuerdo de lo que hay detrás de este párrafo, y que se hace más evidente leyéndolo al revés. Aquí parece que se dice, no sé si con ironía, que en el mundo real no aplican ciertas cosas que sirven para aprobar exámenes. Como el mundo real no “está mal”, por definición, lo que están mal son los exámenes. Se pone como ejemplo el abuso de la herencia, cuando incluso en “el GoF” se recomienda “Favorecer la composición de objetos sobre la herencia de clases”. Este es un claro ejemplo de “mala OO”. ¿Es la herencia dañina? Los diseñadores de Go parece que opinan que es, como mínimo, innecesaria

¿Se aprendería mejor y más rápido si no nos formásemos directamente en orientación a objeto?

Yo creo que el problema no es la formación en OO supuestamente temprana, sino la no formación en otros aspectos:

  • Construye top-bottom, no bottom-up.
  • No escribas código que resuelva problemas que no tienes.
  • No tengas miedo de borrar código innecesario.
  • Refactoriza.
  • Vigila los smells.

Problemas relacionados

No directamente atribuido a la orientación al objeto pero sí muy vinculado a él hay otras cuestiones que no podemos ignorar… ¿Cuánto estamos atribuyendo a la OO y cuánto a las herramientas concretas? En mi caso, ya con más distancia, podría hablar de Java y, sobre todo, de JEE. ¿Es orientada al objeto la arquitectura por capas que se propone, y que deja a las entidades como meros POJOs sin lógica de negocio (pero sí con información de persistencia), o que premia el uso train wrecks vía getters y setters, exponiendo el estado de los objetos (sí, JSF, te miro a ti)? ¿Es orientado al objeto el API de colecciones, que exige el uso de librerías de estáticos constantemente? ¿Es orientado al objeto un lenguaje en el que tienes que convivir constantemente con referencias a null?

Está claro que los lenguajes, frameworks y librerías que utilizamos nos condicionan, pero no podemos identificar sus problemas con la OO. Otra cuestión es si el valor que proporcionan compensa hacer ciertas concesiones…

Problemas que sí son (aparentemente*) propios

Digo aparentemente* porque, en mayor o menor medida, podríamos evitarlos o atenuando prohibiendo características de nuestros lenguajes pero que suceden tan habitualmente que parecen intrínsecos (al paradigma o a la naturaleza humana :) ).

  • Ocultar información: cada vez estoy más convencido del valor de la explicitud. Uno de los valores de la orientación al objeto es la ocultación de la información, y va en contra de esa característica que me gusta. Extraído de ese mismo artículo, “is the principle of segregation of the design decisions in a computer program that are most likely to change”. Las negritas son mías, creo que podéis anticipar por dónde voy: si una de las esencias de nuestro paradigma depende de la probabilidad de un suceso, deberíamos evaluar constantemente las premisas iniciales y cambiar el código en función de ello (refactorizar, como comentaba antes). ¿Cuántas veces un cambio en un objeto se propaga por los demás? Hay situaciones que de forma natural no encajan, como un sistema de logging.
  • Pablo decía en la conversación original que “En C#: típica “property” que cambia estado de la clase o acaba haciendo llamadas pesadas. Una property no debe cambiar jamás un estado, solamente devolver o fijar valores directamente en la clase”. Un método debería consultar o hacer, no ambas, para empezar. Esas properties se refieren tradicionalmente a “entidades”. ¿Debe una entidad tener una dependencia hacia un sistema externo que haga una llamada pesada? Al hablar de entidades la respuesta es clara. Pero… ¿Queremos ignorar que una llamada a un método puede ocultar una llamada bloqueante a un sistema externo? Una vez inyectásemos esa dependencia vía constructor a un objeto, la única garantía que tenemos es que efectivamente no tenemos garantías. Y sí, de nuevo eso podría ser una “mala OO”, pero por este mismo argumento deberíamos prohibir las llamadas estáticas.

Alternativas

  • Comenzando por una no-solución, buena parte de nuestros problemas se solucionarían siendo más rigurosos en la vigilancia de características de la “buena OO”.
  • En la línea de lo anterior, pero más instrumentalizable, prohibir características indeseables de nuestras plataformas (uso de estáticos, inyección de dependencias fuera de constructores, etc.).
  • Domain Driven Design y arquitecturas hexagonales, del que a menudo se dice que es “OO hecho correctamente”.
  • Mezclar orientación al objeto con funcional, como propone Scala (sin que esto excluya el punto anterior). Durante la charla, José Daniel García citó el término FUNGENOOP, podrían ir por aquí los tiros…

LA CHARLA

Tenéis aquí el vídeo de la charla:

Mis comentarios:

  • Gracias (de nuevo) por invitarme. Sentarte en una mesa en la que hay veteranos expertos de verdad como José Daniel es un honor.
  • No dio para mucho el debate, la verdad. Apenas dio tiempo a que diésemos un par de opiniones y, además, nos acabamos yendo bastante del tema :(
  • Parece que todos estamos de acuerdo en que el principal problema, si lo hay, no es la OO sino el uso que damos de él.
  • También queda claro que no es fácil “saber lo correcto” (incluyo tanto saber como lo correcto en las comillas intencionadamente).

 

4 Comentarios

  1. El Poza · junio 22, 2015

    Lo primero que he de comentar es que hace algunos años ha aparecido una especie de postureo tecnológico en la industria del software, apareciendo por todos lados gente que defiende que casi todo lo actual está desfasado y propone nuevas fórmulas completamente “rompedoras”, en algunos casos con razonamientos acertados y en otros cuanto menos dudosos.

    En muchos casos he observado que algunos de estos casos se dan en informáticos teóricos, gente que hace eones que no tira una línea de código en un trabajo real con fechas de entrega reales y con requerimientos reales.

    Creo que hablas muy gratuitamente de la ocultación de información en un objeto y de reescribir código. En una aplicación con OO bien diseñada, la ocultación de información es vital para evitar que un cambio te obligue a reescribir (y testear) una cantidad innumerable de clases lo que supone un ahorro de tiempo y esfuerzo notable. Esto es algo básico, algo que cualquier desarrollador capacitado conoce de sobra (existen otros elementos de la OO que ayudan a esto mismo y ofrecen numerosas ventajas más).

    También me encanta lo de no intentar solucionar problemas que no se tienen. La mantenibilidad y extensibilidad del código, algo imprescindible en cualquier proceso de desarrollo de software hacen precisamente eso, porque bien aplicados nos ahorran esfuerzo y tiempo en una primera codificación y vuelven a hacerlo en futuros cambios. Reescribir código es altamente costoso, de ahí que la reutilización sea otro concepto básico en el desarrollo de software, da igual el lenguaje y el paradigma, sobretodo a la hora de evaluar el impacto en el resto de la aplicación y de testear.

    Los problemas que comentas al principio, no tienen nada que ver con la OO ni con Java (que como todo no es perfecto y tiene sus fallos), pero en todo esto veo un problema básico:
    – Hay gente que cree que sabe lo que es la OO y como desarrollar utilizándola cuando no es así.
    – Hay gente que es obvio que ha leido muchos libros y seguido muchos blogs y tienen un conocimiento teórico extenso pero con una experiencia escasa.
    – Y sobretodo hay gente que porque algo funcione ya está bien hecho.

    Para muestra un botón, concoí a un experto que programaba en Python, fiel defensor de la agilidad de desarrollo que permitían los lenguajes no tipados, al que pregunté como solucionaba ciertos problemas de los lenguajes no tipados que me había encontrado en lenguajes de ese tipo (conocer los tipos de los parámetros y variables para saber la información que albergan, saber que campos posee un objeto para ver que información puedo recuperar etc… teniendo en cuenta que alguien que no ha hecho la aplicación tiene que poder modificarla en un futuro), y a pesar de ser un experto y defensor de los lenguajes no tipados, y aunque estoy convencido que estos problemas deben tener solución ya que si no el código es inmantenible. No supo darme una respuesta. Resumen, era “experto” sin experiencia.

  2. juanignaciosl · junio 22, 2015

    Antes de nada, ¡gracias por molestarte en escribir una réplica extensa e interesante! Te respondo a alguna cuestión que planteas:

    “Creo que hablas muy gratuitamente de la ocultación de información en un objeto y de reescribir código”: no pretendí hablar “muy gratuitamente”, y opino exactamente como dices en ese párrafo, así que no me expliqué con claridad. Lo que quise decir no es que “la ocultación de información” sea mala, sino que tanto ocultación como explicitud son técnicas que proporcionan valor pero son contrapuestas, así que hay que buscar un compromiso. Por ponerte un ejemplo, estos días estoy rehaciendo parte de la lógica de creación de usuarios de CartoDB. La creación es compleja, porque intervienen sistemas externos y elementos costosos de base de datos (no es un mero insert en nuestro caso) y sucede que la creación original estaba oculta tras manejadores de Rails (before_save y similares). En el nuevo código he optado por hacer una clase UserCreation que modela el proceso de creación mediante una máquina de estados. Sigue ocultando buena parte del proceso, pero hace otra observable desde fuera, entre otras ventajas. Sin duda la ocultación de información es un valor, pero creo que no es un valor absoluto. Espero que haya quedado más claro mi punto: no es que la ocultación sea mala o un error, pero sí es una característica intrínseca a la OO que no hay que tomar de forma absoluta.

    La segunda que cito, ciertamente es algo que se puede atacar a nivel de lenguaje, quizá generalizarlo a toda la OO es incorrecto, pero ocurre esencialmente en cualquier lenguaje que conozca.

    Y totalmente de acuerdo en el listado de problemas básicos, que se resumen en que utilizamos mal la OO.

  3. El Poza · junio 22, 2015

    Agradezco tus aclaraciones, y tras releer mi post pedirte disculpas por el tono del mismo, venía de un debate acalorado y las formas no han sido las mejores.

    Un saludo.

  4. juanignaciosl · junio 22, 2015

    Nada que objetar al tono, se agradece la participación de hecho :-)

¿Me dejas una respuesta?