refactoring - ¿Cuánto código duplicado tolera?
coding-style dry (13)
En una revisión de código reciente, detecté algunas líneas de lógica duplicada en una clase (menos de 15 líneas). Cuando sugerí que el autor refactorizara el código, argumentó que el código es más simple de entender de esa manera. Después de volver a leer el código, tengo que estar de acuerdo en que extraer la lógica duplicada perjudicará un poco la legibilidad.
Sé que DRY es una guía, no una regla absoluta. Pero, en general, ¿está dispuesto a perjudicar la legibilidad en nombre de DRY?
Acepto NO código duplicado Si se usa algo en más de un lugar, será parte del marco o al menos una biblioteca de utilidad.
La mejor línea de código es una línea de código no escrita.
El punto de DRY es mantenibilidad. Si el código es más difícil de entender, es más difícil de mantener, por lo que si la refacturación perjudica la legibilidad, es posible que no cumplas la meta de DRY. Por menos de 15 líneas de código, me inclino a estar de acuerdo con tu compañero de clase.
En general, no. No para lectura de todos modos. Siempre hay alguna forma de refactorizar el código duplicado en una intención que revela un método común que se lee como un libro, IMO.
Si quieres argumentar a favor de la violación de DRY para evitar la introducción de dependencias, eso puede tener más peso, y puedes obtener la opinión obstinada de Ayende junto con el código para ilustrar el punto here .
A menos que su desarrollador sea realmente Ayende, me mantendré firme en DRY y obtendré la legibilidad mediante métodos que revelan la intención.
BH
La legibilidad es una de las cosas más importantes que el código puede tener, y no estoy dispuesto a ceder en él. El código duplicado es un mal olor, no un pecado mortal.
Dicho esto, hay problemas aquí.
Si se supone que este código es el mismo, en lugar de ser casualmente el mismo, existe un riesgo de mantenimiento. Tenía comentarios en cada lugar apuntando hacia el otro, y si necesitaba estar en un tercer lugar, lo refactorizaba. (De hecho, tengo un código como este, en dos programas diferentes que no comparten los archivos de código apropiados, por lo que los comentarios en cada programa apuntan al otro).
No ha dicho si las líneas forman un todo coherente, realizando alguna función que pueda describir fácilmente. Si lo hacen, refactorícelos. Es poco probable que este sea el caso, ya que acepta que el código sea más legible e incrustado en dos lugares. Sin embargo, podría buscar una similitud mayor o menor, y quizás factorizar una función para simplificar el código. El hecho de que se repitan una docena de líneas de código no significa que una función deba consistir en esa docena de líneas y no más.
Muy difícil de decir en abstracto Pero mi propia creencia es que incluso una línea de código duplicado debe convertirse en una función. Por supuesto, yo no siempre logro este alto nivel yo mismo.
No tolero ninguno. Puedo terminar teniendo algunas debido a limitaciones de tiempo o cosas por el estilo. Pero todavía no he encontrado un caso donde el código duplicado realmente está garantizado.
Decir que dañará la legibilidad solo sugiere que eres malo para elegir nombres :-)
Personalmente, prefiero mantener el código entendible, ante todo.
DRY se trata de facilitar el mantenimiento en el código. Hacer que el código sea menos comprensible para eliminar código repetido perjudica más la capacidad de mantenimiento, en muchos casos, que tener algunas líneas de código repetidas.
Dicho esto, acepto que DRY es un buen objetivo a seguir, cuando es práctico.
Realmente depende de muchos factores, cuánto se usa el código, legibilidad, etc. En este caso, si solo hay una copia del código y es más fácil de leer de esta manera, entonces tal vez esté bien. Pero si necesita usar el mismo código en un tercer lugar, consideraría seriamente refaccionarlo en una función común.
Refactorizar puede ser difícil, y esto depende del idioma. Todos los idiomas tienen limitaciones, y algunas veces una versión modificada de la lógica duplicada puede ser lingüísticamente más compleja que el código repetido.
A menudo, las duplicaciones de código LOGIC ocurren cuando dos objetos, con diferentes clases base, tienen similitudes en la forma en que operan. Por ejemplo, 2 componentes GUI que muestran valores, pero no implementan una interfaz común para acceder a ese valor. La refacturación de este tipo de sistema requiere que los métodos tomen más objetos genéricos de los necesarios, seguidos por la verificación de tipos y la conversión, o bien la jerarquía de clases debe ser repensada y reestructurada.
Esta situación es diferente a si el código se duplicó exactamente. No crearía necesariamente una nueva clase de interfaz si solo pretendía que se usara dos veces, y las dos veces dentro de la misma función.
Si el código en cuestión tiene un propósito claro de negocio o soporte de tecnología P, generalmente debe refactorizarlo. De lo contrario, tendrás el problema clásico con el código clonado: finalmente descubrirás la necesidad de modificar el código que soporta P, y no encontrarás todos los clones que lo implementan.
Algunas personas sugieren que 3 o más copias son el umbral para la refactorización. Creo que si tienes dos, deberías hacerlo; encontrar los otros clones (o incluso saber que podrían existir) en un gran sistema es difícil, ya sea que tenga dos o tres o más.
Ahora esta respuesta se proporciona en el contexto de no tener ninguna herramienta para encontrar los clones. Si puede encontrar clones de manera confiable, entonces la razón original para refactorizar (evitar los errores de mantenimiento) es menos perceptible (la utilidad de tener una abstracción con nombre sigue siendo real). Lo que realmente quieres es una forma de encontrar y rastrear clones; Resumirlos es una forma de asegurarse de que pueda "encontrarlos" (haciendo que la búsqueda sea trivial).
Una herramienta que puede encontrar clones confiablemente puede al menos evitar que cometas errores de mantenimiento al actualizar la clonación. Una de esas herramientas (yo soy el autor) es el CloneDR . CloneDR encuentra clones usando la estructura del lenguaje objetivo como guía, y encuentra clones independientemente del diseño del espacio en blanco, cambios en los comentarios, variables renombradas, etc. (Se implementa para un número en idiomas como C, C ++, Java, C #, COBOL y PHP ) CloneDR encontrará clones en sistemas grandes, sin recibir ninguna guía. Se muestran los clones detectados, así como el antiunificador , que es esencialmente la abstracción que podría haber escrito en su lugar. Las versiones de este (para COBOL) ahora se integran con Eclipse y te muestran cuándo estás editando dentro de un clon en un búfer, así como dónde están los otros clones, para que puedas inspeccionar / revisar los otros mientras estás allí. (Una cosa que podrías hacer es refactorizarlos :).
Solía pensar que la clonación era completamente errónea, pero la gente lo hace porque no saben cómo el clon variará del original, por lo que la abstracción final no está clara en el momento en que se produce el acto de clonación. Ahora creo que la clonación es buena, si puedes rastrear los clones e intentas refactorizar una vez que la abstracción sea clara.
Tan pronto como repites cualquier cosa , estás creando varios lugares para realizar ediciones si crees que has cometido un error, necesitas extenderlo, editarlo, borrarlo o cualquier otra docena de otras razones por las que podrías enfrentarte a eso. forzar un cambio
En la mayoría de los idiomas, extraer un bloque a un método adecuadamente nombrado rara vez puede perjudicar su legibilidad.
Es su código, con sus estándares, pero mi respuesta básica a su "¿cuánto?" es ninguno ...
no dijiste qué idioma, pero en la mayoría de los IDEs es un Refactor simple -> Método de extracción. Cuánto más fácil es eso, y un único método con algunos argumentos es mucho más fácil de mantener que 2 bloques de código duplicado.
Refactorización: mejorar el diseño del código existente
La regla de los tres
La primera vez que haces algo, simplemente lo haces. La segunda vez que lo haces
algo similar, muecas de dolor ante la duplicación, pero haces el duplicado
cosa de todos modos. La tercera vez que haces algo similar, eres refactor.
Tres golpes y tu refactor.
Seibel: Entonces, para cada una de estas XII llamadas estás escribiendo una implementación.
¿Alguna vez descubrió que estaba acumulando muchos trozos de código muy similar?Zawinski: Oh, sí, definitivamente. Por lo general, por la segunda o tercera vez que ha cortado y pegado
ese pedazo de código es como, bien, es hora de dejar de cortar y pegar y ponerlo en una subrutina.