«La POO es un engaño»: por qué los programadores pierden la paciencia

«La POO es un engaño»: por qué los programadores pierden la paciencia

La frase «POO — es un engaño» suena atrevida y seduce por su provocación. Hay algo de verdad en ella: difícilmente encontrará un desarrollador que no haya tenido que romperse la cabeza con una jerarquía de clases enmarañada o lidiar con consecuencias inesperadas de la herencia. Sin embargo, tras el titular sensacionalista se oculta una realidad mucho más compleja. En este artículo desglosaremos de dónde provienen esas afirmaciones, en qué aspectos la programación orientada a objetos realmente tiene responsabilidad y por qué, a pesar de los críticos, sigue vigente. Lo haremos de forma clara y directa: sin burocracia, pero sin excesivos sentimentalismos.

De dónde vino la POO y por qué la llaman «la nueva clásica»

Para empezar conviene recordar que la abreviatura POO se consolidó en los años setenta gracias al lenguaje Smalltalk, donde por primera vez cobraron sentido los términos «objeto», «mensaje» e «incapsulación» en el sentido actual. Antes existían enfoques modulares, programación procedimental y mucho más. Pero la idea de modelar el software a imagen del mundo real (objetos con estado y comportamiento) pareció liberadora: todo prometía volverse más comprensible y natural.

El cambio de los noventa vino marcado por la adopción masiva de C++ y Java en la industria. Pareció entonces que cualquier proyecto serio debía ser «orientado a objetos», y a los estudiantes en las universidades les enseñaban a dibujar diagramas jerárquicos antes que a ejecutar «¡Hola, mundo!». En ese contexto nacieron los principios SOLID, los patrones de diseño de la Banda de los Cuatro y otras reliquias sin las cuales a veces daba miedo incluso hacer un commit.

Pero toda tecnología que llega a la corriente principal tarde o temprano sufre un retroceso del péndulo: cuanto mayores son las expectativas, mayor la desilusión si el ideal no se cumple. Hoy estamos cosechando los frutos de ese retorno.

Tesis principales de los «antiautoritarios»

«La POO complica en vez de simplificar»

Ejemplo clásico: una jerarquía de herencia de cinco niveles solo para poder sobreescribir un único método. En la teoría todo parece académico, pero en la práctica el desarrollador pasa horas intentando seguir la cadena de llamadas. Los datos están dispersos en distintos archivos, los campos son privados —no se puede acceder— y de composición no hay ni rastro.

La complejidad no solo se aprecia dentro del código: arquitectónicamente, los sistemas grandes con frecuencia se llenan de objetos todopoderosos que controlan la mitad de la aplicación. Reparar a ese monstruo en producción es una prueba de resistencia.

«La herencia rompe la encapsulación»

La teoría promete: hereda y reutiliza. En la práctica, cualquier detalle de la clase base se convierte en un punto común traicionero. Basta cambiar un pequeño método privado y ocho clases derivadas empiezan a comportarse de forma impredecible.

Los críticos señalan el principio composición en lugar de herencia. Pero si el lenguaje o la cultura del proyecto históricamente favorecen la herencia, una solución basada en composición suele parecer antinatural y los desarrolladores optan por el viejo y buen «extends» por rapidez.

«Los objetos imitan la realidad de forma demasiado literal»

¿Hace falta una función simple? «No, hermano, mételo en una clase». A muchos les parece ese enfoque una moda de la POO: como si estuviéramos amueblando habitaciones en lugar de escribir algoritmos. La simpatía formal de la estructura vence a las exigencias reales de la tarea.

De ahí nacen manifiestos como «¡Simplemente escriban funciones!» —sus autores están convencidos de que la lógica de negocio se vuelve más clara si reconocemos que no todo en programación necesita tener un método .toString().

«La POO dificulta el paralelismo»

El estado mutable es el mal raíz cuando se trata de cálculos paralelos o interfaces reactivas. Donde en funciones puras se comprueba la idempotencia, en POO basta con olvidar la sincronización para que aparezca un bloqueo mutuo o una condición de carrera.

Los partidarios de la programación funcional señalan estas dolencias, demostrando que la inmutabilidad y ciertas abstracciones escalan bien. El contraargumento de los defensores de la POO es que los objetos bien diseñados también pueden ser inmutables. Sin embargo, en la práctica se encuentran con menos frecuencia de la deseada.

Grano de verdad en la crítica

Es importante reconocer: muchos problemas están relacionados no con la idea de la POO en sí, sino con cómo la aplicamos. Con frecuencia los problemas surgen del entusiasmo desinformado: «Si la clase está disponible, ¿por qué no heredar?» —y el lío empieza. La ausencia de límites sólidos de módulo y de contratos de interacción conduce a la llamada «clase base frágil».

Además, durante mucho tiempo se vendió la POO como una bala de plata. Los gestores oyeron que «los objetos reflejan el mundo» y esperaron que la nueva paradigma redujera de inmediato los costes de mantenimiento. La realidad, por supuesto, castigó la credulidad.

Finalmente, algunos lenguajes (especialmente versiones antiguas de C++ y Java) fomentaban la herencia pública por defecto y carecían de lambdas cómodas, genéricos y otras herramientas que facilitan la composición. De ahí surgió mucho legado que somos nosotros quienes debemos mantener.

Dónde la POO realmente funciona

  • Modelado de dominios complejos. En fintech, la industria del juego o sistemas CAD, los objetos permiten mantener la lógica junto a los datos en lugar de dispersarla entre procedimientos y arrays.
  • Encapsulación de invariantes. Si una clase que representa fibra de carbono debe conservarse a una temperatura concreta, es conveniente esconder las comprobaciones en sus métodos. La documentación vive junto al código y los errores se bloquean a nivel de API.
  • Frameworks extensibles. Ecosistemas populares (Spring, Unity, Unreal Engine) usan POO para permitir puntos de extensión mediante herencia o inyección de dependencias. Sin objetos, esa interfaz sería engorrosa.

Cabe señalar: la palabra clave aquí es uso racional. Nadie obliga a convertirlo todo en una jerarquía. Pero a veces el enfoque orientado a objetos reduce mucho la carga cognitiva, sobre todo cuando es necesario ocultar mecánicas complejas tras una fachada simple.

Alternativas: funcional, procedural, DOD y ECS

Por supuesto, mientras unos esperaban la salvación en los objetos, otros desarrollaban alternativas. Veamos tres vectores populares.

Programación funcional (PF)

Su bandera principal son las funciones puras y las estructuras de datos inmutables. De ahí derivan la repetibilidad, el refactor sin miedo y las pruebas ligeras. Lenguajes como Haskell o Elixir ponen este enfoque en primer plano, y para muchos desarrolladores es un alivio tras los infinitos setters.

Pero la PF tampoco es mágica. Para quienes piensan en términos de objetos, mónadas, functores y abstracciones categóricas suenan intimidantes. Además, la inmutabilidad estricta a veces acarrea sobrecostes de memoria o requerimientos de optimización a nivel de compilador.

Estilo procedimental

El buen y viejo C sigue presente en ciencia y sistemas operativos. Cuando hace falta código rápido, compacto y predecible sin capas de abstracción, los procedimientos y las estructuras de datos son la salvación. Pero a medida que el producto crece hay que organizarlos con cuidado: la arquitectura por capas sigue siendo válida incluso sin clases.

Data-Oriented Design (DOD) y Entity-Component-System (ECS)

Muy populares en desarrollo de videojuegos. En lugar de objetos «pesados» se usan estructuras de datos simples y sistemas que operan sobre ellas. Esa separación acelera operaciones amistosas con la caché y mejora el escalado en memoria. Unity y Unreal incorporan enfoques ECS, demostrando que se puede prescindir de la herencia clásica sin dejar de pensar de forma «orientada a objetos» en un sentido amplio.

A menudo se presenta como «la muerte de la POO», pero en realidad es solo otra evolución de la encapsulación correcta de lo que haga falta —a veces como estructura de datos más sistema, a veces como clase.

El compromiso moderno: enfoque multi-paradigma

Hoy pocos predican la ortodoxia pura. La mayoría de los lenguajes populares (Kotlin, Swift, C#, Python) permiten combinar objetos, funciones de orden superior y genéricos. Los desarrolladores usan la herramienta adecuada donde ayuda a expresar la idea, en lugar de forzar la idea a encajar en la herramienta.

Ejemplo ilustrativo: en Kotlin se puede declarar una data class (para la encapsulación) y aplicar de inmediato una extensión —una función que parece método pero no rompe la estructura. En Python las funciones sencillas conviven con @dataclass, y en TypeScript las interfaces conviven con tipos algebraicos provenientes de la PF. Todo esto no demuestra que la POO haya muerto, sino que confirma una vieja verdad: a un buen desarrollador le basta con más de una sola paradigma.

Por qué la frase «POO — es un engaño» es peligrosa y útil a la vez

Por un lado desafía el statu quo y obliga a replantear soluciones habituales. Derribar un ídolo es un ritual útil que protege contra la adoración ciega de patrones antiguos. Pero por otro lado, negar categóricamente cualquier herramienta conduce a una forma de fanatismo técnico. Los principiantes leen «POO — es mala», deciden que nunca deben usar clases y terminan duplicando código con funciones sin darse cuenta de que están reinventando un objeto en algún JSON.

El sentido común indica: todo extremo es dañino. La estrategia de «la llamo engaño para provocar» sirve para sacudir a la audiencia, pero no para construir prácticas de ingeniería sostenibles.

Recomendaciones prácticas para desarrolladores

  1. Empieza por los datos. Formula qué entidades existen en el dominio antes de multiplicar clases o funciones. Con frecuencia resulta que la mitad de los «futuros objetos» son solo datos sin comportamiento.
  2. Revisa los límites de responsabilidad. Si una clase cumple más de un papel, lo más probable es que se convierta en un objeto todopoderoso. Es mejor extraer un servicio o aplicar composición.
  3. Sé honesto con la herencia. Hereda solo cuando puedas decir «A — es B». Cuando surge «A tiene B», recurre a la composición.
  4. Aprende lenguajes de otras paradigmas. Un par de tardes con Elm o F# ejercitarán la mente más que una semana leyendo sobre patrones de diseño.
  5. Escribe pruebas. Independientemente del enfoque, las pruebas unitarias detectan rápido la fragilidad del diseño y muestran dónde has exagerado con la encapsulación.
  6. No temas refactorizar. El código es un organismo vivo. Si ayer una clase salvó la situación y hoy estorba, divídela o saca la lógica afuera. Es normal.
  7. Prioriza la legibilidad sobre la doctrina. Si a un colega le lleva diez minutos entender tres líneas de tu solución «puramente orientada a objetos», quizá sea mejor escribir una función normal.

Conclusión: ¿vale la pena «enterrar» la POO?

La programación orientada a objetos no es una religión ni un fraude, sino simplemente una herramienta. Sí, puede engañar expectativas si se aplica a ciegas. Pero cualquier otro enfoque también puede decepcionar si se olvida el contexto de la tarea, el sentido común y las limitaciones del entorno.

La frase «POO — es un engaño» tiene valor precisamente como provocación. Recuerda que no existe una píldora mágica y que el código no se volverá perfecto pegándole patrones por todas partes. Lo que realmente funciona es la curiosidad, la disposición a experimentar y la valentía de desechar lo innecesario. En lugar de erigir otro ídolo o derribar el anterior, acordemos esto: que la herramienta sirva a la tarea y no la tarea a la herramienta. Entonces objetos, funciones y estructuras de datos puras encontrarán su lugar legítimo en el código —sin engaños y con utilidad.

Alt text