En programación informática , el código duplicado es una secuencia de código fuente que aparece más de una vez, ya sea dentro de un programa o en diferentes programas que son propiedad de la misma entidad o que ella mantiene. El código duplicado generalmente se considera indeseable por varias razones. [1] Por lo general, se aplica un requisito mínimo a la cantidad de código que debe aparecer en una secuencia para que se considere duplicada en lugar de coincidentemente similar. Las secuencias de código duplicado a veces se conocen como clones de código o simplemente clones; el proceso automatizado de encontrar duplicaciones en el código fuente se denomina detección de clones.
Dos secuencias de código pueden ser duplicadas entre sí sin ser idénticas carácter por carácter, por ejemplo, siendo idénticas carácter por carácter solo cuando se ignoran los espacios en blanco y los comentarios, o siendo idénticas token por token , o idénticas token por token con variaciones ocasionales. Incluso las secuencias de código que solo son idénticas funcionalmente pueden considerarse código duplicado.
Algunas de las formas en que se puede crear código duplicado son:
También puede ocurrir que se requiera una funcionalidad muy similar a la de otra parte de un programa y que un desarrollador escriba de forma independiente un código muy similar al que existe en otro lugar. Los estudios sugieren que ese código reescrito de forma independiente normalmente no es similar desde el punto de vista sintáctico. [2]
Otro motivo de duplicación es el código generado automáticamente, en el que puede ser conveniente tener código duplicado para aumentar la velocidad o la facilidad de desarrollo. Tenga en cuenta que el generador real no contendrá duplicados en su código fuente, solo en el resultado que produce.
La forma más común de solucionar el código duplicado es moverlo a su propia unidad ( función o módulo) y llamar a esa unidad desde todos los lugares donde se utilizó originalmente. El uso de un estilo de desarrollo de código abierto, en el que los componentes se encuentran en ubicaciones centralizadas, también puede ayudar con la duplicación.
El código que incluye funcionalidad duplicada es más difícil de soportar porque,
Por otra parte, si una copia del código se utiliza para diferentes propósitos y no está debidamente documentada, existe el peligro de que se actualice para un propósito, pero esta actualización no será necesaria ni apropiada para sus otros propósitos.
Estas consideraciones no son relevantes para el código generado automáticamente, si solo hay una copia de la funcionalidad en el código fuente.
En el pasado, cuando el espacio de memoria era más limitado, el código duplicado tenía la desventaja adicional de ocupar más espacio, pero hoy en día es poco probable que esto sea un problema.
Cuando se copia un código con una vulnerabilidad de software , la vulnerabilidad puede seguir existiendo en el código copiado si el desarrollador no es consciente de dichas copias. [3] La refactorización de código duplicado puede mejorar muchas métricas de software, como líneas de código , complejidad ciclomática y acoplamiento . Esto puede conducir a tiempos de compilación más cortos, menor carga cognitiva , menos error humano y menos fragmentos de código olvidados o pasados por alto. Sin embargo, no toda la duplicación de código se puede refactorizar. [4] Los clones pueden ser la solución más eficaz si el lenguaje de programación proporciona abstracciones inadecuadas o demasiado complejas, en particular si se apoyan en técnicas de interfaz de usuario como la edición simultánea . Además, los riesgos de romper el código durante la refactorización pueden superar cualquier beneficio de mantenimiento. [5] Un estudio de Wagner, Abdulkhaleq y Kaya concluyó que, si bien se debe realizar un trabajo adicional para mantener los duplicados sincronizados, si los programadores involucrados son conscientes del código duplicado, no se produjeron significativamente más fallas que en el código no duplicado. [6] [ disputado – discutir ]
Se han propuesto varios algoritmos diferentes para detectar código duplicado. Por ejemplo:
Considere el siguiente fragmento de código para calcular el promedio de una matriz de números enteros
externo int matriz_a []; externo int matriz_b []; int suma_a = 0 ; para ( int i = 0 ; i < 4 ; i ++ ) suma_a += matriz_a [ i ]; int promedio_a = suma_a / 4 ; int suma_b = 0 ; para ( int i = 0 ; i < 4 ; i ++ ) suma_b += matriz_b [ i ]; int promedio_b = suma_b / 4 ;
Los dos bucles se pueden reescribir como una única función:
int calc_promedio_de_cuatro ( int * matriz ) { int suma = 0 ; para ( int i = 0 ; i < 4 ; i ++ ) suma += matriz [ i ]; devuelve suma / 4 ; }
o, normalmente de manera preferible, parametrizando el número de elementos de la matriz.
El uso de la función anterior proporcionará un código fuente que no tiene duplicación de bucle:
externo int matriz1 []; externo int matriz2 []; int promedio1 = calc_promedio_de_cuatro ( matriz1 ); int promedio2 = calc_promedio_de_cuatro ( matriz2 );
Tenga en cuenta que en este caso trivial, el compilador puede optar por incluir en línea ambas llamadas a la función, de modo que el código de máquina resultante sea idéntico para los ejemplos duplicados y no duplicados anteriores. Si la función no está incluida en línea, entonces la sobrecarga adicional de las llamadas a la función probablemente tardará más en ejecutarse (del orden de 10 instrucciones de procesador para la mayoría de los lenguajes de alto rendimiento). En teoría, este tiempo adicional de ejecución podría ser importante.