¿Por qué es importante DRY?

81

Muy simple, ¿por qué querría escribir código que funcione para todos los casos y datos escalables cuando todo lo que necesito hacer es repetir el mismo proceso varias veces con algunos pequeños ajustes?

Es poco probable que necesite editar esto nuevamente en el corto plazo.

Parece mucho menos trabajo simplemente ir ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

Y si alguna vez necesito agregar algo ...

function doStuff4(){/*.d.*/}

Y si necesito eliminarlo, lo elimino.

Es más difícil descubrir cómo hacer que todo eso se convierta en un patrón directo en el que pueda alimentar datos y tratar todos los casos, y hacer un montón de cambios que no creo que vaya a tener. que hacer.

¿Por qué estar SECO cuando parece que un corte rápido + pegar va a ser mucho menos trabajo?

Incógnito
fuente
11
porque el secado aún es más rápido cuando lo haces bien, y qué pasa si cometiste un error en a. que afecta a todos los demás
Daniel Little
97
"Es poco probable que necesite editar esto nuevamente en el corto plazo" , puede esperar, pero lo más probable es que esté cometiendo un error aquí. Y si va a trabajar en ese código nuevamente, pero no tan pronto, solo empeorará las cosas; olvidará dónde están los duplicados, y los duplicados crecerán discrepancias sutiles pero traicioneras. "Escribe como si la persona que mantendría tu código es un loco loco que sabe dónde vives", para citar los clásicos.
9000
14
Creo que se puede resumir con: un único punto de cambio es más fácil de mantener.
Falcon
17
Si no puede responder esto usted mismo, necesita obtener más experiencia en el mundo real de desarrollo y mantenimiento.
David Heffernan
15
@Wayne Sentí una gran perturbación en la fuente, como si millones de programadores de repente gritaran de terror.
Incognito

Respuestas:

121

Si se repite, puede crear problemas de mantenimiento. Si doStuff1-3 tiene un código estructurado de manera similar y soluciona un problema en uno, podría olvidarse fácilmente de solucionar el problema en otros lugares. Además, si tiene que agregar un nuevo caso para manejar, simplemente puede pasar diferentes parámetros a una función en lugar de copiar y pegar en todo el lugar.

Sin embargo, DRY a menudo es llevado al extremo por programadores inteligentes. A veces, para no repetirse, debe crear abstracciones tan obtusas que sus compañeros de equipo no puedan seguirlas. A veces, la estructura de dos cosas es solo vagamente similar pero lo suficientemente diferente. Si doStuff1-4 es lo suficientemente diferente como para que refactorizarlos para que no se repitan, tendrás que escribir un código no natural o sufrir backflips de codificación inteligentes que harán que tu equipo te fulmine con la mirada, entonces puede estar bien repetirlo. Me he esforzado por no repetirme un par de veces de forma antinatural y lamenté el producto final.

Siempre me equivoco al lado de DRY, en el raro caso de repetirme cuando pienso que los beneficios de la legibilidad valen los riesgos de que alguien se olvide de corregir un error en varios lugares.

Teniendo en cuenta ese consejo, suena como en tu caso

repita el mismo proceso varias veces con algunos pequeños ajustes

Definitivamente trabajaría duro para no repetirme en su caso. Suponiendo "ajustes" mínimos: se pueden manejar con diferentes parámetros que afectan el comportamiento o tal vez se inyectan dependencia para realizar diferentes subtareas.

¿Por qué estar SECO cuando parece que un corte rápido + pegar va a ser mucho menos trabajo?

Últimas palabras famosas. Te arrepentirás de pensar que cuando un ingeniero junior modifica / repara / refactoriza un doStuff y ni siquiera se da cuenta de que el otro existe. Produce hilaridad. No se produce principalmente acidez estomacal. Cada línea de código cuesta más. ¿Cuántas rutas de código debe probar con tantas funciones repetidas? Si una función, solo tiene que probar una ruta principal con algunas modificaciones de comportamiento. Si está pegado, debe probar cada doStuff por separado. Lo más probable es que te pierdas uno y un cliente puede tener un error no deseado y es posible que tengas algunos correos electrónicos no deseados en tu bandeja de entrada.

Doug T.
fuente
2
Er, solo para que quede claro, no estoy proponiendo que seco sea malo, esta pregunta es más del abogado de los demonios. Realmente estoy buscando una respuesta lógica que pueda vincular a las personas que piensan que cortar + pegar + ajustar el código está bien.
Incógnito
2
Dicho esto, me gusta más su respuesta, ya que cubre ambas fallas en DRY: no molestar y exagerar, así como explicar los impactos. - Sobre el punto de sacrificar la legibilidad por errores, diría que el código repetitivo es menos legible por la misma razón que usted señala, donde es fácil perder la noción de las cosas.
Incógnito
16
Subrayaría una trampa fácil de DRY: código similar fusionado. Si tiene dos casos de uso que no están relacionados funcionalmente pero tienen un código muy similar, es fácil fusionar los dos porque DRY es bueno . Desafortunadamente, cuando uno necesita evolucionar, a menudo se encuentra con la desagradable tarea de tener que dividir la función una vez más, y luego pasar por todos los sitios de llamadas y considerar cuidadosamente cuál debería llamarse aquí ... Ejemplo: tipificación estructural LLVM (todos los tipos similares se fusionan en uno) hace que sea casi imposible asignar el IR al código original.
Matthieu M.
1
Bingo. Si se cambian dos o más piezas de código, y los cambios serán siempre los mismos para todas las piezas, entonces deben fusionarse. No debe fusionarse ninguna pieza que deba cambiarse de manera diferente a las demás. Si el código nunca cambiará en absoluto, no importa mucho si se fusionó o no. La cuestión de si los cambios deben bloquearse o desconectarse es mucho más importante que el tamaño del código en cuestión.
supercat
1
@MatthieuM es un ejemplo un poco injusto. LLVM está aplicando la tipificación estructural como una optimización ; es decir, la gente de LLVM decidió pagar el precio de IR difícil de entender por los beneficios de rendimiento. DRY suele ser un problema de mantenimiento, pero en este caso fue claramente una decisión deliberada para reducir el mantenimiento.
Benjamin Hodgson
47

Porque SECO será menos trabajo más tarde.


SECO: (No te repitas)

Una función tomando un argumento.

def log(arg):
    print(arg)

C&P: (copiar y pegar)

26 millones de funciones hacen esencialmente lo mismo, pero con una diferencia de 2 caracteres.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

¿Qué tal si actualizamos nuestra impresión para especificar qué es exactamente la impresión?

SECO:

def log(arg):
    print(arg + "Printed from process foo")

Hecho.

C&P:

Tienes que regresar y cambiar cada función .


¿Cuál crees que sería más fácil de depurar?

John
fuente
10
Además, debe escribir tantos conjuntos de pruebas similares como funciones duplicadas.
9000
Usted ha ilustrado el concepto adecuadamente, pero en la práctica nadie haría lo que describió con las funciones de millones, de ninguna manera de esa manera.
Robert Harvey
@Robert ¡Espero que no! Elegí una tarea muy simple para tratar de ilustrar mejor el concepto y por qué puede ser algo bueno.
John
11
@Robert: ¿has leído alguno de los artículos en thedailywtf.com ;)? Hay algunos por ahí que harían exactamente eso
HorusKol
1
@ 9000 No si no tiene ningún conjunto de pruebas: p (que en realidad podría ser el caso en algunos proyectos ... desafortunadamente ...)
Svish
16

Porque , aplicado a tu ejemplo:

  • + legibilidad

    Menos código a menudo se traduce en menos ruido . (no siempre...)

  • + flexibilidad

    Si alguna vez tuvo que cambiar el comportamiento de la doStuffX, querrá suicidarse o quien lo escribió,

  • + extensibilidad

    Si ha extraído las distintas partes de una estructura de datos de su elección y luego solo ha iterado sobre ella llamando a un genérico doStuff, también podría agregar una línea en su estructura de datos donde desea una nueva entrada, o eliminar una, y cambiar el comportamiento solo significará editar doStuff. Más fácil de mantener .

  • + rentabilidad

    menos código aquí significa:

    • => menos desarrollo => costo reducido
    • => menos probabilidad de errores => menos tiempo de soporte => costo reducido
  • + (posible) optimización gestionada

    Dependiendo del idioma, el compilador / intérprete podría tener una mayor probabilidad de determinar que el genérico doStuffhace siempre las cosas casi idénticas, a menudo una llamada tras otra, y podría alinearlo o intentar optimizarlo . Probablemente no para X variaciones de doStuffX.

  • + pruebas y calidad

    La prueba es más fácil: doStuffnecesita pruebas, y eso es todo. Bueno, no exactamente, pero eso ya cubre más . Solo sus expectativas de IO varían y deben probarse en diferentes condiciones, pero aún así es mucho más fácil de probar y más sostenible que todas las variaciones de doStuffX.

En general, esto representa un código más fácil de mantener y una eficiencia de desarrollo mejorada para su equipo, y es una de las muchas buenas prácticas para ayudarlo a producir software más robusto y confiable.

haylem
fuente
13

Como todos los demás han hecho un gran trabajo al explicar los problemas de mantenimiento con el código duplicado, solo diré esto:

Gran parte de la programación requiere que pienses en el futuro, no solo en el presente inmediato. Tiene razón en que copiar y pegar es más fácil ahora, pero la afirmación de que es poco probable que tenga que volver a editar esto en el corto plazo " muestra que no está pensando correctamente. Sí, puede ganar un poco de tiempo con un copiar y pegar rápido y sucio, pero al hacerlo, está demostrando que no puede mirar más allá de su problema inmediato y pensar en el mañana. ¿Está seguro de que nunca necesitará volver a visitar este código? ¿Sabe con certeza que hay ¿No hay errores? ¿Puede garantizar al 100% que no necesitará volver a visitarlo cuando necesite implementar su próximo conjunto de características? Esos son problemas para mañana y deben tenerse en cuenta cuando diseñe hoy.

Por supuesto, hay momentos en que será necesario copiar / pegar. Como desarrollador de UI, descubrí que hay ocasiones en que tengo que violar el principio DRY. Es una mierda, me estremezco cada vez que sucede, y afortunadamente, es raro. Pero no suceda.

La diferencia es que cuando se viola DRY, debe tener una razón muy convincente para hacerlo, y la afirmación: es más difícil descubrir cómo hacer que todo eso se convierta en un patrón directo no es realmente uno de ellos. A menos que esté bajo una crisis de tiempo masiva y haga que su jefe grite para obtener algo en las próximas horas o perderá su trabajo, no creo que esta sea una justificación válida.

No lo tomes a mal: no estoy tratando de castigarte o castigarte, sino de tratar de hacerte ver dónde está mal tu mentalidad. Los programadores invierten en la pereza futura; DRY es una forma de lograr eso. El trabajo que realiza hoy para resolver un problema de diseño difícil dará sus frutos mañana.

Bedwyr
fuente
No estoy seguro de estar de acuerdo con un jefe que te dice "hazlo o te despiden" es una buena razón para violar DRY. Deuda técnica, ¿cuándo tiene tiempo para hacerlo bien, es realmente un ahorro de tiempo, etc.?
Incógnito
1
@Incognito, estaba tratando de ser un poco irónico :)
bedwyr
7

Es poco probable que necesite editar esto nuevamente en el corto plazo.

Si este es realmente el caso, es posible que pueda salirse con la suya, pero la mayoría de las veces estará trabajando en un código que debe mantenerse. Eso significa ampliar la funcionalidad, corregir errores y otras mejoras. Si tiene pequeñas variaciones del mismo código en 10 lugares diferentes, y un día vuelve a ese código y necesita hacer un cambio, ahora tiene la tarea propensa a errores de hacer el mismo cambio en 10 lugares diferentes (Lo sentimos, hay fueron 11 lugares, olvidaste uno y ahora tienes un error).

Si puede generalizar qué problema está tratando de resolver, puede hacer que su código sea más fácil de extender y solucionar si aparecen errores.

Alex
fuente
Buena respuesta, pero incluso si me salgo con la suya, ¿qué pasa con la pobre savia que puede mantenerla después de mí? ;).
Incógnito
Ver: "la mayoría de las veces vas a estar trabajando en un código que debe mantenerse" :)
Alex
Incluso entonces, es solo el caso si lo que está copiando y pegando es una perfección 100% libre de errores. Y no lo es, y deja de pensar que podría ser.
Dan Ray
Admitiré que he copiado y pegado cosas en el pasado, pero nunca por nada me iba a quedar por más de un día. A veces solo necesitas un script de descarte rápido y sucio.
Alex
6

Como dije en la respuesta a otra pregunta, mi enfoque es el siguiente:

  1. La primera vez que resuelvo un problema determinado, lo hago.
  2. La segunda vez (es decir, cuando resuelvo un problema similar) pienso: hm, tal vez me estoy repitiendo, pero por ahora voy a copiar y pegar rápidamente.
  3. La tercera vez que pienso: hm, estoy repitiéndome -> ¡hazlo general!

Es decir, hasta 2, otro principio (YAGNI) gana a DRY. Pero a partir de 3 (¡o 4 si soy realmente vago!) Parece que lo voy a necesitar y por eso sigo SECO.

Actualizar

Algunas ideas adicionales de mi experiencia reciente. Tuve que adaptar / integrar dos componentes A y B desarrollados por otro equipo en nuestro producto. Primero: los dos componentes A yb B son muy similares entre sí, por lo que ya me molestó el hecho de que tenían una arquitectura algo diferente. Segundo: tuve que adaptarlos, así que me hubiera encantado usar subclases y anular solo lo que realmente necesitaba.

Así que comencé a refactorizar estos dos componentes (cada uno de los cuales consta de aproximadamente 8 clases de C ++): quería tener una arquitectura común para A y B, y luego agregar las características que necesitamos definiendo subclases. De esta manera, nuestros dos nuevos componentes A 'y B' se habrían derivado de los existentes.

Después de dos semanas tratando de obtener una estructura común y bien definida del código existente y de tener que explicar durante nuestras reuniones diarias que estaba progresando poco porque el código original era demasiado desordenado, hablé con mi jefe. Observamos que no necesitaríamos más que estos dos nuevos componentes A 'y B' (no iban a haber cuatro o seis de ellos, solo esos dos).

Ok, que así sea: hice una copia masiva y cambié el nombre de las clases de A y B y comencé a adaptar la copia del código. Lo puse a trabajar en dos semanas más (todavía estoy arreglando algunos errores).

Ventajas: Tenemos la funcionalidad casi terminada ahora y cuando hemos solucionado todos los errores, hemos terminado. Hemos guardado todas las refactorizaciones y pruebas de A y B.

Desventajas: Hace dos semanas, el otro equipo cambió otro componente C, que es usado por A y B. Adaptaron A y B, pero A 'y B' también se rompieron y tuvimos que cambiarlos nosotros mismos. Esto introdujo un nuevo error que tuvimos que corregir. Este trabajo adicional probablemente habría sido innecesario si A 'y B' hubieran compartido la mayor parte de su código con A y B.

Entonces: la duplicación de código siempre es peligrosa. Creo que siempre se trata de encontrar compensaciones y, a menudo, no es fácil.

Giorgio
fuente
5

Solo para aclarar, ya que no encuentro esto en ninguna de las otras respuestas:

DRY es un principio de desarrollo de software destinado a reducir la repetición de información de todo tipo .

Cada conocimiento debe tener una representación única, inequívoca y autorizada dentro de un sistema.

El principio DRY mencionado por Andy Hunt y Dave Thomas no se limita a evitar la duplicación de código. También aboga por la generación de código y cualquier proceso de automatización. Irónicamente, los resultados de la generación de código podrían incluso ser códigos duplicados ...

La razón por la que ya se ha explicado a fondo en las otras respuestas, pero el comentario de Falcon lo resume bastante bien en mi humilde opinión:

Un único punto de cambio es más fácil de mantener.

Steven Jeuris
fuente
Oh wow, pensé que la etiqueta tenía algunos datos. Pondré algo de información allí.
Incógnito
3

Hay demasiada SECA. Cuando esto sucede, dos conceptos que en algún momento parecen ser lo suficientemente similares como para justificar el código de factorización (1) pueden luego resultar lo suficientemente diferentes como para merecer implementaciones separadas.

En otras palabras, el acoplamiento SECO y suelto a veces entra en conflicto. Si espera que doStuff1 y sus amigos diverjan con cada nueva versión del software, está bien duplicar su código.

En mi experiencia, puede ser difícil juzgar hacia dónde se dirige su software en el futuro, y por esta razón, DRY es a menudo una opción segura.

El código que se ha "secado" en exceso generalmente tiene un flujo de control complejo y demasiados parámetros. Lo que inicialmente era una función simple se extendió más tarde para admitir una nueva funcionalidad controlada por un parámetro adicional. Después de dos o tres iteraciones, la función ya no se puede mantener. Soluciona un error que ocurre en una configuración e introduces nuevos errores en otras configuraciones.

Es comprensible que la calidad del código a menudo disminuya a medida que el código evoluciona, pero he visto casos en los que una función multiparamétrica con espagueti if-then-else en el cuerpo fue el resultado de un esfuerzo de refactorización bien intencionado pero mal realizado.

(1) Estoy usando la palabra "código", pero esto también se aplica al diseño.

Joh
fuente
Sería útil dar un ejemplo de "demasiado seco", ya que es el extremo menos visto del espectro.
incógnito el
@Incognito: he editado mi respuesta. No hay un ejemplo concreto, pero espero que lo que quise decir sea lo suficientemente claro.
Joh
2

Tengo que mencionar los problemas con DRY en el mundo de la base de datos relacional. Las bases de datos están diseñadas para funcionar de manera rápida y correcta mediante la lógica basada en conjuntos y mediante consultas que se pueden modificar. Los principios DRY a menudo hacen que el desarrollador escriba consultas no Sargable o use la lógica Row-by-agonizing-Row para aprovechar el código existente en múltiples situaciones. DRY y la optimización del rendimiento a menudo están en desacuerdo y, en el mundo de las bases de datos, el rendimiento suele ser mucho más crítico que la capacidad de mantenimiento. Esto no significa que no deba usar los principios DRY en absoluto, solo que debe ser consciente de cómo afectará la usabilidad general de la base de datos. Los desarrolladores de aplicaciones son SECOS en primer lugar y el rendimiento en segundo lugar, los desarrolladores de bases de datos piensan en primer lugar la integridad de los datos, el rendimiento en segundo lugar, la seguridad de los datos en tercer lugar (el rendimiento y la seguridad pueden cambiar de lugar en algunos sistemas).

En general, he notado que cuantas más capas de abstracción pongas en las consultas de la base de datos, más lentas se volverán. No estoy diciendo que no quisiera que las personas que diseñan los programas de la base de datos no hicieran un mejor trabajo al permitir que los desarrolladores usen DRY sin afectar lo bien que funciona la base de datos, pero no diseño software de base de datos a ese nivel , entonces quizás el conflicto entre la abstracción y el rendimiento en la base de datos es más difícil de arreglar de lo que supongo. Sin embargo, tenemos que trabajar con los sistemas tal como están construidos actualmente. Podemos pedir una mejor implementación de los principios de DRY en futuras versiones que también no afectarán el rendimiento (y ha mejorado a través de los años pero sigue siendo problemático), pero mientras tanto debemos considerar si DRY es el movimiento correcto para esta base de datos. en este momento.

Pero a menudo las mismas características que desea utilizar para garantizar el cumplimiento del principio DRY son las que causan tremendos problemas a la base de datos. No digo que nunca uses DRY, pero no te excedas.

Ejemplos de lo que estoy hablando. Debe importar un millón de registros una vez al mes. Los registros ya se pueden agregar manualmente a través de la interfaz de usuario llamando a un proceso almacenado. Este proceso, debido a que fue diseñado para importar registros únicos, solo agrega un registro a la vez. Usando DRY para evitar tener el código de inserción en dos lugares, escribe un cursor para llamar al proceso repetidamente en lugar de escribir las importaciones basadas en conjuntos que necesita. El tiempo para la importación va de los 30 minutos que tomaría usar la lógica basada en conjuntos a 18 horas. Ahora, la forma correcta de adherirse a DRY en este caso sería arreglar el proceso para manejar múltiples importaciones de registros. Desafortunadamente, a menudo es imposible o muy difícil enviar una matriz a un proceso (dependiendo del back-end de db) y al cambiar el proceso, terminas rompiendo la aplicación.

Las funciones escalares y las funciones con valores de tabla también se utilizan para implementar los principios DRY y, una vez más, pueden afectar seriamente el rendimiento, especialmente si necesita usarlas de una manera que evite que los índices sean útiles.

Las vistas también son buenas para implementar DRY. Sin embargo, si implementa DRY mediante el uso de vistas que llaman vistas que llaman a otras vistas, llegará rápidamente al punto en que las consultas se agotarán bajo carga. De hecho, puede terminar necesitando generar conjuntos de datos de millones de registros cuando solo necesita tres al final. Por lo tanto, una vista de un nivel de un conjunto complejo de combinaciones para implementar DRY puede ser excelente (yo mismo tengo una que usamos para asegurarnos de que todos los informes financieros usen el mismo conjunto de tablas y cálculos de ciertas cosas), más de dos niveles y debe considerar si está creando un desastre de rendimiento.

HLGEM
fuente
1

No veo los puntos clave de mi respuesta arriba, así que aquí va. No mires DRY tanto como una regla contrahaciendo algo. Puede estar redactado de esa manera, pero realmente puede servir a un propósito bastante diferente y positivo. Es una señal para detenerse, pensar y encontrar una mejor respuesta. Me reta a buscar oportunidades para diseñar una mejor solución. Es el lado bueno de un mal olor en mi código lo que me induce a repensar mi diseño y me hace hacerlo mucho mejor. DRY no se trata solo de una infracción de sintaxis bitty bitty. Me reta a modularizar. Me reta a hacer componentes. Señala la repetición que me recuerda pensar en usar plantillas y generación de código en lugar de la fuerza bruta y la ignorancia. Me ayuda a descubrir que debería encontrar algo de tiempo para automatizar mi automatización. ¡Te lleva a un estilo de vida parsimonioso! Le ayuda a pasar más tiempo haciendo cosas nuevas y geniales en lugar de detalles aburridos y viejos. ¡Y te da buenos modales, buen aliento y un estilo de vida saludable! Bueno, tal vez me extravío un poco ...

John Tobler
fuente
DRY tiene efectos muy diferentes en mí, sin embargo, si estos son sus efectos en usted, prefiero la filosofía de que algo sea "una señal para detenerse, pensar y encontrar una mejor respuesta", y el desafío.
n611x007
1

Tengo un antiguo proyecto heredado, donde a algunos de los desarrolladores anteriores no les importaba DRY en absoluto. Entonces, toda la base de código estaba abarrotada de métodos auxiliares como GetSystemTimeAsString (), LogToFile () y muchas otras cosas. Algunos métodos fueron ligeramente personalizados para necesidades especiales, pero la mayoría fueron solo copiar y pegar.

Desafortunadamente, algunos de los métodos tenían errores sutiles como la matriz de caracteres no lo suficientemente largos en algunos casos, usando cosas inseguras como strcpy (), etc.

Por lo tanto, fue una verdadera PITA encontrar todos los fragmentos de código, armonizarlos y corregir los errores. Y todavía estamos armonizando y arreglando cosas.

Nunca se sabe, si cometió un error en su primer método y luego tuvo que arreglarlo varias veces, porque acaba de copiarlo. Y si desea utilizar algunos de los métodos más adelante, ¿cómo sabe cuál de los 5 métodos en la base de código es el adecuado para su caso ahora? Así que solo copia uno, personalízalo y aquí comienza de nuevo ...

Simon
fuente
1

Sí, no se preocupe por DRY si está escribiendo un código desechable .

Pero DRY es importante, por supuesto, si planea mantener el código.

Pacerier
fuente
1

La fraseología "no te repitas" es un poco simplista. Lo importante es "evitar tener una pieza de información potencialmente modificable encapsulada en dos lugares independientes ".

Si se supone que un programa procesa widgets, cada uno con tres woozles, y son muchos bucles de la forma

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

entonces la expectativa de que se espera que los widgets contengan tres woozles se encapsularía en cada uno de esos bucles, y actualizar el código para acomodar cualquier otro número de woozles por widget podría ser difícil. Por el contrario, si uno dijera

#define WOOZLES_PER_WIDGET 3

y cada ciclo fue reescrito

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

Tal diseño podría hacer que sea muy fácil cambiar el número de woozles por widget.

Sin embargo, es importante tener en cuenta que si bien es deseable consolidar información como el número de woozles por widget en un solo punto, no siempre es práctico. A veces puede ser necesario codificar la lógica, que solo funcionará si las cosas son de un tamaño particular. Por ejemplo, si cada woozle tiene un valor y uno quiere encontrar la mediana asociada con un widget en particular, puede ser posible ordenar los valores y tomar el medio, y este enfoque funcionaría con cualquier número de woozles, pero la lógica que está escrito a mano específicamente para encontrar la mediana de tres elementos podría ser significativamente más rápido.

Si bien tener una constante WOOZLES_PER_WIDGET puede hacer que el código sea más legible, debe comentarse para dejar en claro que su valor no se puede cambiar sin realizar otros ajustes en la lógica del programa. En ese caso, la lógica que está codificada para tres elementos y la constante WOOZLES_PER_WIDGET estaría duplicando la información "cada widget tiene tres woozles", pero los beneficios de tal duplicación (mayor velocidad de ejecución) podrían superar el costo.

Super gato
fuente
0

Si bien estoy de acuerdo con los comentarios de otros pósters sobre mantenibilidad, etc., todos los cuales son válidos.

Me gustaría agregar una pequeña voz disidente al debate.

  • Solo es importante para los programadores. A las personas que pagan su salario no les importa si el software pasa UAT.
  • En términos de importancia, se ubica muy por debajo de los elementos, como obtener los requisitos correctos, escuchar a los patrocinadores del proyecto y entregar a tiempo.
James Anderson
fuente
Como este sitio es para "Programadores", creo que es seguro decir que la pregunta se dirige al "punto de vista de los programadores". Sus declaraciones sobre los contribuyentes, UAT y el rango de importancia son válidas, por supuesto, pero no son relevantes para esta pregunta específica.
ozz
1
Estoy en total desacuerdo. La buena gestión comprenderá los principios y por qué se están haciendo si se explica en detalle. Esto debería ser una conversación seria y profunda, no una caída de 5 minutos por cosa.
Michael Durrant
2
Su segundo punto es completamente correcto.
Jim G.
1
@Ozz, el orgullo en su oficio es importante incluso necesario para un buen programador, pero, tal vez el "punto de vista de los programadores" debería incluir un mínimo de preocupación por la "satisfacción del cliente".
James Anderson
0

<tl;dr>

No pude leer todas las respuestas repetidas, por lo que es posible que me haya perdido algo (y lo repetiré yo mismo <= ¿ves lo que hice aquí?).

¡Aquí está la lista de cosas que son increíbles para prevenir la duplicación de código!

  1. Más fácil de probar: solo necesita probar una 'copia' del código.
  2. Más fácil de arreglar: solo necesita encontrar el error en una 'copia' del código y arreglarlo una vez.
  3. Más fácil de actualizar (igual que arriba): los cambios necesarios, a menudo se pueden manejar modificando el código en muy pocos lugares porque se tomó el tiempo para reutilizar el código correctamente y no copió las mismas líneas en cientos o miles de lugares diferentes en la fuente.
  4. Más fácil de reutilizar: cuando (no está duplicado en algunos lugares) y se mantiene en métodos genéricos con un nombre apropiado, es fácil encontrarlos y usarlos en lugar de escribir el suyo.
  5. Más fácil de leer: el código duplicado es difícil de leer porque es innecesariamente detallado; contiene muchas líneas que no son parte de la lógica y la funcionalidad específica prevista (por ejemplo, comandos genéricos utilizados para configurar el escenario para que tenga lugar la acción o tareas genéricas simples repetidas que se necesitan en muchos lugares). El código limpio hace que la lógica y la funcionalidad se destaquen porque no hay repetición en el espacio de código.
  6. Más fácil de depurar debido a (1) y (5).
  7. Le ahorra tiempo y dinero y hace más cosas divertidas en el futuro; específicamente crea un código mejor y más robusto. Esta es la conclusión y es un resumen de casi todo lo anterior. Si mucha gente usa la misma función doFoo1(a, b), hay una mejor posibilidad de que muchas de sus molestas fallas y casos extremos se descubran y resuelvan. Si todos copian el código y crean doFoo2(specialA)... doFuu2^n(a, b, c)entonces duplicaron los problemas doFoo1y concretamente crearon mucho más trabajo.

</tl;dr>

Versión larga:

El problema con la duplicación de código es que "crece exponencialmente" (en otras palabras, se expande rápidamente) porque cuando duplica el código, sin saberlo, otorga permiso a otros (por ejemplo, ya no está en posición de juzgarlos) y los animas a hacer lo mismo. También hace que sea más difícil no hacerlo porque es más difícil detectar y reutilizar código útil cuando hay muchas repeticiones redundantes confusas en la fuente. Especialmente si el código aún no se extrae en una función con el nombre adecuado. Entonces, si enfrenta un problema común simple de resolver, es probable que escriba usted mismo un código que lo resuelva ... Y probablemente no podrá verificar algunos casos extremos, agregando más código no probado con errores.

Otra cosa es que para un novato esto puede sonar como un problema que solo afectará a las grandes empresas, pero descubrí que afecta a las pequeñas empresas de manera muy grave (como en 10,000 líneas de código duplicado del lado del servidor). Es un estado mental. No solo debes dominar DRY, sino esforzarte por alentar a otros a hacer lo mismo; porque de lo contrario te condenarás a la mayoría del código duplicado. Cuando los medios de DRY están a la mano y se aplican, es mucho más fácil aplicarlos. Cuando hay mucho código duplicado, es mucho más fácil aplicar soluciones de copiar y pegar.

Cosas que encuentro dañinas en la duplicación de código:

  1. ¿Es esta función utilizable? Digamos que encuentra una función que hace (o parece que hace lo que necesita), cómo sabe si incluso se supone que funciona correctamente o si es solo un código que se ha duplicado y abandonado.
  2. Código redundante A veces las personas duplican el código, lo usan y lo olvidan (siempre pueden duplicarlo nuevamente en el futuro). En algún momento, alguien elimina las llamadas a la función duplicada en algunos lugares en un esfuerzo por refactorizar, pero la función no utilizada permanece incluso si no se está utilizando activamente.
  3. Difícil de encontrar lo que estás buscando. El código duplicado ocupa espacio y hace que encontrar cosas útiles y necesarias (usando herramientas como grep) sea una tarea más difícil de lo que tiene que ser, ya que obtiene docenas o miles de resultados donde debería haber obtenido solo un puñado.
  4. (Se ha mencionado antes): difícil de mantener pero también difícil de usar para fines de mantenimiento y regresión. Si el código de prueba se duplica y no se extrae correctamente en las funciones, otros lo duplicarán. ¿Alguien se molestará en escribir una API fácil de usar y fácil de leer para mejorar la calidad de vida? En mi experiencia, no, a menudo hay algo que las personas consideran más urgente hasta que se les va de las manos.
  5. La duplicación de código es más difícil de leer porque hace que el código sea detallado donde no tiene que estar, en lugares donde la verbosidad no agrega información sobre la funcionalidad prevista: por ejemplo, llamadas a métodos genéricos que se utilizan [una y otra vez] para Sentar las bases para múltiples tipos de funcionalidad prevista, hace que sea más difícil que esta funcionalidad real aparezca.
  6. Esto se ha mencionado mucho. Si el código es incorrecto, alguna chica o chico pobre tendrá que buscar y cambiar cada uso de ese código. Por ejemplo, si alguien usó una llamada insegura de inyección SQL a mysql_query en muy pocos lugares en una Clase organizada donde se necesita, sería fácil arreglarlo y usar PHP PDO en su lugar, pero si lo usaran en más de mil lugares copiando la llamada y una vez más, solucionarlo prácticamente necesitará ser subcontratado o, a veces, de manera más peligrosa, el código deberá reescribirse desde cero.
  7. Duplicar código es un mal hábito. Si practicas algo, lentamente se convierte en una segunda naturaleza y afecta a las personas que te rodean. Los desarrolladores junior ven que tú también lo haces. Debes practicar lo que predicas y acostumbrarte a hacer lo correcto. Aprendes más. Escribir código no duplicado es más difícil y más desafiante. Es un hábito gratificante.

Últimas notas sobre la prevención de duplicación de código demasiado entusiasta y resumiendo las cosas:

Esto también se ha dicho antes, pero a veces evitar la duplicación hace que te "inclines hacia atrás" y hagas cosas que son demasiado sofisticadas (o sin importancia) para que otros las entiendan. Escribir código ilegible (o como lo llamamos en broma código de "preservación del trabajo") es un problema en sí mismo, incluso cuando no se trata de evitar la duplicación de código. Sin embargo, creo que si se inculca la infraestructura correcta y las mejores prácticas desde el principio, es mucho más fácil evitar la duplicación de código y las personas a menudo pueden evitar hacer cosas poco intuitivas para evitar futuros montones innecesarios e ilegibles de trabajo realizado para la prevención de la duplicación de código si haces las cosas bien desde ese principio.

¿Qué está haciendo las cosas bien? Bueno, esa es una pregunta difícil de responder, pero una cosa es definir qué métodos son necesarios para el proyecto y ver lo que ya ha sido implementado por otros (fuera y) dentro de la empresa y reutilizarlo cuando sea posible; documentando todo lo que agregas a la base de código e intentando que sea una muesca más genérica de lo que tiene que ser, pero eso es todo. No exagere los patrones de diseño solo para hacer que el código sea flexible donde no es necesario.

Wolfdawn
fuente