¿Una defensa para repetitivo?

14

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

Para poder 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 es getters y setters en Java).

abstraído
fuente
77
Argumentos contra el código duplicado (suponiendo que la placa de referencia esté copiada / pegada): stackoverflow.com/a/2490897/1583
finalizada
1
@Oded: Eso es correcto. Pero leíste mal la pregunta. :) Está intentando buscar si hay algo que decir sobre el código repetitivo. Supongo que está muy bien informado sobre las desventajas.
Steven Jeuris
3
@ StevenJeuris - Leí la pregunta perfectamente. Por eso no publiqué una respuesta. Solo estoy agregando al otro lado del argumento. Así, el OP tiene "un argumento bien formado y bien pensado más allá de la aborrecimiento que he desarrollado para él con el tiempo" para la próxima vez;)
Finalizado
2
Boilerplate puede ser estéticamente agradable: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic
Varias buenas respuestas y comentarios que se complementan entre sí ... difícil elegir cuál aceptar.
abstraído

Respuestas:

15

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, dice el argumento, no hay necesidad de escribirlo explícitamente.

Y eso sería genial si solo el compilador tuviera la intención de leerlo. Pero recuerde que "los programas deben escribirse para que la gente los lea, y solo de manera incidental para que las máquinas los ejecuten". (Irónicamente, esta cita proviene 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 terquedad).

Lo que puede parecer aburrido y repetitivo 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.

Específicamente el ejemplo de Java, estoy de acuerdo en que es un buen ejemplo de repetitivo malo, ya que puede ser reemplazado por algo que sea 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 repetitivos de todos los lenguajes sean tan derrochadores como los captadores y establecedores de Java y C ++.

Mason Wheeler
fuente
77
Por supuesto, este argumento funciona en ambos sentidos. Una cantidad considerable de código repetitivo solo está ahí para apaciguar al compilador y no ayuda a los humanos a comprender: para mantenerse con captadores / establecedores, esas docenas de líneas deben leerse por completo para asegurarse de que "esos no son nada captadores y establecedores" , en lugar de leer una sola línea corta por propiedad que simplemente establece que es una propiedad y qué tipo tiene.
66
Creo que repetitivo es perjudicial para el lector humano también. Al ser forzados a escribir texto repetitivo y sin sentido, estamos ocultando las partes relevantes del código de otras personas. Si algo es útil, entonces, por definición, no es repetitivo.
Andres F.
1
@ Jorge: Por el contrario, es mucho más que mi opinión; Es la opinión de la gran mayoría de las personas que han tratado de estudiarlo. Y cuando "difícil de leer" es inherentemente una cuestión de opinión en primer lugar, el hecho de que esa opinión sea tan ampliamente compartida lo convierte en un hecho.
Mason Wheeler
1
@Mason Wheeler: La forma en que las personas perciben los lenguajes de programación a menudo está influenciada por su experiencia pasada. Las personas que aprendieron a programar en Scheme encuentran que C o Pascal son torpes y difíciles de leer. Por otro lado, la gran mayoría de las personas aprendieron a programar en un idioma convencional.
Giorgio
2
Soy de la opinión de que cuando se oculta más contexto al programador al eliminar la repetitiva, eso solo significa que el Humano tiene que mantener un mapa mental más grande de todas las cosas que pasan sin ser vistas detrás de escena Y eso es un detrimento mayor cuando se trata de depuración que ahorrar un poco de espacio visual al crear.
Patrick Hughes
7

Un argumento a favor del código repetitivo es que si lo cambia en un lugar, solo afecta a un flujo del código. Esto tiene que equilibrarse con el hecho de que, en la mayoría de los casos, realmente desea que un cambio afecte a cada fragmento de código que lo utiliza. Pero he visto ejemplos raros que respaldan el argumento.

Digamos que tienes un código que dice

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

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

Un día aparece alguien y dice "ok, solo en este camino, queremos que Grommit la barra antes de engañarlo".

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 algunas nuevas funcionalidades y cree que encaja bien con FooTheBar. Y obedientemente les preguntas si deberías Grommitar esa barra antes de que la engañes y te dicen "no, no esta vez".

Entonces simplemente llama al método anterior.

Pero luego su usuario dice "ok, espere, en el tercer caso, queremos que gane Doodle the Bar antes de llamar a BeFooed".

No hay problema, piensas, puedo hacer eso.

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. Tal vez debería haber aceptado las dos líneas repetidas de código. A estas alturas, tendría tres piezas de código, cada una de 2 a 3 líneas de longitud y ya no parecería muy repetida.

Dicho todo esto, lo contrarrestaría con "este no es un caso común, y cuando sucede, puede refactorizar".

Otro argumento que escuché recientemente es que el código repetitivo a veces puede ayudarlo a navegar por el código. El ejemplo que estábamos discutiendo fue donde eliminamos toneladas de código de mapeo repetitivo y lo reemplazamos con AutoMapper. Ahora, se argumentó que, dado que todo está basado en convenciones, no puede decir "¿Dónde está establecida esta propiedad?" Al IDE y esperar que lo sepa.

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

No quiere decir que estoy de acuerdo con ellos, pero no obstante es un argumento justo.

pdr
fuente
2
Preferí la segunda parte de tu respuesta. ; p +1
Steven Jeuris
solo date cuenta de que mi ejemplo es bastante similar al tuyo ... supongo que incluso si no tiene sentido común parece que sucede bastante :)
kritzikratzi
6

La evolución de la eficiencia.

Empiezas con esto:

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

entonces te deshaces de todo ese molesto repetitivo y lo pones en una función:

  1. createFieldHtml( id, label )

    esto es bueno, me estoy ahorrando muchas 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, ahora también puedo usarlo para casillas de verificación

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

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

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

    ahora representa un selector de fecha cuando sea necesario. Hm ... los params se están yendo un poco de las manos

  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 resulta difícil poner esto en palabras porque es algo que he notado recientemente, así que haré una lista:

  1. Me parece que existe cierto temor a tener líneas duplicadas que se extienden un poco. Si solo son unas pocas líneas, puede que no haya 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 observas objetivamente y parece que es solo "ocultar el desastre", ¡sospecha! podría ser el momento para un buen viejo repetitivo
  3. Cuando tienes una función que se vuelve cada vez más poderosa; eso toma muchas rutas de ejecución diferentes dependiendo de la entrada y, en última instancia, hace muy poco, ¡podría ser un momento repetitivo!
  4. Cuando agrega una capa de abstracción encima de otra capa de abstracción, pero solo para acortar su código (la capa subyacente no está destinada a ser cambiada) - ¡tiempo de repetición!
  5. Cuando tiene una función que toma tantos parámetros que realmente necesita tener parámetros con nombre, tal vez es hora de repeticiones.

Una cosa que siempre me pregunto es:
¿Puedo copiar y pegar en otro proyecto sin cambiar nada? en caso afirmativo, está bien encapsular o colocar en una biblioteca, en caso negativo: es hora de repeticiones.

Esto es muy opuesto a la percepción general de que repetitivo es copiar y pegar código. Para mí, repetitivo se trata de copiar y pegar, pero siempre tener que modificarlo un poco.


Actualización : acabo de encontrar un artículo que da a mi ejemplo arriba un nombre real: "antipatrón demasiado SECO".

La función obtiene más parámetros y tiene una lógica interna cada vez más compleja para controlar su comportamiento en diferentes casos. Las funciones demasiado SECAS son fáciles de detectar. Tienen un montón de intrincadas lógicas si-entonces que intentan abordar una amplia diversidad de usos. [...] Además, repetir código no siempre es malo si el código es pequeño y realiza una función discreta.

Es una lectura corta e interesante, puede encontrar el artículo aquí: Anti-Pattern Too Dry

kritzikratzi
fuente
1
"Cuando agrega una capa de abstracción encima de otra capa de abstracción, pero solo para acortar el código" Es cierto, solo debe agregar capas de abstracción cuando existe la posibilidad de reutilización.
Steven Jeuris
44
+1. No te repitas, pero no te esfuerces demasiado para evitar casi repetirte.
Julia Hayward
4

Me desprecian código repetitivo, pero ser capaz de eliminar el código repetitivo no siempre quiere decir que es el mejor camino a seguir.

El marco WPF tiene propiedades de dependencia , lo que implica una cantidad increíble de código repetitivo. Durante mi tiempo libre , investigué una solución que reduce en gran medida la cantidad de código que debe escribirse. Más de un año después , sigo mejorando esta solución y aún necesito ampliar su funcionalidad o corregir errores.

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

El marco WPF está bien documentado. Es adecuada documenta cómo escribir el código repetitivo. 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.

Steven Jeuris
fuente
Sin embargo, todavía estoy bastante contento con el resultado que tengo en este momento, y con mucho gusto lo uso en mis proyectos de tiempo libre. :)
Steven Jeuris
3
Cada vez que toco WPF y esas propiedades de dependencia, siempre termino deseando que C # tenga algo tan simple como las macros de C ++. Claro que se abusan de las macros en manos equivocadas, pero podrían eliminar tantas repeticiones aquí. Tendré que echar un vistazo a su marco de AOP la próxima vez que comience a desear esas macros :)
DXM
@DXM Si lo hace, y se bloquea miserablemente, no olvide culparme y publicar los errores. ; p
Steven Jeuris
El fragmento de código me funcionó bastante bien para las propiedades de dependencia.
Codismo
@Codism: Bueno, son una solución, pero también los desprecio . :)
Steven Jeuris
1

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

Si refactoriza la plantilla estándar en una biblioteca común o clase principal, entonces solo necesita cambiar el código en un lugar cuando cambia su API. Más importante aún, cuando ocurren cambios inesperados, el código se rompe en un solo lugar y le permite saber exactamente lo que tiene que arreglar para que todo vuelva a funcionar. Esto es preferible a un escenario donde un cambio causa fallas en docenas, o incluso cientos de clases.

cuantícula
fuente
2
¿Cómo es esto un argumento a favor de repetitivo ?
Chris Wesseling
0

Voy a tomar un tacto diferente. La coherencia 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 consistencia hace que el código sea mucho más accesible "una vez que haya visto uno, los haya visto a 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 algo repetitivo, junto con el poder de tu biblioteca, también le has dado al desarrollador:

  • Un punto de partida comprende el preámbulo (repetitivo) en su funcionalidad, la mayoría de las clases clave y los puntos de acceso generalmente aparecerán como parte del repetitivo. Esto proporciona a los desarrolladores un punto de partida en la documentación.
  • Las expectativas de su ubicación en los desarrolladores se harán evidentes, por ejemplo, si configura un objeto de rastreo como parte del preámbulo, los desarrolladores sabrán dónde registrar las excepciones y la información.
  • La comprensión implícita al forzar al desarrollador a pasar por su proceso de instanciación de clases, puede inferir las técnicas que necesitará para acceder al resto de su biblioteca y tener la oportunidad de presentarle cualquier convención que haya utilizado en toda su biblioteca.
  • Fácil validación cuando se necesita su código repetitivo, por lo general, puede validarse muy fácilmente con excepciones y cláusulas de protección, evitando que los consumidores se atasquen mucho más adelante cuando ya está comprometido con un proceso defectuoso
  • La configuración de una biblioteca que requiere código repetitivo 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 repetitivo requerido se mejora con el patrón Factory o Command

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

Dead.Rabit
fuente
-3

El único problema real con el código repetitivo es que cuando encuentras un error en él, tienes que arreglarlo en todas partes donde lo usaste en lugar del único lugar que reutilizaste .

Edward extraño
fuente