Principio DRY — Don't Repeat Yourself
"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." — Andrew Hunt y David Thomas, The Pragmatic Programmer (1999)
DRY no es "no copies código". Es algo más preciso y más poderoso: cada pieza de conocimiento del sistema debe tener una única representación autoritativa. Cuando esa representación cambia, el cambio se propaga automáticamente a todo lo que depende de ella — sin que nadie tenga que recordar actualizar múltiples lugares.
Qué es DRY realmente
La distinción importante: DRY habla de conocimiento, no de líneas de código.
Dos funciones que hacen cosas parecidas pero responden a razones de cambio distintas no son violaciones de DRY. Si el cálculo de descuento para clientes VIP en facturación cambia independientemente del cálculo de descuento para empleados en RRHH, representarlos por separado no viola DRY — unificarlos sería un error.
DRY sí se viola cuando:
- La misma regla de negocio aparece en dos lugares. Si la regla cambia, hay que recordar cambiarla en ambos.
- La misma validación está duplicada en el frontend y el backend sin un contrato compartido.
- La misma consulta SQL aparece copiada en cinco repositorios distintos.
- La misma configuración está hardcodeada en varios archivos en lugar de venir de una fuente central.
❌ Violación de DRY
Ejemplo 1 — Lógica de negocio duplicada
# En el módulo de pedidos
function validate_order(order):
if order.total < 0:
raise Error("Total cannot be negative")
if order.items.is_empty():
raise Error("Order must have at least one item")
if order.customer_id is null:
raise Error("Order must have a customer")
# En el módulo de presupuestos (copipaste con pequeñas variaciones)
function validate_quote(quote):
if quote.total < 0:
raise Error("Total cannot be negative")
if quote.items.is_empty():
raise Error("Quote must have at least one item")
if quote.customer_id is null:
raise Error("Quote must have a customer")
Si la regla "total no puede ser negativo" cambia (por ejemplo, para permitir notas de crédito), hay que recordar cambiarla en ambos lugares. Si uno se olvida, el sistema queda inconsistente.
Ejemplo 2 — Configuración duplicada
# Servicio A
timeout = 30
max_retries = 3
base_url = "https://payments.wiedii.internal"
# Servicio B (mismo dominio, mismos valores copiados)
timeout = 30
max_retries = 3
base_url = "https://payments.wiedii.internal"
Si la URL del servicio de pagos cambia, hay que actualizarla en todos los servicios que la usan. Una fuente de verdad central (variable de entorno, registro de configuración, archivo compartido) elimina el problema.
✅ Aplicación de DRY
Ejemplo 1 — Extraer la lógica al lugar que le pertenece
# Regla de negocio en su único lugar autoritativo
function validate_document(doc):
if doc.total < 0:
raise Error("Total cannot be negative")
if doc.items.is_empty():
raise Error("Document must have at least one item")
if doc.customer_id is null:
raise Error("Document must have a customer")
# Los módulos delegan
function validate_order(order):
validate_document(order)
# validaciones específicas de pedidos, si las hay
function validate_quote(quote):
validate_document(quote)
# validaciones específicas de presupuestos, si las hay
La regla compartida vive en un lugar. Si cambia, cambia en un solo sitio.
Ejemplo 2 — Fuente única de configuración
# config/payments.yaml (o variable de entorno)
PAYMENTS_SERVICE_URL: "https://payments.wiedii.internal"
PAYMENTS_TIMEOUT: 30
PAYMENTS_MAX_RETRIES: 3
# Todos los servicios leen de la misma fuente
config = load_config("payments")
client = HttpClient(url=config.url, timeout=config.timeout)
DRY, WET y AHA
En la práctica, el ecosistema habla de tres posiciones:
WET — Write Everything Twice (o "We Enjoy Typing"): el anti-patrón. Código duplicado sin razón, con toda la deuda técnica que eso implica.
DRY — Don't Repeat Yourself: elimina la duplicación de conocimiento. Es el objetivo, pero puede llevarse demasiado lejos.
AHA — Avoid Hasty Abstractions (formulado por Kent C. Dodds): no abstraigas demasiado pronto. La abstracción incorrecta es más cara que la duplicación. Es mejor tener código duplicado que entender bien antes de abstraer, que crear una abstracción prematura que une cosas que en realidad son distintas y termina siendo un cuello de botella en la evolución del sistema.
La secuencia recomendada en Wiedii: duplica cuando no conoces todavía el patrón → abstrae cuando ves la tercera repetición y entiendes el dominio suficientemente bien (la "regla de tres").
Cuándo la duplicación es correcta
La duplicación no siempre es un error. Es correcta cuando:
Las razones de cambio son distintas. Dos fragmentos de código similares que pertenecen a distintos bounded contexts o a distintos actores del sistema deben permanecer separados aunque se vean iguales hoy. Si los unificas, creates un acoplamiento que luego es más difícil de romper.
La abstracción sería prematura. La "regla de tres" ayuda aquí: si solo ves dos casos, espera a ver el tercero antes de abstraer. Con solo dos casos, no siempre se tiene suficiente información para diseñar la abstracción correcta.
El código es de bootstrapping o glue. El código de inicialización, composición de dependencias o configuración de entorno suele parecer repetitivo pero en realidad cada instancia es distinta en contexto. Unificarlo forzadamente puede oscurecer la intención.
Señales de alerta de violación DRY
- La respuesta a "¿dónde cambio X?" es "en varios sitios" — señal clásica.
- Bugs que aparecen en dos lugares a la vez porque hay lógica duplicada.
- En code review, alguien dice "esto ya existe en el módulo Y".
- Copipaste con pequeñas variaciones (renombrar variables, cambiar un literal) entre archivos.
- Constantes repetidas (strings, números mágicos) en múltiples archivos.
DRY en distintos niveles del sistema
A nivel de código: funciones, clases, módulos compartidos para lógica común.
A nivel de datos: una única fuente de verdad para cada entidad del dominio. Si el precio de un producto existe en la base de datos de pedidos y en la de inventario y en caché y en el frontend, necesitas una estrategia de sincronización que mantenga la coherencia — o tienes duplicación de conocimiento a nivel de datos.
A nivel de configuración: variables de entorno centralizadas, registros de configuración, secrets managers. Nunca un valor de configuración hardcodeado en múltiples servicios.
A nivel de documentación: si la misma decisión arquitectónica está explicada en tres wikis distintas, cuando la decisión cambie una quedará desactualizada. Un ADR en 04-estandares/ es la fuente autoritativa; el resto referencia al ADR.
Documentos relacionados
- SOLID — El principio SRP define las razones de cambio que determinan si la duplicación es correcta o no
- KISS — El equilibrio: no abstraer más de lo necesario
- politicas-core — Políticas de desarrollo Wiedii