Inicio
Series Sobre mí Suscribirse
Los patrones de diseño apestan

Los patrones de diseño apestan

En la ingeniería de software, el término "patrón de diseño" (que, sinceramente, es un poco redundante — ¿acaso todos los patrones no son diseño?) se usa constantemente. Originalmente vino de la arquitectura — la arquitectura de verdad, con edificios y planos — no del software.

Pero en 1994, el mundo del software tuvo su propia versión cuando se publicó el ahora infame libro "Design Patterns" de Gamma, Helm, Johnson y Vlissides — también conocidos como la "Banda de los Cuatro" (Gang of Four, GoF). Presentaron 23 patrones canónicos como abstracciones de nivel más alto que las llamadas a funciones. Estos patrones estaban pensados como plantillas reutilizables, independientes del lenguaje, para resolver problemas recurrentes de diseño de software.

Suena bien, ¿no? Casi demasiado bien...

El problema es que los patrones de diseño pasaron de ser un vocabulario útil a algo casi dogmático. Se enseñan como soluciones universales, se aplican donde no hacen falta, y se tratan como una marca de buena ingeniería.

La realidad es esta: Los patrones de diseño apestan.

Sí, lo dije.

Los patrones de diseño están sobrevalorados, sobreutilizados, y muchas veces son directamente innecesarios.

Puede sonar duro, sobre todo para quienes tienen el libro de la Banda de los Cuatro en su mesita de noche, pero escúchame. La mayoría de las veces, los patrones de diseño no son más que parches feos para el hecho de que nuestros lenguajes de programación no son lo bastante potentes o flexibles como para expresar lo que realmente queremos.

Java y su romance con el boilerplate

Toma Java, por ejemplo (voy a criticarla bastante hoy, así que ponte cómodo). ¿Por dónde empezar? Java es el ejemplo perfecto de la "manía de los patrones de diseño". Cada proyecto parece una copia calcada del anterior porque a los desarrolladores de Java les enseñan a meter tantos patrones como sea posible.

Es el lenguaje que prácticamente forzó a los patrones de diseño a ser mainstream. ¿Por qué? Porque Java es verbosa, rígida, y le falta expresividad. Es como escribir una novela donde solo puedes usar palabras de tres sílabas — cada problema se siente diez veces más difícil de lo que debería.

¿Ah, estás trabajando en una simple app CRUD? Mejor mete un Factory, tal vez un Observer para esa notificación de cambio en la base de datos, y no te olvides del Singleton — porque, ya sabes, todos necesitamos un logger global, ¿no?

Patrón vs. característica del lenguaje

La razón de fondo por la que los patrones de diseño suelen ser basura es que la mayoría de las veces existen solo porque al lenguaje mismo le falta alguna capacidad. Básicamente estás haciendo parches para las limitaciones del lenguaje.

Toma el patrón Singleton como ejemplo. Lo has visto mil veces:

public class Logger {

    private static Logger instance;

    private Logger() {}

    public static Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }
}

Eso son como 15 líneas de código solo para decir "quiero una única instancia de esto". ¿Qué somos, cavernícolas? No deberíamos tener que escribir esto a mano. Un lenguaje moderno debería ofrecer construcciones para manejar esto elegantemente, pero no, Java no. En cambio, obtenemos toneladas de boilerplate y complejidad disfrazada de "buenas prácticas".

¿Quieres ver cómo lo maneja Scala?

object Logger

Eso es todo. Ese es el patrón Singleton completo. Listo.

No hay que lidiar con bloques estáticos, seguridad de hilos, ni tonterías de instanciación perezosa. Scala hace lo que Java debería haber hecho desde el principio: tratar esto como una característica básica del lenguaje, no como un patrón que hay que implementar manualmente. Java te obliga a este lío porque no tiene funciones de primera clase. Es culpa del lenguaje, no tuya, que estés escribiendo un patrón Strategy.

Los patrones de diseño no resuelven problemas de tu código; resuelven problemas de tu lenguaje.

¿Un patrón Factory? Eso es simplemente Java negándose a darte constructores decentes o una forma nativa de manejar la creación de objetos complejos. En lenguajes como Python, Ruby o Scala, rara vez necesitas un Factory. De hecho, la mayoría de los patrones de diseño de los que tanto hablan los desarrolladores de Java simplemente desaparecen en lenguajes más flexibles y expresivos.

Toma Python como ejemplo:

  • ¿Necesitas un Factory? Simplemente pasa una función o usa __init__ con inteligencia.
  • ¿Quieres un Singleton? Usa un módulo o una clase que inicializas una vez, y listo.
  • ¿Observer? Bueno, las funciones son ciudadanas de primera clase. Solo pásalas de un lado a otro.

El hecho es que, en un lenguaje suficientemente expresivo, los patrones se vuelven triviales o, mejor aún, simplemente no existen. Resuelves los problemas directamente, en vez de envolverlos en abstracciones que alguien más inventó hace 20 años en un lenguaje que no envejeció bien.

El culto a la sobreingeniería

El culto a la sobreingeniería

Los patrones de diseño también alimentan un problema más profundo en el mundo del software: la sobreingeniería. He visto a ingenieros junior (y a algunos senior, por desgracia) poner esa cara de asombro cuando escuchan "patrones de diseño" e intentar meter inmediatamente tantos como sea posible en su proyecto.

Están resolviendo problemas imaginarios.

Cuando esto pasa, el código deja de ser comprensible y se vuelve ilegible, frágil y excesivamente abstracto. Se convierte en un laberinto de interfaces, métodos factory, y convenciones de nombres raras que te hacen sentir como si estuvieras interpretando textos antiguos.

Los "buenos" patrones de diseño tienden a estar sobreingenierizados porque tienen que cubrir tantos casos de uso como sea posible. Pero el código sobreingenierizado tiene un costo: hay que leerlo, entender qué hace, y entender cómo funciona dentro del contexto de todo el sistema. Por lo tanto, como con cualquier otra técnica de desarrollo de software, hay que evaluar la técnica contra el costo de usarla, y decidir si los beneficios superan ese costo.

No todos los problemas necesitan un patrón de diseño. De hecho, la mayoría no lo necesita. A menudo, la solución más simple y directa es la correcta. Como regla general: si tu solución necesita un diagrama para explicarse, te pasaste de la raya.

Dónde los patrones son realmente útiles

El valor más honesto de los patrones: darle un nombre corto a una idea grande. En un equipo, es más fácil decir "eso es un facade" que explicar cada vez por qué escondemos tres clases detrás de un wrapper.

Eso es todo. Ese es el verdadero caso de uso.

Los patrones no están para enseñarte a escribir buen código. Están para hablar sobre código que ya está escrito. Para que puedas preguntar "¿qué es esta clase?" y escuchar "ah, eso es parte del mediator". No para comparar frenéticamente tu código con diagramas UML preguntándote "¡¿qué patrón aplico aquí?!"

Un desarrollador que entiende los conceptos subyacentes — separación de responsabilidades, encapsulación, composición sobre herencia — escribirá código limpio de forma natural, aunque nunca haya oído la palabra "Singleton". Los patrones son solo etiquetas para lo que los buenos desarrolladores ya saben hacer.

He trabajado en varias de las empresas tecnológicas más grandes. Nadie usa estos términos en el día a día, y jamás me preguntaron por ellos en una entrevista (para mí sería una señal de alarma).

La filosofía de Gosling contra la filosofía de Guido

Hay un gran momento de DHH que explica perfectamente por qué Java terminó así.

James Gosling, el diseñador de Java, tenía una visión oscura de los programadores. Su premisa: el desarrollador promedio se va a disparar en el pie si le das demasiado poder. Así que Java se construyó como una caja de arena — mantenla rígida, mantenla segura, no dejes que se hagan daño a sí mismos. Genial para una aseguradora de nivel medio escribiendo código que tiene que durar 20 años. No tan genial para la expresividad.

Guido van Rossum fue en la dirección opuesta con Python. Su premisa: el código se lee más de lo que se escribe, así que optimiza para la claridad y dale a los programadores herramientas de verdad. Funciones de primera clase, decoradores, gestores de contexto, duck typing — Python te da los bloques de construcción para resolver problemas directamente, en vez de canalizarlo todo a través de jerarquías de clases y ceremonias de interfaces.

Los patrones de diseño son una solución del mundo de Gosling. Existen porque el lenguaje no confía en que resuelvas el problema directamente. En un lenguaje del mundo de Guido, simplemente... lo resuelves.

Los patrones de diseño son reliquias de una época en la que los lenguajes no eran lo bastante expresivos. El hecho de que la mitad de los patrones del GoF desaparezcan en Python, Ruby o Scala te lo dice todo — nunca se trató de diseño. Se trataba de que el lenguaje no se interpusiera en tu camino.

Liked this? I publish one deep-dive every other Tuesday.

Join 4,000+ engineers. No sponsors.

Get the newsletter

¿Te gustó? Estas también te pueden interesar:

¿Quién es realmente responsable de los fracasos del equipo?

Los argumentos opcionales DEBEN usar palabras clave (Python 3)

Mi empatía es un detector de pegatinas