El primer paso para aplicar el principio DRY es reconocer dónde ocurre la duplicación. Muchas veces la repetición pasa inadvertida hasta que enfrentamos un defecto o necesitamos incorporar una mejora. En esta sección veremos técnicas, señales y herramientas que ayudan a identificar duplicaciones antes de que se conviertan en un problema grave.
Adoptaremos una mirada práctica enfocada en proyectos escritos en Java, aunque las recomendaciones son aplicables a cualquier lenguaje orientado a objetos.
Detectar duplicaciones es más sencillo cuando podemos clasificarlas. Las principales categorías son:
Algunas pistas habituales indican que hay duplicación de lógica:
Las revisiones de código son un espacio ideal para identificar duplicaciones tempranas. La persona revisora puede señalar similitudes con otras partes del sistema, mientras que la programación en pareja permite detectar patrones repetidos mientras se escribe el código.
Herramientas como SonarQube o SpotBugs incluyen detectores de duplicación textual y estructural. Configurarlas en la integración continua genera reportes automáticos que alertan sobre la repetición de bloques de código.
Algunos IDEs, como IntelliJ IDEA, ofrecen inspecciones que resaltan fragmentos similares dentro del proyecto, facilitando la refactorización inmediata.
Los comandos `rg`, `grep` o `findstr` permiten localizar patrones de texto repetidos. Buscar por firmas de métodos o cadenas literales ayuda a detectar duplicaciones semánticas. Ejemplos:
rg "IVA" src/main/java
rg "if \\(status == Status.ACTIVO\\)" -g"*.java"
Estas búsquedas se pueden automatizar en scripts de verificación previa a los commits para prevenir que la duplicación llegue a la rama principal.
Las métricas de duplicación calculan el porcentaje de código repetido. Mantenerlo por debajo del 5% es un objetivo razonable para proyectos medianos. Otra métrica útil es la longitud promedio de los métodos: secciones extensas suelen contener lógica duplicada o responsabilidades mezcladas.
Las pruebas son una herramienta indirecta para detectar duplicación. Si múltiples tests replican la misma configuración o datos, probablemente el código de producción también esté duplicado. Extraer métodos de utilidad en los tests puede revelar refactorizaciones necesarias en el código real.
Historias con descripciones muy similares o que reutilizan exactamente el mismo criterio de aceptación pueden dar origen a duplicaciones. Documentar la motivación del cambio y referenciar el código afectado ayuda a evitar que se creen variantes del mismo flujo en distintas capas.
Observemos un servicio que calcula bonos para distintos perfiles. A simple vista parece correcto, pero repite lógica con pequeñas diferencias:
class BonoService {
double calcularBonoGerente(Empleado empleado) {
if (!empleado.activo()) {
return 0.0;
}
double base = empleado.salario() * 0.2;
if (empleado.antiguedad() >= 5) {
base += empleado.salario() * 0.05;
}
if (empleado.resultados().esSobresaliente()) {
base += 5000;
}
return base;
}
double calcularBonoLiderTecnico(Empleado empleado) {
if (!empleado.activo()) {
return 0.0;
}
double base = empleado.salario() * 0.18;
if (empleado.antiguedad() >= 5) {
base += empleado.salario() * 0.05;
}
if (empleado.resultados().esSobresaliente()) {
base += 3000;
}
return base;
}
}
Hay una duplicación semántica: ambos métodos repiten los mismos chequeos y solo cambian porcentajes y bonos adicionales. Podemos revelar esa duplicación aplicando pruebas y extrayendo los parámetros variables:
class BonoService {
double calcularBono(Empleado empleado, PoliticaBono politica) {
if (!empleado.activo()) {
return 0.0;
}
double base = empleado.salario() * politica.porcentajeBase();
if (empleado.antiguedad() >= politica.antiguedadMinima()) {
base += empleado.salario() * politica.porcentajeAntiguedad();
}
if (empleado.resultados().esSobresaliente()) {
base += politica.bonoExtra();
}
return base;
}
}
record PoliticaBono(double porcentajeBase,
int antiguedadMinima,
double porcentajeAntiguedad,
double bonoExtra) {}
El refactor permite reutilizar el mismo flujo para distintos perfiles. Las políticas se definen como datos y el código de negocio queda centralizado.
Para detectar duplicaciones durante una revisión de código, asegúrate de responder:
Aunque identificar duplicaciones es fundamental, prevenirlas es más eficiente. Algunas medidas son:
Identificar la duplicación es un trabajo continuo que requiere observación, herramientas y colaboración. Al mantener la lógica centralizada, aumentamos la calidad y reducimos el coste de mantener el sistema.
En el siguiente tema veremos técnicas de refactorización basadas en abstracciones para eliminar la duplicación detectada.