El principio DRY sostiene que cada pieza de conocimiento debe tener una representación única, inequívoca y autorizada dentro de un sistema. Su objetivo es evitar que la duplicación de lógica se convierta en una fuente continua de defectos y costos de mantenimiento.
Aplicar DRY no implica abstraer de manera excesiva, sino consolidar la información para que cada cambio se realice en un único lugar, manteniendo la coherencia del negocio.
DRY fue acuñado por Andrew Hunt y David Thomas en "The Pragmatic Programmer". Surgió como una respuesta a los problemas cotidianos provocados por la copia y el pegado indiscriminado de código y configuraciones.
Cuando dos fragmentos comparten la misma lógica, tarde o temprano uno de ellos queda desactualizado, generando defectos que son difíciles de detectar porque el programador asume que ambos fragmentos se encuentran sincronizados.
En proyectos Java podemos encontrar duplicaciones de distinta naturaleza:
Un código duplicado suele generar conversaciones recurrentes durante revisiones de código: "este método ya existe en otra clase", "recuerdo haber implementado algo similar". También aparecen errores que solo se corrigen en una parte, dejando la otra obsoleta.
La automatización ayuda: algunas herramientas de análisis estático detectan duplicaciones textuales, pero el criterio profesional sigue siendo indispensable para evaluar duplicaciones más sutiles.
No todo lo repetido amerita una abstracción. En ocasiones, dos fragmentos similares representan etapas distintas del negocio y evolucionan por separado. DRY se aplica cuando la duplicación comparte el mismo motivo de cambio; si ambas partes necesitan modificarse al mismo tiempo, entonces la duplicación es nociva.
Aplicar una abstracción demasiado pronto puede introducir complejidad artificial. Conviene refactorizar cuando la duplicación ya es evidente y se confirma que la lógica representa un mismo concepto.
Entre las técnicas más usadas encontramos:
El principio también se aplica a consultas SQL y mapeos. Vistas, procedimientos almacenados o repositorios reutilizables impiden que la misma consulta se defina en múltiples capas. En proyectos Java, frameworks como JPA permiten centralizar las consultas en una única entidad o repositorio.
Eliminar duplicaciones sin pruebas automatizadas es riesgoso. Un conjunto de pruebas bien diseñado permite refactorizar con confianza, asegurando que la nueva abstracción respeta el comportamiento original.
Antes de aplicar una transformación DRY, conviene escribir pruebas para el comportamiento duplicado, garantizando que ambas versiones se comportan igual.
Supongamos un servicio de facturación con dos métodos que calculan impuestos por separado, generando inconsistencias:
class FacturacionService {
double calcularTotalFactura(Factura factura) {
double subtotal = factura.subtotal();
double iva = subtotal * 0.21;
double ingresosBrutos = subtotal * 0.03;
return subtotal + iva + ingresosBrutos;
}
double calcularTotalNotaCredito(NotaCredito nota) {
double subtotal = nota.subtotal();
double iva = subtotal * 0.21;
double ingresosBrutos = subtotal * 0.027;
return subtotal + iva + ingresosBrutos;
}
}
El IVA debería ser el mismo en ambos casos, pero la copia modificada del código introduce un porcentaje distinto para ingresos brutos. Apliquemos DRY:
class CalculadoraDeImpuestos {
private static final double IVA = 0.21;
private static final double INGRESOS_BRUTOS = 0.03;
double calcularImpuestos(double subtotal) {
double iva = subtotal * IVA;
double ingresosBrutos = subtotal * INGRESOS_BRUTOS;
return iva + ingresosBrutos;
}
}
class FacturacionService {
private final CalculadoraDeImpuestos calculadora;
FacturacionService(CalculadoraDeImpuestos calculadora) {
this.calculadora = calculadora;
}
double calcularTotalFactura(Factura factura) {
return factura.subtotal() + calculadora.calcularImpuestos(factura.subtotal());
}
double calcularTotalNotaCredito(NotaCredito nota) {
return nota.subtotal() + calculadora.calcularImpuestos(nota.subtotal());
}
}
Ahora la lógica tributaria reside en una clase exclusiva. Cualquier cambio impositivo se refleja en un solo lugar y los servicios reutilizan la misma implementación.
El principio también se extiende a documentación, tableros de gestión y procesos operativos. Mantener una única fuente de verdad evita discrepancias entre manuales, diagramas y el sistema en ejecución.
En el ecosistema Java existen soluciones que detectan duplicaciones o promueven la reutilización:
Estas herramientas no sustituyen al criterio humano, pero actúan como redes de seguridad que alertan sobre duplicaciones accidentales.
Algunos equipos confunden DRY con crear una mega abstracción que resuelva todos los casos, conduciendo a diseños crípticos. Otros se enfocan solo en reducir el número de líneas ignorando el significado del código.
La mejor práctica es abstraer con moderación, nombrar bien los componentes y validar que la nueva estructura representa un concepto claro del dominio.
Incorporar preguntas concretas en la revisión ayuda a sostener DRY:
DRY es un pilar de la simplicidad porque concentra el conocimiento en ubicaciones bien definidas. Al adoptarlo, disminuye la probabilidad de defectos y se acelera el mantenimiento. En el siguiente tema aprenderemos a detectar duplicaciones de lógica de forma sistemática.