¿Una defensa para repetitivo?

14

Para mí, el código repetitivo es obviamente malo. Sin embargo, he conocido a un desarrollador que muestra resistencia en cualquier intento de reducir la placa de calderas. Me di cuenta de que no tenía un argumento bien formado y bien pensado más allá del aborrecimiento que he desarrollado con el tiempo.

De modo que pueda formar un argumento convincente para favorecer menos repetitivo, ¿cuáles son algunos argumentos en contra? En otras palabras, ¿cuáles son los argumentos (si los hay) a favor de repetitivo?

(Me refiero a lo que creo que generalmente se entiende por repetitivo, pero un buen ejemplo son los que obtienen y configuran en Java).

    
pregunta abstracted 14.05.2012 - 20:52
fuente

7 respuestas

12

Una cosa importante para recordar es que el código generalmente se hace más pequeño al eliminar el contexto innecesario. Si el compilador puede resolver algo, el argumento continúa, no hay necesidad de escribirlo explícitamente.

Y eso sería genial si solo el compilador estuviera destinado a leerlo. Pero recuerde que "los programas deben escribirse para que la gente los lea, y solo de forma incidental para que los ejecuten las máquinas". (Irónicamente, esta cita proviene de de un libro de texto dedicado a uno de los idiomas más difíciles de leer para los seres humanos comunes, debido en gran parte a su excesiva suavidad.)

Lo que puede parecer aburrido y repetitivo para usted mientras lo escribe puede ser un contexto valioso para otra persona que llega un año (o cinco) más tarde y tiene que mantener su código.

WRT específicamente en el ejemplo de Java, estoy de acuerdo en que es un buen ejemplo de mala calidad, ya que puede reemplazarse por algo que es más corto y más fácil de leer, y también más flexible: Propiedades . Pero eso no significa que todos los elementos sintácticos de todos los lenguajes sean tan inútiles como los captadores y definidores de Java y C ++.

    
respondido por el Mason Wheeler 14.05.2012 - 21:05
fuente
7

Un argumento a favor del código repetitivo es que si lo cambias en un lugar, solo afecta a un flujo del código. Esto debe compararse con el hecho de que más a menudo que no, realmente desea que un cambio afecte a cada pieza de código que lo usa. Pero he visto ejemplos raros que apoyan el argumento.

Digamos que tienes un fragmento de código que dice

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Esto se usa en aproximadamente 2 lugares en tu código.

Un día alguien aparece y dice "bien, solo en este camino, queremos que grommitas la barra antes de manipularla".

Y piensas "bueno, esto es simple".

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Luego, su usuario agrega alguna nueva funcionalidad y cree que encaja bien con FooTheBar. Y les preguntas debidamente si deberías Grommit esa barra antes de que la Foo y dicen "no, no esta vez".

Así que solo llamas al método de arriba.

Pero tu usuario dice "ok, espera, en el tercer caso, queremos que dibujes la barra antes de llamar a BeFooed".

No hay problema, crees, puedo hacerlo.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

De repente, su código se está volviendo menos repetitivo. Quizás deberías haber aceptado las dos líneas de código repetidas. A estas alturas ya tendrías tres piezas de código, cada 2-3 líneas de largo y sin tener un aspecto muy repetido.

Dicho todo esto, yo diría que "este no es un caso común, y cuando sucede, puedes refactorizarlo".

Otro argumento que he escuchado recientemente es que el código repetitivo a veces puede ayudarlo a navegar por el código. El ejemplo que discutíamos era donde habíamos eliminado toneladas de código de mapeo repetitivo y lo habíamos reemplazado con AutoMapper. Ahora, se argumentó, porque todo está basado en convenciones, no se puede decir "dónde se encuentra esta propiedad" al IDE y esperar que se sepa.

He visto a personas argumentar cosas similares sobre los contenedores IoC.

No quiero decir que esté de acuerdo con ellos, pero es un argumento justo.

    
respondido por el pdr 14.05.2012 - 21:46
fuente
6

La evolución de la eficiencia

Empiezas con esto:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

luego te deshaces de todo lo molesto y lo pones en una función:

  1. createFieldHtml( id, label )

    esto es bueno, me estoy ahorrando tantas líneas!

  2. createFieldHtml( id, label, defaultValue )

    sí, también necesito un valor predeterminado, que fue fácil de agregar.

  3. createFieldHtml( id, label, defaultValue, type )

    genial, también puedo usarlo para las casillas de verificación

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    El diseñador de UX dice que la etiqueta debe estar después de la casilla de verificación.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    ahora muestra un selector de fecha cuando es necesario. Hm ... los params están un poco fuera de control

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    hubo un caso en el que necesito agregar clases CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

En defensa de repetitivo

Me cuesta mucho poner esto en palabras porque realmente es algo que he notado recientemente, así que haré una lista:

  1. Me parece que existe cierto temor de tener líneas duplicadas que se extiendan un poco. Si son solo unas pocas líneas, puede que no sea ningún problema. algunas cosas son inherentemente "casi repetitivas" (como el ejemplo anterior). Veo pocas posibilidades de optimizar allí a largo plazo.
  2. A la gente le encanta encapsular la funcionalidad en algún lugar; Si miras objetivamente y parece que solo se trata de "ocultar el desastre", ¡desconfía! podría ser el momento para un buen viejo reparto
  3. Cuando tienes una función que se vuelve más y más poderosa; eso toma muchos caminos de ejecución diferentes dependiendo de la entrada y, en última instancia, hace muy poco, ¡puede ser un tiempo de repetición!
  4. Cuando agrega una capa de abstracción sobre otra capa de abstracción, pero solo para hacer que su código sea más corto (la capa subyacente no debe cambiarse): ¡el tiempo de la placa de la caldera!
  5. Cuando tienes una función que toma tantos parámetros que realmente necesitas para tener parámetros con nombre, tal vez sea el momento de la repetición.

Una cosa que recientemente siempre me pregunto es esto:
¿Puedo copiar y pegar en otro proyecto sin cambiar nada? Si es así, está bien para encapsular o poner en una biblioteca, si no es así: es el momento de la repetición.

Esto se opone en gran medida a la percepción general de que boilerplate es copiar y pegar código. Para mí, repetitivo es sobre copiar y pegar, pero siempre hay que modificarlo un poco.

Actualización : acabo de encontrar un artículo que da a mi ejemplo anterior un nombre real: "anti-patrón demasiado SECO".

  

La función obtiene más parámetros y es cada vez más compleja.   Lógica interna para controlar su comportamiento en diferentes casos. Demasiado seco   Las funciones son fáciles de detectar. Tienen un montón de lógica intrincada si-entonces   que tratan de abordar una amplia diversidad de usos. [...] También, repitiendo   el código no siempre es malo si el código es pequeño y realiza una   Función discreta.

Es una lectura breve e interesante, puede encontrar el artículo aquí: Antipatrón demasiado seco

    
respondido por el kritzikratzi 15.05.2012 - 04:04
fuente
4

Desprecio el código de la placa de la caldera, pero ser capaz de eliminar el código de la placa de la caldera no siempre significa que esa es la mejor manera de hacerlo.

El marco de trabajo de WPF tiene propiedades de dependencia , que involucra una cantidad insana de código repetitivo. Durante mi tiempo libre investigué una solución que reduce mucho la cantidad de código que necesita ser escrito. Más de un año después, Sigo mejorando esta solución , y aún necesito extender en su funcionalidad o corregir errores.

¿Cuál es el problema? Esto es genial para aprender cosas nuevas y explorar soluciones alternativas, pero probablemente no sea la mejor decisión comercial .

El marco de trabajo de WPF está bien documentado. correctamente documenta cómo escribir su código de boiler. Intentar eliminar este código repetitivo es un buen ejercicio, y algo que definitivamente vale la pena explorar, pero lograr el mismo nivel de 'pulido' que ofrece msdn lleva mucho tiempo, lo que no siempre tenemos.

    
respondido por el Steven Jeuris 14.05.2012 - 21:34
fuente
1

El problema con boilerplate es que viola DRY. En esencia, cuando escribe repetitivo, está repitiendo el mismo código (o un código muy similar) en varias clases. Cuando ese código necesita ser cambiado, no es seguro en absoluto que el desarrollador recordará todos los lugares donde se repitió el código. Esto conduce a errores donde se utilizan API o métodos antiguos.

Si refactoriza la plantilla en una biblioteca común o clase principal, entonces solo necesita cambiar el código en un lugar cuando cambie su API. Más importante aún, cuando ocurren cambios inesperados, el código se rompe en un y le permite saber exactamente qué debe corregir para que todo funcione nuevamente. Esto es mucho más preferible a un escenario donde un cambio causa fallas en docenas, o incluso cientos de clases.

    
respondido por el quanticle 14.05.2012 - 21:15
fuente
0

Voy a tomar un tacto diferente. La consistencia en el desarrollo es una de las características más importantes del diseño de software, es una herramienta crítica para hacer que las aplicaciones sean extensibles y mantenibles, pero puede ser difícil de lograr al administrar un equipo en múltiples sitios, idiomas y zonas horarias.

Si se logra, la coherencia hace que el código sea mucho más accesible "una vez que haya visto uno, los haya visto todos", mucho más barato de mantener y refactorizar, pero sobre todo, mucho más fácil de extender. Cuando escribes una biblioteca que requiere un poco de repetición, junto con el poder de tu biblioteca, también le has dado al desarrollador:

  • Un punto de partida entiende el preámbulo (boilerplate) en su funcionalidad, la mayoría de las clases clave y los puntos de acceso generalmente aparecerán como parte de la boilerplate. Esto le da a los desarrolladores un punto de partida en la documentación
  • Expectativas su ubicación en los desarrolladores se hará evidente, por ejemplo, si configura un objeto de rastreo como parte del preámbulo, entonces los desarrolladores sabrán dónde registrar excepciones e información
  • Comprensión implícita a medida que obliga al desarrollador a pasar por el proceso de creación de instancias de clases, pueden inferir las técnicas que necesitarán para acceder al resto de su biblioteca y tener la oportunidad de presentarles las convenciones que usted desee. Lo he usado en toda tu biblioteca
  • Validación sencilla cuando se necesita su código de caldera, por lo general puede validarse fácilmente con excepciones y cláusulas de protección, evitando que los consumidores se atasquen mucho más cuando ya están comprometidos con un proceso defectuoso
  • La configuración de una biblioteca que requiere el código de repetición es fácil ya que ya existe un punto de implementación obvio para personalizar la funcionalidad para una única ruta de ejecución. Esto es particularmente útil si su código requerido está mejorado con el patrón de Fábrica o Comando

Cuando los consumidores de su biblioteca controlan la creación de instancias, pueden crear fácilmente métodos de extensión / privados, clases para padres o incluso plantillas para implementar el código de la plantilla.

    
respondido por el Dead.Rabit 05.12.2014 - 12:56
fuente
-3

El único problema real con el código de repetición es que cuando encuentra un error, debe corregirlo en todos los lugares en que lo usó en lugar de en el único lugar en el que reutilizó .

    
respondido por el Crazy Eddie 14.05.2012 - 23:27
fuente