Código de fantasía corto comentado versus código más fácil de entender sin comentar, ¿cuál es el preferido?

18

A veces, un algoritmo se puede escribir de dos maneras:

  • El camino corto y elegante; o
  • La forma más larga y fácil de entender.

Por ejemplo, aquí es un camino más largo, más fácil de copiar una cadena sourceque desten C:

*dest = *source;
while (*source != '\0') {
    source++;
    dest++;
    *dest = *source;
} (true);

Y aquí hay una forma corta y elegante.

// Copy string source to dest
while (*dest++ = *source++);

Siempre he escuchado y leído que se debe evitar el código elegante, y tiendo a estar de acuerdo. Pero, ¿qué pasa si tomamos en cuenta los comentarios? Supongamos que, como en los ejemplos anteriores, tenemos un código no comentado, más largo y supuestamente más fácil de entender, y un código bien comentado, corto y elegante. ¿Todavía se prefiere el código no elegante?

EDITAR: Muchos han comentado los nombres de las variables, por lo que he modificado el código de ejemplo para que no sea un factor al preferir sobre el otro. Traté de eliminar la doble asignación en el primer ejemplo, pero eso solo hizo que el código fuera menos legible.

Quizás este no fue el mejor ejemplo porque muchos encuentran que el código 'elegante' es más legible y comprensible que el código más largo. La idea era tener un código más largo que fuera mucho más fácil de entender que un código muy corto pero complicado.

EDIT2: Aquí hay un nuevo examen que obtuve de SO :

Versión de lujo comentada:

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Versión larga no comentada:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}
gablin
fuente
2
@gablin: "bueno" es una palabra, pero es un adjetivo con un significado algo diferente de "bueno", y ya no se usa ampliamente (al menos en los EE. UU.) La forma del adverbio de "bueno" es "bueno" como en "código bien comentado".
John M Gant
@ John: Ah sí, por supuesto. He actualizado la pregunta en consecuencia. Gracias.
gablin
2
¿De qué manera es 'elegante' el camino corto? Esa es una pieza de código C de un libro de texto que cualquier persona que afirme conocer C debería poder leer sin ningún problema. La terquedad no significa 'fantasía'.
JBRWilkinson
@JBRWilkinson: Como dije en la parte modificada de la pregunta, este ejemplo no es bueno ya que la versión "elegante" aparentemente no es tan elegante. El objetivo era tener una forma corta pero no comprensible con comentarios y luego una forma más larga pero mucho más legible sin comentarios.
gablin
@gablin: Tu edición compromete las respuestas actuales.
Maniero

Respuestas:

28

Generalmente preferiría extraer el código elegante en su propio método.

En lugar de comentar el código elegante, el nombre del método debería ser todo lo que necesita para aclarar las cosas.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}
Mongus Pong
fuente
3
Gran punto Factorizar el código autónomo es mucho mejor que los comentarios. El compilador sabe cómo alinearlo si es necesario.
dbkk
Ah sí, esa es una excelente manera de hacer que el comentario sea obsoleto. Pero a pesar de esto, ¿preferirías siempre el código elegante sobre el código más largo?
gablin
En general si. Siento que los métodos cortos y bien nombrados hacen que el código sea más fácil de leer y mantener. La complejidad incluida en sus propios métodos hace que la reutilización sea más accesible y aparente. Siempre hay excepciones aunque, en última instancia, siempre depende del código.
Mongus Pong
¿Seguramente su función debería llamarse 'strcpy'?
JBRWilkinson
Hay un error en ese fragmento de código. ¿Qué se devuelve? ¿Qué se suponía que debía devolverse? Sólo lo hacen un método vacío y acabar de una vez;)
Cristiano Mann
10

Estoy a favor de la versión más larga. El problema con la versión corta del código, además de que es más difícil de leer para algunos programadores, es que la mayoría de las veces es más difícil detectar errores con solo mirarlo.

Tengo un ejemplo de la vida real. En nuestro producto teníamos el siguiente fragmento de código:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

Este código parece perfectamente razonable a primera vista, pero después de un largo período de tiempo, este contador se desborda y rompe la condición (en el escenario de la vida real aplastamos el sistema de producción de nuestro cliente con un OOM). Este código es un poco menos "sofisticado", pero está claro que hace lo que se supone que debe hacer:

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

Y puede decir que el desarrollador que escribió este código simplemente no era lo suficientemente bueno (lo cual no es cierto, era un tipo bastante brillante), pero creo que si su técnica de codificación requiere que sea un experto en programación GOD Para obtener su código correcto, está haciendo algo mal. Su código debe ser tan infalible como sea posible por su bien y por quien tenga que mantener este código después de usted (que puede no ser tan inteligente como usted).

Entonces, estoy a favor de la simplicidad y la claridad.

Editar: Ah, y con respecto a los comentarios, no importa. Muchas personas no leerán comentarios de todos modos ( http://www.javaspecialists.co.za/archive/Issue039.html ) y aquellos que no entiendan su código sin comentarios, no lo entenderán lo suficientemente bien con ellos para que puedan puede mantenerlo El objetivo es ayudar a las personas a ver que cierto código es "correcto", los comentarios no pueden ayudar con eso.

Hila
fuente
1
"aplastó el sistema de producción de nuestro cliente" - eso es bastante malo: -S
"El problema con la versión corta del código, además de ser más difícil de leer para algunos programadores", cualquier parte del código puede ser difícil de leer "para algunos programadores". Solo necesitas encontrar programadores lo suficientemente estúpidos. No rebajes el código al mínimo denominador.
quant_dev
@quant_dev: por el contrario, "la depuración es dos veces más difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la manera más inteligente posible, por definición, no es lo suficientemente inteligente como para depurarlo". - Brian W. Kernighan
Michael Borgwardt
@MichaelBorgwardt No aplicaría el dictamen de Kernighan a ciegas a todas las situaciones posibles. El ejemplo de OP es una función escrita "de la manera más inteligente posible" (o cerca de ella) y, sin embargo, debería ser bastante fácil de depurar, si se necesita alguna depuración. Por otro lado, los complicados oneliners de bit-twiddling pueden ser muy inteligentes, pero ciertamente serán aún más difíciles de depurar. (También: Kernighan supone que las habilidades de codificación = habilidades de depuración. No tiene por qué ser así. He depurado con éxito el código que no habría podido escribir).
quant_dev
6

Generalmente preferiría la versión más larga. Se me ocurren dos razones principales:

  • Es probable que más personas lo entiendan con menos esfuerzo (suponiendo que no sea un ejemplo "estándar" como esta copia de cadena).
  • Es posible poner puntos de interrupción en declaraciones individuales y avanzar con un depurador.

Para lo mejor de ambos mundos, envuelva el código en una función, cuyo nombre hace el comentario por usted:

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '\0') {
        t++;
        s++;
        *s = *t;
    }
}

La única razón para no hacer esto sería si el rendimiento fuera un problema y la elaboración de perfiles realmente demostrara que la sobrecarga de la función es significativa.

Paul Stephenson
fuente
1
¿No es eso para lo que está en línea?
Antsan el
De hecho, aunque la inline viene con su propia cuota de problemas, como tener que exponer el cuerpo de la función en archivos de encabezado. ¿Acaso los compiladores modernos no tienen material en línea para ti de forma automática?
Paul Stephenson el
4

Lo que sea más claro. A menudo es un fragmento de código compacto y fácil de entender que no requiere un comentario ... como su segundo ejemplo.

Por lo general, los fragmentos de código más cortos son más fáciles de entender, ya que hay menos para que el lector tenga en mente a la vez. Obviamente, hay un límite cuando el código se ofusca demasiado y no quiero decir que se deba recortar el espacio en blanco que mejora la claridad.

Los comentarios nunca deben indicar algo obvio del código, que solo haga que el lector lea lo mismo dos veces. Para mí, el primer fragmento requiere una aclaración. ¿Por qué el desarrollador no ha utilizado un do...whilebucle para eliminar los duplicados de la *s = *t;tarea? Tengo que analizar más código para darme cuenta de que está implementando una copia de cadena. Un comentario sería más útil en este código más largo que en el código más corto.

El comentario sobre el segundo fragmento es casi redundante, ya que el bucle while es prácticamente idiomático, pero dice lo que hace el código en un nivel superior al código en sí mismo, lo que lo convierte en un comentario útil.

CB Bailey
fuente
El desarrollador (yo) no lo usé do ... whilesimplemente porque no lo pensé cuando escribí la pregunta. Gracias por señalar eso. ^^ El segundo fragmento puede ser obvio para usted, pero ciertamente no lo es para mí.
gablin
4

El problema es que no hay una definición clara short fancy codeya que depende mucho del nivel del programador. Mientras que algunas personas no tienen problemas para comprender una while(*s++ = *t++);expresión, otras sí.

Personalmente, encuentro el más while(*s++ = *t++);legible y el más largo más difícil de leer. Sin embargo, otros podrían no estar de acuerdo.

De todos modos, es solo una cuestión de usar el sentido común. La legibilidad definitivamente debería ser una prioridad, pero hay un punto en el que el código más largo se vuelve menos legible cuando se hace más largo. La verbosidad a menudo reduce la legibilidad de mi experiencia.

Wolph
fuente
Me entristece que un tema de muchas de estas respuestas sea "los desarrolladores pueden no reconocer la forma estándar de escribir strcpy () en C"
AShelly
No debería, no significa que no haya más buenos programadores, sino que a) ya no enseñamos mucho C yb) que la fuerza de C es también su debilidad, en tanto que ese ciclo es comprensible para alguien que practica en C, también es bastante arcano y en un mundo que se esfuerza por escribir código seguro bastante aterrador por lo que implica sobre lo que puede hacer en C
Murph
Entonces nos encontramos con otro desafío para nuestras tareas diarias. Necesitamos adivinar el nivel general de comprensión del lenguaje de nuestros pares directos para que nuestras revisiones de código sigan siendo constructivas. No caer en batallas de las cuales es la expresión de intención "correcta" y más limpia.
frogstarr78
2

Tengo que estar en desacuerdo con la mayoría de las otras respuestas aquí: creo que (al menos en este caso) el código más corto es mejor. Contrariamente a su reclamo, el código más largo no es "más fácil", al menos para un lector. En todo caso, parece que ha dejado de querer alargarlo, a pesar de que hace que el código sea más difícil de entender y / o tenga la seguridad de un funcionamiento correcto.

En particular, tener la asignación del primer byte de la cadena fuera del bucle, separada de la asignación para los otros bytes, significa que uno debe tener mucho más cuidado al leer para asegurarse de que todos los bytes se copien correctamente. La secuencia básica de acciones en la versión más corta es mucho más fácil de verificar. Su único problema real está en el formato: cuando tiene un cuerpo de bucle intencionalmente vacío, es mejor dejarlo claro, algo como:

while (*dest++ = *source++)
    ;

o incluso:

while (*dest++ = *source++)
    ; /* no body */

Algunas personas prefieren usar llaves en su lugar:

while (*dest++ = *source++)
    {}

Independientemente del formato exacto que prefiera, se han cometido suficientes errores con cosas como:

if (x>y);
     x = z;

... que es importante asegurarse de que 1) es obvio lo que está realmente controlado por cualquier control de flujo, y 2) es obvio que el código fue escrito sabiendo lo que estaba controlado por él, para que alguien que lo lea no pierda el tiempo intentando para averiguar si acaban de encontrar un error.

Jerry Coffin
fuente
Sí, en retrospectiva de este ejemplo en particular, la versión 'elegante' es probablemente más legible que la versión más larga. Si pudiera pensar en un mejor ejemplo, lo haría, pero no puedo en este momento. Pero no "hice todo lo posible" por alargarlo, así es como escribiría una copia de cadena, al menos inicialmente. Puede que no sea el mejor enfoque, pero no se hizo más de lo necesario por intención.
gablin
2
Keep it simple, stupid!

Asegúrese de que cualquier otro programador pueda entender lo que hace su código, y aún mejor si es de un vistazo (aquí es donde los buenos nombres y comentarios entran en juego).

El sofisticado ensamblaje en línea y el kung-fu de bit-twiddling es genial en nombre de la optimización (quizás innecesaria y prematura), pero cuando ni siquiera puedes entender el código que escribiste cuando te encuentras con un error dos meses después ... ¿Cuál era el punto? Te costarás tiempo y esfuerzo.

A menudo me refiero al Zen de Python en estas situaciones. En particular:

Explicit is better than implicit.
Simple is better than complex.
Humphrey Bogart
fuente
1

No escriba código sofisticado en software de producción. Sé que se siente bien poder escribir eso, y es más corto. Escribir código sofisticado aumenta significativamente el valor "WTF / minuto", en otras palabras, disminuye la calidad.

texto alternativo

Tamás Szelei
fuente
1

Por supuesto, depende completamente de las circunstancias. pero en general, considero que esta es una buena regla general:

La depuración es el doble de difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la manera más inteligente posible, por definición no es lo suficientemente inteligente como para depurarlo.

~ Brian Kernighan

violeta313
fuente
más largo pero más significativo, incluso elegante , que el acrónimo KISS más compacto ~ espero que la ironía no se pierda; p
violet313
0

En mi experiencia, la mayor victoria en términos de código corto y elegante tiende a ser recurrente en lugar de iteración. También es una de las cosas más difíciles de entender al revisar el código, a menos que esté trabajando en el tipo de lenguaje donde todo es recursivo de todos modos. Todavía lo favorecería por la elegancia y la velocidad de desarrollo que ofrece, pero trato de asegurarme de que tenga comentarios detallados si parece que será opaco para los futuros mantenedores o para mí mismo.

glenatron
fuente
0

Estoy empezando a no confiar nunca en los comentarios. Con demasiada frecuencia, los comentarios no se actualizan cuando se actualiza el código y están muy desactualizados o representan reglas de clientes / administradores que ya no son relevantes.

Ha llegado al punto en algunos casos donde los comentarios ya ni siquiera coinciden con el código que están describiendo.

Si tengo que elegir entre corto / elegante y más largo / más fácil de entender, siempre elijo este último a menos que haya realmente buena razón.

Steven Evers
fuente
0

La legibilidad y la facilidad de mantenimiento son clave, y su segundo ejemplo (es decir, el más largo) es mucho más de ambos. Pero, ¿por qué limitarse a dos opciones? Incluso el código más largo es demasiado complejo (en mi humilde opinión) para no anotar más. Lo pondría en un método propio con Javadoc apropiado (o lo que sea) y un nombre de método adecuado.

Chris Knight
fuente