Módulo 1: Qué son de verdad los patrones
4. De dónde salen los patrones (y por qué no se inventan)
Descripción
Al terminar esta lección vas a saber de dónde salió la idea de "patrón" —que empieza, curiosamente, en la arquitectura de edificios y no en la programación—, cómo llegó al software y quiénes le pusieron los nombres que hoy usamos. Pero el objetivo no es la anécdota histórica. El objetivo es que entiendas una distinción que cambia por completo cómo se usan: los patrones se descubrieron, no se diseñaron. Nadie se sentó a inventar el Observer. Alguien notó que la misma estructura aparecía una y otra vez en código que funcionaba bien, la describió y le puso nombre.
Esto importa por una razón muy práctica, y es la que da título a la lección. Si un patrón es un descubrimiento —el registro de una solución que la gente ya estaba usando porque el problema se lo exigía—, entonces aplicar un patrón sin tener el problema es tener una solución sin problema. No es un uso creativo del patrón: es un error de categoría, como llevar paraguas bajo techo. La mayoría del código sobre-diseñado que existe en el mundo nace exactamente de ahí: de tratar los patrones como si fueran invenciones disponibles para usar en lugar de descripciones de algo que ocurre cuando ciertas condiciones se dan.
Vas a llevarte también dos cosas incómodas y útiles. La primera es que el catálogo original tiene edad —treinta y tantos años— y que varios de sus patrones existen porque a los lenguajes de esa época les faltaban cosas que hoy vienen de fábrica. La segunda es que los propios autores del libro han dicho públicamente que cambiarían partes de él. Saber eso te vacuna contra tratar el catálogo como escritura sagrada, que es la actitud que produce más daño en este tema.
Conexión con el módulo: la lección 2 dijo que un patrón es una tripleta problema-solución-consecuencias, y la lección 3 se ocupó del nombre. Esta lección explica por qué esa tripleta existe y por qué no se puede fabricar una nueva por decreto. La lección 5 va a convertir esto en técnica: si los patrones se descubren, entonces reconocerlos en código ajeno consiste en buscar el problema, no la forma. La lección 6 va a dibujar el mapa del catálogo con esta perspectiva encima —cuáles envejecieron bien y cuáles no—. Y la lección 7, sobre cómo no estudiar patrones, es en buena medida el corolario práctico de esta.
Los senderos que hace la gente
Camina por un parque grande y vas a ver dos tipos de camino. Están los que alguien diseñó: rectos, pavimentados, con sus curvas elegantes en el plano. Y están los otros: esas franjas de tierra pelada que atraviesan el pasto en diagonal, donde la gente decidió que el camino oficial daba demasiada vuelta.
Esos senderos de tierra tienen nombre —se les llama caminos de deseo— y son fascinantes por lo que significan. Nadie los diseñó. Nadie convocó una reunión. Aparecieron porque miles de personas, cada una resolviendo su propio problema —"quiero llegar a la esquina y el camino da vuelta"—, tomaron la misma decisión de forma independiente. El sendero es el rastro acumulado de esas decisiones. Es evidencia física de un problema real.
Ahora, la parte interesante. Hay universidades y parques donde los urbanistas hacen algo muy inteligente: esperan. Dejan pasar el primer año sin pavimentar todos los caminos, miran dónde pisa la gente, y después pavimentan los senderos que ya existen. No están diseñando el camino: están reconociendo uno y dándole forma. El sendero ya funcionaba; lo que aportan es el pavimento, el drenaje y la iluminación.
Un patrón de diseño es un sendero pavimentado. Alguien notó que en muchos proyectos distintos, gente que no se conocía entre sí había llegado a la misma solución estructural para el mismo tipo de problema. Ese "llegar a lo mismo por separado" es la señal. El patrón no inventa la solución: la reconoce, la describe con cuidado, le pone nombre y anota sus consecuencias.
Y de aquí sale la advertencia central de la lección, que es tan visual que casi no hace falta explicarla: pavimentar un sendero donde nadie camina no crea un camino. Crea una cicatriz de concreto en medio del pasto. Se ve profesional, costó dinero, y no sirve para nada —peor: ahora hay que mantenerla, y le estorba a quien corta el pasto—.
Eso es exactamente el rincón plugins/ de Boletia. Alguien pavimentó un sendero de seis carriles para un lugar al que nadie iba. Dos años después sigue ahí, nadie camina por él, y todo el mundo lo rodea con cuidado.
Ejemplo trabajado: un patrón naciendo en Boletia
Vamos a ver el descubrimiento ocurriendo. No te voy a mostrar un patrón aplicado, sino el momento anterior: el sendero formándose.
Boletia, en su primer año, tenía un solo proveedor de pago. El cobro se veía así:
# Archivo: checkout/checkout.py — versión del primer año.
# Un solo proveedor. No hay nada que decidir.
def charge(order):
client = StripeClient(api_key=settings.STRIPE_KEY)
# Stripe trabaja en centavos, por eso multiplicamos y convertimos a entero.
return client.create_charge(amount=int(order.total * 100), currency="MXN")
Aquí no hay patrón, y está bien que no lo haya. Hay un problema —cobrar— y una solución directa. Meter una interfaz aquí sería pavimento sobre pasto virgen.
Llega el segundo proveedor, porque muchos clientes en la región no usan tarjeta y piden transferencia. La reacción natural, la que tomaría cualquiera con prisa, es un condicional:
# Segundo año. Dos proveedores. El if más honesto del mundo.
def charge(order, provider_name):
if provider_name == "stripe":
client = StripeClient(api_key=settings.STRIPE_KEY)
return client.create_charge(amount=int(order.total * 100), currency="MXN")
else:
client = MercadoPagoClient(token=settings.MP_TOKEN)
# Este quiere el monto como float y el concepto por separado.
return client.pay(order.total, description=f"Boletia #{order.id}")
Sigue sin haber patrón, y sigue estando bien. Dos ramas, un archivo, se lee de corrido. Cualquiera que insista en abstraer aquí está adelantándose al problema —el módulo 2 le va a poner nombre a ese apuro—.
Ahora pasan tres cosas a lo largo del tercer año.
Primera: entra el tercer proveedor, el pago en efectivo con referencia en tienda. El if se vuelve if/elif/elif/else.
Segunda: aparece una necesidad nueva. El equipo de operaciones quiere reintentar cobros fallidos desde un script nocturno. Ese script necesita cobrar, así que alguien copia el condicional a otro archivo. Ahora la misma decisión vive en dos lugares.
Tercera: llega el módulo de reembolsos. Cada proveedor devuelve dinero de forma distinta. Alguien escribe un refund con el mismo condicional otra vez, en un tercer archivo.
En este punto, mira el paisaje sin pensar en patrones:
checkout.py → if stripe / elif mercadopago / elif cash (cobrar)
retry_job.py → if stripe / elif mercadopago / elif cash (cobrar de nuevo)
refunds.py → if stripe / elif mercadopago / elif cash (devolver)
Tres archivos preguntan exactamente lo mismo. Y cuando entre el cuarto proveedor, alguien va a tener que acordarse de los tres —y va a olvidarse de uno, porque así funcionan las personas—. Eso ya no es un if: es un sendero pisado.
Fíjate en lo que ocurre naturalmente en un equipo cuando llega a este punto. Nadie dice "apliquemos un patrón". Alguien dice algo mucho más simple:
"Oigan, ¿y si cada proveedor tuviera su propio archivo con
chargeyrefund, y estos tres nada más pidieran el que toca?"
Y ahí está. Esa frase, dicha en una junta cualquiera, en cualquier empresa del mundo, es un patrón siendo redescubierto. No se necesitó el libro. El problema empujó hacia la solución. Lo que el libro aporta es que esa solución ya tiene nombre —es una familia de objetos intercambiables con una interfaz común, o sea el terreno de Strategy y Factory, que veremos en los módulos 3 y 4— y, sobre todo, que ya tiene sus consecuencias documentadas por gente que la usó antes que tú.
Qué esperar de este ejemplo. Tres cosas.
La primera: hubo tres etapas donde la ausencia de patrón era la decisión correcta. Un proveedor: nada. Dos proveedores: un if. Es solo en la tercera etapa —tres variantes, y la misma decisión repetida en tres lugares— cuando la estructura empieza a ganarse su lugar. Ese "cuándo" no es arbitrario y tiene una regla asociada que verás en el módulo 2, la regla de tres.
La segunda: el patrón emergió del problema, no al revés. Nadie llegó con la solución buscando dónde ponerla. La forma correcta de trabajar es esta, y es la que la lección 7 va a defender de frente.
Y la tercera, la más importante para esta lección: si hubieras empezado por el patrón, en el primer año, con un solo proveedor, habrías escrito exactamente el rincón plugins/. Una interfaz, una implementación, un mecanismo de selección, y ningún problema resuelto. La diferencia entre el payments/ de Boletia —que está bien— y su plugins/ —que no— no es la estructura: las dos se parecen bastante. La diferencia es que una llegó después del problema y la otra llegó antes.
La historia, en corto
Vale la pena conocerla porque explica varias rarezas del catálogo.
Un arquitecto de edificios, en los años setenta
La palabra "patrón", en el sentido que la usamos, la acuñó Christopher Alexander, un arquitecto —de edificios, de verdad— que estaba incómodo con algo de su oficio. Alexander observaba que los pueblos viejos, construidos sin arquitectos, sin planos y sin escuelas, resultaban más agradables de habitar que muchos edificios modernos diseñados por profesionales. Y se preguntó por qué.
Su respuesta fue que esos lugares acumulaban, a lo largo de generaciones, un conocimiento no escrito sobre qué funciona: qué ancho tiene que tener una banqueta para que la gente se detenga a conversar, por qué una ventana con un asiento debajo se usa y una sin él no, por qué un cuarto con luz de dos lados se siente distinto a uno con luz de un lado. Nadie lo había diseñado. Se había descubierto por acumulación de intentos.
Alexander se propuso escribir ese conocimiento. En 1977 publicó, con Sara Ishikawa y Murray Silverstein, A Pattern Language, un libro con 253 patrones que van desde la escala de una región entera hasta el detalle de un alféizar. Y en 1979, The Timeless Way of Building, donde explica la idea detrás.
Dos cosas de Alexander se heredaron al software y conviene subrayarlas.
La primera es su definición, que sigue siendo la mejor que existe: cada patrón describe un problema que ocurre una y otra vez, y luego el núcleo de la solución a ese problema, de tal manera que puedes usar esa solución un millón de veces sin hacerla nunca dos veces igual. Fíjate en la última parte: el patrón no es una plantilla que se copia. Es el núcleo de una idea que cada vez toma una forma distinta según el contexto. Esa frase, aplicada al software, es la vacuna contra el "copio el diagrama y ya".
La segunda es que sus patrones vienen del campo, no del escritorio. Alexander no los inventó: los observó en lugares que ya existían y que la gente disfrutaba.
Dos programadores llevan la idea al software
A finales de los ochenta, Kent Beck y Ward Cunningham —dos figuras que después iban a aparecer en muchas otras historias del oficio— leyeron a Alexander y probaron la idea en programación. En 1987 presentaron un trabajo sobre usar lenguajes de patrones para programas orientados a objetos, con patrones para diseñar interfaces de usuario en Smalltalk. La semilla quedó plantada y durante varios años circuló entre grupos de gente que trabajaba en orientación a objetos.
El libro de 1994
En 1994, cuatro autores —Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides, a quienes la industria acabó llamando la banda de los cuatro, o GoF por sus siglas en inglés— publicaron Design Patterns: Elements of Reusable Object-Oriented Software. Ese libro catalogó 23 patrones y es, sin exagerar, el motivo por el que existe esta guía.
El detalle que más nos importa es cómo los consiguieron. No los inventaron: los extrajeron de sistemas que ya funcionaban —bibliotecas de interfaces gráficas, entornos de Smalltalk, código de C++ de la época—. Es exactamente el método de Alexander: mirar lo que ya está construido y funcionando, encontrar lo que se repite, describirlo.
El libro los organizó en tres familias, y esa clasificación sobrevive hasta hoy:
| Familia | De qué se ocupa | Ejemplos |
|---|---|---|
| Creacionales | Cómo se construyen los objetos | Factory Method, Abstract Factory, Builder, Prototype, Singleton |
| Estructurales | Cómo se componen los objetos entre sí | Adapter, Facade, Decorator, Composite, Proxy, Bridge, Flyweight |
| De comportamiento | Cómo se reparten responsabilidades y se comunican | Strategy, Observer, Template Method, Command, State, Iterator, y otros |
Esas tres familias son la razón por la que los módulos 3, 4 y 5 de esta guía están ordenados como están. La lección 6 vuelve sobre ellas como herramienta mental —no como taxonomía para memorizar—.
Qué envejeció bien y qué no
Aquí conviene la honestidad, porque el catálogo tiene treinta y tantos años y el oficio cambió.
Envejeció bien: el método. La idea de describir problema, solución y consecuencias sigue siendo la mejor forma de hablar de estructura. Y un grupo de patrones —Strategy, Adapter, Facade, Decorator, Observer, Factory, Template Method, Builder— aparece hoy tanto o más que en 1994.
Envejeció regular: varios patrones del catálogo se usan poco. Flyweight, Bridge, Prototype, Memento aparecen en contextos específicos y no en el día a día. No son errores; simplemente su problema es menos frecuente de lo que parecía entonces.
Envejeció mal: el Singleton, que es el más famoso de todos y probablemente el más dañino. Es tan famoso porque es el más fácil de entender y de implementar, y es dañino porque introduce estado global disfrazado de buena práctica —con todo lo que eso implica para las pruebas, la concurrencia y la capacidad de razonar sobre el sistema—. El dato relevante: el propio Erich Gamma ha dicho en entrevistas que lo quitaría de la lista. Que uno de los autores del libro diga eso es la mejor prueba de que el catálogo no es escritura sagrada. El módulo 4 le dedica una lección entera, titulada sin eufemismos "el patrón del que más hay que desconfiar".
Y hay una crítica más profunda, que veremos en la sección siguiente porque cambia cómo se estudia el catálogo entero.
Por qué "descubierto" cambia cómo los usas
Ya tienes la historia. Ahora la consecuencia práctica, que es lo único que de verdad importa de todo lo anterior.
Si un patrón fuera una invención, sería una herramienta disponible: la tomas cuando quieras, la aplicas donde te parezca, y la única pregunta sería si la usaste bien. Bajo esa lente, "aplicar más patrones" suena a "usar más herramientas", y usar más herramientas suena a profesionalismo.
Como un patrón es un descubrimiento, la lógica se invierte. Un patrón es la descripción de lo que pasa cuando ciertas condiciones se dan. Es más parecido a un diagnóstico que a una herramienta. Y bajo esa lente, la pregunta correcta no es "¿lo apliqué bien?" sino "¿tengo las condiciones?".
De ahí salen tres consecuencias que quiero que te lleves.
Primera: el patrón sin el problema es una solución sin problema. No es un uso avanzado ni una preparación para el futuro. Es una pieza de código cuya única razón de existir es que alguien conocía el nombre. En una revisión, la pregunta que desarma esto es simple y educada: "¿qué problema concreto resuelve esto hoy?". Si la respuesta habla en futuro —"por si algún día"— no hay problema, hay pronóstico.
Segunda: no puedes inventar un patrón esta tarde. Puedes inventar una estructura, y puede ser buena. Pero un patrón necesita la parte de "que se repite": necesita evidencia de que la misma solución apareció en muchos lugares independientes. Sin esa evidencia, lo que tienes es una idea, no un patrón. Por eso los patrones nuevos que se han incorporado al vocabulario de la industria —Repository, Dependency Injection, Circuit Breaker— no aparecieron porque alguien los propusiera, sino porque tanta gente los estaba usando que hubo que ponerles nombre. El nombre llega al final, siempre.
Tercera: si tu problema no calza, el patrón no es la autoridad. Cuando la forma canónica de un patrón no encaja con tu caso, la conclusión no es que tu caso esté mal. Los patrones son descripciones de lo típico, y tu situación puede ser atípica con todo derecho. Recuerda la frase de Alexander: usar la solución un millón de veces sin hacerla nunca dos veces igual. Adaptar es lo esperado; forzar tu problema para que quepa en el diagrama es al revés.
El corolario incómodo: patrones que existen porque al lenguaje le faltaba algo
Hay una crítica al catálogo que conviene conocer desde temprano, porque te ahorra estudiar cosas que en tu lenguaje no necesitas.
Varios de los 23 patrones existen, en buena medida, para compensar limitaciones de los lenguajes de finales de los ochenta —C++ y Smalltalk, sobre todo—. Cuando el lenguaje ya trae la capacidad de fábrica, el patrón se vuelve invisible: sigue siendo la misma idea, pero deja de necesitar clases, jerarquías y ceremonia.
El caso más claro es Strategy en un lenguaje con funciones de primera clase. Compara:
# La misma idea, dos formas. Boletia, cálculo de precios.
# Forma A — Strategy "de libro", con clases.
class PricingRule:
def price_for(self, ticket, order_date): ...
class VipPricing(PricingRule):
def price_for(self, ticket, order_date):
return ticket.base_price * 1.40
class GeneralPricing(PricingRule):
def price_for(self, ticket, order_date):
return ticket.base_price
# Uso: alguien elige la regla y el calculador la aplica sin saber cuál es.
def calculate_price(ticket, order_date, rule: PricingRule):
return rule.price_for(ticket, order_date)
# Forma B — la misma idea, con funciones. En Python una función es un valor.
def vip_pricing(ticket, order_date):
return ticket.base_price * 1.40
def general_pricing(ticket, order_date):
return ticket.base_price
# El calculador recibe la función y la aplica. Mismo desacoplamiento, cero clases.
def calculate_price(ticket, order_date, rule):
return rule(ticket, order_date)
Las dos formas resuelven el mismo problema con el mismo desacoplamiento. La forma B tiene menos ceremonia, menos archivos y menos nombres que aprender. En un lenguaje donde las funciones no son valores, la forma B no es posible y por eso hay que envolver cada comportamiento en una clase —que es de donde viene la forma A—.
Esta observación no es mía ni es nueva: Peter Norvig la formuló en una charla de 1996 en la que argumentaba que buena parte de los patrones del catálogo resultan invisibles o mucho más simples en lenguajes dinámicos. La conclusión práctica es doble y conviene tener las dos mitades:
- La idea del patrón nunca sobra. Separar lo que varía de lo que no, y darle una forma común, es útil en cualquier lenguaje. Eso no depende de la sintaxis.
- La ceremonia del patrón muchas veces sí sobra. Si tu lenguaje resuelve la parte mecánica, escribir la jerarquía completa de clases es pagar un costo por nada.
Esta guía va a señalarte cada vez que eso ocurra, y el módulo 3 le dedica una lección entera con el título más directo posible: "en un lenguaje con funciones de primera clase, ¿hace falta la clase?". Por ahora quédate con el reflejo: cuando veas un patrón, pregúntate cuánto de esto es la idea y cuánto es el andamio que mi lenguaje ya no necesita.
Errores comunes
Tratar el catálogo como escritura sagrada (de actitud). Qué pasa: alguien asume que los 23 patrones son un canon cerrado y correcto, y los aplica con la confianza de quien sigue una norma. Cuando su caso no calza con el diagrama, fuerza el caso. Por qué pasa: el libro tiene autoridad histórica real, y en un tema donde casi todo es "depende", una lista de 23 cosas con nombre se siente como tierra firme. Cómo detectarlo: si tu justificación es "así viene en el libro", estás usando autoridad prestada —la falla 3 de la lección anterior—. Cómo corregirlo: recuerda que uno de sus autores diría hoy que quitaría el Singleton, que varios patrones existen para compensar limitaciones de lenguajes de los ochenta, y que la propia definición de Alexander pide adaptar la solución en cada uso. El catálogo es un buen mapa de 1994, no un reglamento.
Aplicar el patrón antes de tener el problema (de criterio). Qué pasa: alguien introduce una interfaz, una fábrica o un sistema de eventos "para estar preparados", con un solo caso real sobre la mesa. Meses después sigue habiendo un solo caso, y ahora también hay tres archivos, un nombre extra que aprender y gente que rodea ese rincón con cuidado. Por qué pasa: la solución se conoce antes que el problema, y una vez que conoces la solución, el mundo se llena de lugares donde parece que encaja. También hay una presión social: agregar estructura parece trabajo de ingeniería, dejar algo simple parece descuido. Cómo detectarlo: cuenta las implementaciones reales que existen hoy. Si es una, es pavimento sobre pasto. Cómo corregirlo: el módulo 2 completo. Y la pregunta que puedes hacerte tú mismo antes de que te la hagan: "¿qué problema concreto resuelve esto hoy, con lo que hay en el repositorio ahora mismo?".
Confundir "no hay patrón" con "está mal diseñado" (de criterio). Qué pasa: alguien mira un módulo simple y directo —un if de dos ramas, una función de veinte líneas— y concluye que le falta diseño. Propone estructura donde no hay dolor. Por qué pasa: después de estudiar patrones, el código sin ellos se ve incompleto, del mismo modo que después de aprender una palabra nueva empiezas a verla en todas partes. Cómo detectarlo: pregúntate si puedes nombrar un cambio futuro concreto y solicitado que hoy sea caro. No "podría pasar que", sino "marketing pidió". Si no lo hay, el diseño simple está bien. Cómo corregirlo: recuerda las tres etapas del ejemplo de esta lección. Un proveedor: sin estructura. Dos: un if. Tres y repetido en tres lugares: ahí sí. El código simple no es código sin diseño; muchas veces es el resultado de haber decidido no agregar lo que todavía no hace falta.
Ejercicios
Ejercicio 1 — Encuentra un camino de deseo en tu vida. Piensa en algún lugar que frecuentes —tu casa, tu oficina, tu trayecto habitual— y encuentra un ejemplo real de una solución que nadie diseñó y que apareció porque el problema la empujó. Puede ser físico (dónde se acumulan los zapatos, qué llave abre qué) o de proceso (cómo se avisa algo en tu equipo aunque no esté escrito en ningún lado). Después responde: (a) ¿cuál era el problema que la empujó? (b) si alguien la "oficializara" —le pusiera un nombre y la documentara—, ¿qué ganaría y qué se perdería?
Ver solución
No hay respuesta única. Lo que sí es predecible es la forma del hallazgo.
Sobre (a): casi siempre el problema es una fricción pequeña y repetida. Nadie hace un camino de deseo por un problema grande y único: los hace la repetición. Eso es literalmente la definición de patrón —"un problema que se repite"— y es útil sentirlo en algo tuyo antes de aplicarlo a código.
Sobre (b), la respuesta interesante suele tener las dos mitades. Al oficializar una práctica se gana que la gente nueva no tenga que descubrirla sola, que se pueda discutir, y que deje de depender de que cierta persona esté presente. Se pierde flexibilidad: una vez escrita, la práctica se vuelve más difícil de cambiar, y aparece la tentación de aplicarla en casos donde no encaja solo porque está escrita. Ese intercambio —claridad a cambio de rigidez— es exactamente el que se paga al introducir un patrón en el código, y por eso el ejercicio funciona.
Ejercicio 2 — Ubica la etapa correcta. Para cada uno de estos cuatro escenarios de Boletia, decide si la estructura propuesta se gana su lugar hoy, y justifica contando variantes y lugares afectados. No hay respuestas de una palabra.
- Hay un formato de reporte (CSV). Alguien propone crear una interfaz
ReportExportercon una implementación. - Hay tres formatos (CSV, PDF, XLSX) que repiten el mismo esqueleto de cuatro pasos en un solo archivo. Alguien propone unificar el esqueleto.
- Hay dos canales de notificación (correo y SMS) y el
checkoutllama a los dos directamente, en dos líneas seguidas. Alguien propone un sistema de eventos con suscriptores. - Hay un tipo de mapa de asientos. Alguien propone un registro de plugins con descubrimiento dinámico, clase base abstracta y carga por nombre de módulo.
Ver solución
1. No se gana su lugar. Una implementación, un archivo, cero dolor. La interfaz no resuelve ningún problema actual: solo agrega un nombre que aprender y un archivo que abrir. Es pavimento sobre pasto. Si mañana llega el PDF, agregar la interfaz en ese momento cuesta lo mismo que cuesta hoy —y para entonces sabrás cómo tiene que ser la interfaz, porque tendrás dos casos reales en lugar de uno imaginado—.
2. Sí, con matices. Tres variantes reales, un esqueleto verdaderamente compartido y un dolor concreto: cualquier cambio al flujo general obliga a revisar tres caminos y a acordarse de los tres. El costo es que leer una exportación completa deja de ser leer de corrido. Con tres variantes y más formatos en el horizonte, sale a cuenta. El matiz: conviene verificar que los tres de verdad comparten el esqueleto y que no hay uno que ya esté divergiendo, porque si lo hay, el esqueleto común se va a llenar de banderas.
3. Todavía no, probablemente. Dos destinatarios, dos líneas seguidas, un solo lugar. Un sistema de eventos aquí compra desacoplamiento que nadie está pidiendo y paga con lo peor: el flujo deja de poder seguirse con el dedo. La respuesta cambia si hay información adicional —por ejemplo, que ya hay tres módulos distintos que quieren enterarse, o que un canal caído está tumbando cobros exitosos—. Sin esa información, es prematuro. Fíjate que en la lección 3 el mismo cambio sí se justificaba: allá había cinco interesados, un sexto anunciado y un fallo que arrastraba el cobro. El mismo patrón, dos veredictos distintos según el contexto. Eso es criterio.
4. Claramente no. Es el caso de plugins/ y es el ejemplo canónico de esta guía. Una implementación, un mecanismo de extensión completo, y un costo permanente: entender el mapa de asientos requiere leer tres archivos. Además hay un costo escondido que se nota poco: el descubrimiento dinámico por nombre de módulo hace que las herramientas —el editor, los buscadores, el analizador estático— no puedan seguir el rastro, así que ni siquiera puedes preguntarle al editor quién implementa esto.
Por qué funciona: los cuatro escenarios se distinguen únicamente por cuántas variantes reales hay y en cuántos lugares duele. Ni una sola vez hizo falta el nombre del patrón para decidir. Ese es el punto de la lección.
Ejercicio 3 — Separa la idea del andamio. Toma la forma A del ejemplo de Strategy con clases que aparece en esta lección. Responde: (a) ¿qué parte de esa estructura es la idea del patrón, la que sirve en cualquier lenguaje? (b) ¿qué parte es andamio que Python no necesita? (c) menciona un caso concreto en el que, aun estando en Python, preferirías la forma con clases.
Ver solución
(a) La idea. Que el comportamiento variable esté separado del código que lo usa; que todas las variantes tengan la misma forma —reciben lo mismo y devuelven lo mismo—; y que quien las usa no sepa cuál le tocó. Esas tres cosas son el patrón y valen en Java, en Go, en Python o en JavaScript. Si las tienes, tienes una Strategy, con clases o sin ellas.
(b) El andamio. La clase base PricingRule con su método vacío, la palabra class repetida por cada variante, la herencia, y la ceremonia de instanciar objetos que no guardan ningún estado. En Python, una función suelta ya cumple las tres condiciones de (a): tiene una forma —su firma—, está separada, y quien la recibe no sabe cuál es. La clase no aporta nada extra en este caso concreto.
(c) Cuándo sí querrías las clases, aun en Python. Varios casos legítimos:
- Cuando la regla necesita estado o configuración propia. Si
EarlyBirdPricingtiene que llevar su fecha de corte y su porcentaje, una clase con constructor es más limpia que una función con parámetros amarrados por fuera. - Cuando la variante tiene más de un método. Si además de
price_forcada regla tiene que responderis_refundableymax_per_order, ya no es un comportamiento sino un conjunto coherente. Ahí la clase agrupa lo que va junto, que es cohesión —un concepto que la guía de fundaciones cubre—. - Cuando quieres que el conjunto sea explícito y verificable. Una clase base con métodos abstractos hace que el editor y el analizador estático te avisen si una variante nueva olvidó implementar algo. Con funciones sueltas, ese olvido aparece en tiempo de ejecución.
Por qué funciona: la pregunta "¿cuánto de esto es idea y cuánto es andamio?" es aplicable a todos los patrones que verás en los módulos 3 a 6, y es lo que te va a permitir usarlos en cualquier lenguaje sin arrastrar ceremonia ajena. Y la parte (c) evita el error opuesto —creer que las clases siempre sobran—, que es otra forma de aplicar una regla sin contexto.
Resumen y siguiente paso
En esta lección viste que los patrones son caminos de deseo pavimentados: senderos que la gente pisó por su cuenta, resolviendo el mismo problema una y otra vez, y que alguien después reconoció, describió y nombró. Viste el nacimiento de uno dentro de Boletia —un proveedor de pago, luego dos, luego tres repetidos en tres archivos— y comprobaste que hubo dos etapas en las que la ausencia de estructura era la decisión correcta, y que la diferencia entre el payments/ sano y el plugins/ enfermo no es la forma sino el orden: uno llegó después del problema, el otro antes.
Conociste la historia: Christopher Alexander y sus patrones de arquitectura de edificios en los setenta, con la definición que sigue siendo la mejor —un problema que ocurre una y otra vez, y el núcleo de su solución, de modo que puedas usarla un millón de veces sin repetirla nunca igual—; Beck y Cunningham llevándola al software a finales de los ochenta; y el libro de la banda de los cuatro en 1994, que extrajo sus 23 patrones de sistemas que ya funcionaban y los ordenó en tres familias. Y viste que ese catálogo tiene edad: hay patrones que se usan poco, uno —el Singleton— que su propio autor quitaría, y varios que existen para compensar limitaciones de lenguajes de la época.
De ahí salieron las tres consecuencias prácticas: el patrón sin el problema es una solución sin problema; no se puede inventar un patrón por decreto, porque le faltaría la evidencia de repetición; y si tu caso no calza con el diagrama, el diagrama no es la autoridad. Más el reflejo del corolario: distinguir siempre la idea del patrón —que vale en cualquier lenguaje— del andamio que tu lenguaje quizás ya no necesita.
Antes de avanzar deberías poder: explicar en una frase por qué se dice que los patrones se descubrieron; identificar las tres etapas del ejemplo de proveedores de pago y por qué la estructura solo se gana su lugar en la tercera; y decir qué parte de una Strategy con clases es idea y qué parte es ceremonia.
Hasta aquí todo ha sido conceptual. La lección 5 baja a la práctica con la habilidad más útil de este módulo: reconocer un patrón en código que nadie etiquetó. Porque en el mundo real no hay comentarios que digan "aquí empieza el Adapter". Vas a aprender qué pistas concretas se buscan, en qué orden se mira un archivo desconocido, y vas a hacerlo sobre el código de notificaciones de Boletia sin que el nombre aparezca por ningún lado.
Recursos
- A Pattern Language (Alexander, Ishikawa, Silverstein) — el libro de 1977 con los 253 patrones de arquitectura. Hojear tres o cuatro patrones basta para entender el método; la forma de cada ficha es la que el software terminó copiando.
- Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides) — el catálogo original de 1994. Vale la pena conocer su prólogo, donde explican de dónde extrajeron los patrones.
- Design Patterns in Dynamic Languages (Peter Norvig) — las diapositivas de la charla de 1996 que argumenta que buena parte del catálogo se vuelve invisible o trivial en lenguajes dinámicos. Es el corolario de esta lección, en su fuente.
- Design Patterns 15 Years Later: An Interview with Erich Gamma, Richard Helm, and Ralph Johnson (InformIT) — la entrevista donde los propios autores revisan qué cambiarían, incluido quitar el Singleton.