Pattern Selection

Práctica y pregunta central

¿Qué problema, variación o coupling necesito administrar, y qué costo justifica otra organización? Pattern Selection comienza por esa pregunta. Se opone a pattern-first design: comenzar con «¿qué patrón puedo usar?» y después buscar una necesidad que justifique el nombre.

design-pattern describe conocimiento reutilizable con contexto y consecuencias. Esta práctica ayuda a decidir si adaptarlo, rechazarlo o simplificar una implementación existente. Reconocer una colaboración como Strategy puede facilitar comunicación; diseñar todas las colaboraciones para exhibir patrones puede empeorar comprensión.

La descripción GoF incluye aplicabilidad y trade-offs, no solamente estructura. Su valor exige evaluar condiciones de uso. Design Patterns: Elements of Reusable Object-Oriented Software.

Proceso orientativo

  1. Comprender el problema. Describir el comportamiento necesario, quién lo usa y qué restricción importa.
  2. Identificar forces y variation points. Precisar qué cambia independientemente y qué debe permanecer estable.
  3. Preferir el diseño más simple que funciona. Una función o construcción directa puede satisfacer la necesidad.
  4. Observar presión recurrente. Revisar cambios reales, duplicación de decisiones y acoplamiento que cuesta mantener.
  5. Considerar candidatos. Comparar una pequeña selección con la solución directa.
  6. Evaluar consecuencias. Incluir pruebas, debugging, configuración, lifecycle y costo de evolución.
  7. Implementar solo con trade-off justificado. Conservar evidencia de qué obligación protege la solución.

No es un procedimiento obligatorio de siete reuniones. Puede aplicarse en una conversación breve o en una revisión de diseño más extensa según alcance. Tampoco exige esperar a que un riesgo conocido produzca un incidente: una integración comprometida y requisitos verificables pueden constituir presión real.

YAGNI cuestiona capacidades especulativas construidas para un futuro supuesto, y no elimina la necesidad de diseño sostenible. Fowler desarrolla el costo de mantener lo que todavía no se necesita. Yagni.

Forces: tensiones a equilibrar

Forces son necesidades y restricciones que empujan en direcciones distintas. Un patrón responde a una combinación de tensiones; no maximiza abstracción por principio.

TensiónPregunta para este diseño
Extensión y simplicidad¿Qué variación comprometida requiere un contrato y cuál solo imaginamos?
Abstracción y comprensión¿La conversación expresa propósito o obliga a navegar tipos genéricos?
Desacoplamiento e indirection¿Qué cambio queda contenido y cuánto cuesta seguir una operación?
Reuso y generalización prematura¿Hay consumidores reales compatibles o una API para casos hipotéticos?

El equilibrio depende del contexto. Un contrato de extensiones públicas tiene consumidores y costos de compatibilidad distintos de una función privada. Esa diferencia puede justificar cuidado anticipado sin construir mecanismos para toda posibilidad.

Una abstracción también puede cambiar quién posee el recurso o quién selecciona una política. Si esas decisiones siguen implícitas, agregar una interface puede desplazar el problema en lugar de resolverlo.

Heurísticas, no respuestas automáticas

PresiónFamilia candidata
Varía creación o configuración.creational-patterns
Se necesita combinar, adaptar o envolver partes.structural-patterns
Varía comportamiento o colaboración.behavioral-patterns

Estas familias orientan lectura; sus preocupaciones pueden interactuar. Crear un objeto diferente puede modificar comportamiento y lifecycle, pero no exige seleccionar un patrón de cada familia.

Señal de problemaCandidatoQué comprobar antes
Algoritmos intercambiables.strategy-patternContrato compartido y selección independiente.
Interfaz incompatible.adapter-patternCompatibilidad semántica, no solo firmas.
Responsabilidad adicional sin cambiar el componente.decorator-patternOrden, transparencia y ownership.
Entrada común demasiado dependiente de detalles internos.facade-patternPropósito coherente, contrato de resultado y límites de coordinación.
Necesidad de un representante controlado, lazy o remoto.proxy-patternCostos observables, permisos, fallos y lifecycle.
Creación concreta variable en un protocolo anfitrión.factory-method-patternNecesidad de extensión del Creator frente a una función o construcción directa.
Familia de productos compatibles variable.abstract-factory-patternRestricción conjunta real y costo de agregar tipos de producto.
Construcción compleja.builder-patternEtapas, invariantes y necesidad frente a una función directa.
Solicitud que debe tratarse como objeto o datos.command-patternEstado, autoridad y efectos de su ejecución.
Varios dependientes necesitan conocer cambios.observer-patternSuscripciones, lifecycle y semántica de notificación.

Candidate ≠ automatic answer. La tabla es una heurística, no un decision engine. No puntúa nombres ni garantiza calidad. Un algoritmo diferente puede expresarse con una función; una interfaz estable puede no necesitar un wrapper.

Ejemplo propio: cálculo de precios

Una propuesta pobre dice: «usemos Strategy porque es un buen patrón». La formulación útil dice: «el cálculo varía entre segmentos de clientes, cambia por razones independientes y los callers no deberían conocer cada algoritmo».

Supongamos que inicialmente existe una tarifa fija. Una función directa permite entender y probar el cálculo. Crear una interfaz, factory, registro y configuración dinámica antes de tener variantes añade obligaciones sin una presión demostrada.

Después se incorporan tres políticas con reglas y pruebas independientes. Podemos comparar:

AlternativaQué conservaCosto que introduce
Función con selección local.Un punto pequeño y visible para decidir.El selector puede crecer junto con las reglas.
Función de cálculo suministrada.Contrato de entrada/salida, algoritmo intercambiable.Alguien debe elegir y proporcionar la función.
Objetos Strategy.Contrato y estado propio de cada política si lo necesita.Tipos, ensamblaje y lifetime adicionales.

La elección depende de necesidades reales del lenguaje y la operación. Si las políticas solo transforman datos sin estado, funciones pueden bastar. Si administran colaboradores o configuración con reglas propias, objetos pueden expresar mejor esas obligaciones.

Verificar que introducir una política no obligue a editar callers ajenos, y que una selección inválida produzca un resultado definido. Una implementación con nombres correctos pero selección distribuida por todo el sistema puede mantener el mismo coupling.

También puede decidirse conservar el diseño directo: tres ramas breves que cambian juntas no implican variación independiente. Rechazar Strategy sería correcto si agrega más navegación que aislamiento útil.

Patterns have costs

Los costos deben aparecer explícitamente en la comparación: más tipos, más abstracciones, indirection y carga cognitiva; debugging a través de wrappers o eventos; configuración, lifecycle y riesgo de generalización excesiva.

Una interface puede ocultar cuál implementación está activa. Un registro dinámico puede trasladar errores de compilación a startup. Un Observer puede requerir inspeccionar una suscripción para entender por qué cambió una pantalla. Esos costos pueden justificarse, pero no desaparecen porque la solución tenga un nombre reconocido.

Más patrones no equivale a mejor diseño. Comparar el cambio esperado y el trabajo adicional en lectura, pruebas y soporte. Evitar medir éxito por número de interfaces, ausencia de conditional o parecido con un diagrama del libro. Si la justificación invoca modificabilidad o testabilidad, quality-attribute-scenarios ayuda a precisar qué cambio o comprobación importa. quality-attribute-trade-offs contrasta el beneficio esperado con otras consecuencias, sin convertir un patrón local en garantía de calidad.

Patrón, lenguaje y framework

Funciones de primera clase pueden expresar Strategy; protocolos de iteración, Iterator; eventos, parte del mecanismo Observer. Closures, constructores o ensamblaje suministrado pueden reducir ceremony de creación.

La presión e intención pueden seguir existiendo aunque el lenguaje no requiera una jerarquía de clases. A la inversa, usar una feature no demuestra que sus consecuencias estén resueltas: eventos no administran por sí solos suscripciones ni delivery guarantees.

Los propios autores GoF discuten cómo lenguajes y metaprogramación cambian la manifestación de patrones. Entrevista retrospectiva. No hace falta reconstruir el ceremony histórico que una plataforma ya proporciona.

Patrón, principio y arquitectura

Un principio orienta decisiones generales; un patrón propone una colaboración recurrente con contexto. Dependency Inversion, Open/Closed y Single Responsibility son principios. Strategy, Decorator y Adapter son patrones: pueden ayudar a aplicar un principio sin ser categorías equivalentes.

architectural-pattern y architecture-profile tratan otros compromisos. Una composición posible es:

Microservices architecture profile
└── Payment Service
    └── Ports and Adapters
        └── Pricing component
            └── Strategy

microservices y ports-and-adapters permiten recuperar esas dimensiones. El dibujo muestra alcances anidados en un ejemplo, no una escalera universal de tamaños. Seleccionar Strategy no resuelve deployment ni propiedad de datos entre servicios.

Composición y comprobación

Abstract Factory puede crear Strategies compatibles; Decorator puede envolverlas; Command puede despacharse mediante Mediator. Cada colaboración necesita una razón distinta y contratos que no se contradigan.

Evitar pattern soup: agregar una abstracción para cada llamada hasta que el flujo solo pueda entenderse recorriendo un catálogo. Si una composición dificulta localizar autoridad, orden o recursos, compararla con una versión simplificada.

Probar el comportamiento que motivó el cambio: selección correcta, entrada incompatible, modificación independiente y conservación de resultados. No crear pruebas que solo certifiquen nombres de clases o una secuencia de delegaciones triviales.

Una revisión útil puede cerrar con problema, alternativa directa, candidato, beneficio esperado, costo aceptado y evidencia. Si no puede explicarse qué presión protege el patrón, conservarlo requiere reconsideración. design-patterns conecta esta práctica con las familias sin imponer un catálogo obligatorio.