Asignación booleana de mejores prácticas [cerrada]

10

Encontré el siguiente condicional en un programa que he adquirido de otro desarrollador:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Creo que este código es redundante y feo, así que lo cambié a lo que pensé que era una asignación booleana simple basada en una comparación:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

Al ver esto, alguien revisando mi código comentó que aunque mi cambio es funcionalmente correcto, podría confundir a alguien más que lo mira. Él cree que el uso de un operador ternario hace que esta asignación sea más clara, mientras que no me gusta agregar más código redundante:

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE) ? true : false;

Su razonamiento es que hacer algo de la manera más concisa no vale la pena, si hace que otro desarrollador tenga que detenerse y descifrar exactamente lo que has hecho.

La verdadera pregunta aquí es cuál de estos tres métodos para asignar un valor al booleano obj.NeedsChangees el más claro y el más fácil de mantener.

Zach Posten
fuente
25
La tercera forma es ridícula; solo indica lo que ya debería ser obvio en la segunda forma.
Robert Harvey
66
Esto depende totalmente de las preferencias personales. Podemos fingir lo contrario, pero como todos son funcionalmente equivalentes, todo se reduce al estilo . Claro, hay una diferencia en la legibilidad, pero mi "legible y transparente" podría ser su "obtuso y opaco"
MetaFight
3
@scriptin 5-8 líneas v 1 línea es más que preferencia, el revestimiento 5-8 generalmente es más claro y mejor para él. En este ejemplo simple, prefiero la línea 1, pero en general he visto demasiados 10 revestimientos que se ofuscaron en 1 revestimientos para mayor comodidad. Dado eso, nunca me quejaría de la variante 1, puede que no sea bonita, pero hace el trabajo de la misma manera clara y obvia.
gbjbaanb
44
Las opciones 1 y 3 me dicen "El autor realmente no entiende la lógica booleana".
17 de 26
2
La variante 1 puede ser útil si necesita establecer a menudo un punto de interrupción que depende del valor.
Ian

Respuestas:

39

Prefiero 2, pero podría hacer un pequeño ajuste:

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

Para mí, los paréntesis hacen que la línea sea más fácil de analizar y deja en claro de un vistazo que está asignando el resultado de una comparación y no está realizando una doble asignación. No estoy seguro de por qué (como fuera de lugar, no puedo pensar en un lenguaje en el que los paréntesis realmente eviten una doble asignación), pero si debe satisfacer a su revisor, entonces quizás esto sea un compromiso aceptable.

Jacob Raihle
fuente
44
esta es la respuesta correcta, aunque el código en la pregunta es correcto, agregar los corchetes le dice al lector que no es una asignación. Si estaba buscando rápidamente el código, los corchetes le brindan esa información adicional instantánea que le impide mirar más de cerca para ver si el código pretendía ser así, y no fue un error accidental. Por ejemplo, imagine que la línea era a = b == c, ¿quiso decir asignar un bool o quiso decir asignar c a b y a?
gbjbaanb
Los paréntesis evitarían una doble asignación en Python. Incluso en idiomas donde no impiden la doble asignación, los paréntesis definitivamente ayudan a indicar que se trata de dos tipos de operaciones.
user2357112 es compatible con Monica el
23

La variante 1 se entiende fácilmente, pero esa es su única ventaja. Asumo automáticamente que cualquiera que escriba de esta manera no entiende realmente de qué se tratan los booleanos y escribirá un código infantil similar en muchos otros aspectos.

La variante 2 es lo que siempre escribiría y esperaría leer. Creo que cualquiera que esté confundido por ese idioma no debería ser un escritor profesional de software.

La variante 3 combina las desventajas de ambos 1 y 2. 'dijo nuff.

Kilian Foth
fuente
Bueno, la variante 1 comparte su ventaja con la variante 2 ...
Deduplicator
1
+1 para código infantil. He estado buscando ese código durante años, simplemente me faltaba la palabra correcta para identificarlo.
Lilienthal
1
Mi primera suposición con un código como la Variante 1 es que las dos ramas en un punto en el pasado eran más complicadas, y alguien no estaba prestando atención al refactorizar. Sin embargo, si así fue como se escribió por primera vez, entonces estoy de acuerdo con "no entender booleanos"
Izkata
13

Cada vez que el código es más complicado de lo que necesita, se desencadena un "¿qué se supone que está haciendo?" huele en el lector.

Por ejemplo, el primer ejemplo me hace preguntarme: "¿hubo alguna otra funcionalidad en la instrucción if / else en algún momento que se eliminó?"

El ejemplo (2) es simple, claro y hace exactamente lo que se necesita. Lo leo e inmediatamente entiendo lo que hace el código.

La pelusa adicional en (3) me haría preguntarme por qué el autor lo escribió de esa manera en lugar de (2). No debería ser una razón, pero en este caso no parece ser, así que no es útil en absoluto y más difícil de leer porque la sintaxis sugiere algo presente que no está allí. Intentar aprender lo que está presente (cuando no hay nada) hace que el código sea más difícil de leer.

Enderland
fuente
2

Es fácil ver que la Variante 2 y la Variante 1 están relacionadas a través de una serie de refactorizaciones obvias y simples:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Aquí, tenemos una duplicación de código innecesaria, podemos factorizar la asignación:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE)
{
    true
}
else
{
    false
}

o escrito de manera más concisa:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE) true else false

Ahora, debería ser inmediatamente obvio que esto asignará verdadero si la condición es verdadera y asignará falso si la condición es falsa, IOW simplemente asignará el valor de la condición, es decir, es equivalente a

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE

Las variantes 1 y 3 son códigos de novatos típicos escritos por alguien que no entiende cuál es el valor de retorno de una comparación.

Jörg W Mittag
fuente
Agregaría su if (...) ... parte falsa como comentario justo antes del agradable, luego obtendrá el escaneo simple a través de la claridad del código y el mejor código.
DaveM
2

Mientras que su programación debe tender hacia explícito sobre implícita "como si el tipo que termina el mantenimiento de su código será un psicópata violento que sabe dónde vive", que puede asumir algunas cosas básicas que su sucesor será psico competente.

Una de ellas es la sintaxis del lenguaje que está usando.

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

es muy claro para cualquiera que conozca la sintaxis de C / C ++ / C # / Java / Javascript.

También es mucho más legible que 8 líneas.

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

y menos propenso a errores

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.Needschange = false;
}

Y es mejor que agregar caracteres innecesarios, como si medio olvidara la sintaxis del idioma:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE ? true : false;

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE);

Creo que hay mucho error sobre la sintaxis tipo C de muchos lenguajes: orden de operaciones inconsistente, asociatividad izquierda / derecha inconsistente, usos sobrecargados de símbolos, llaves / duplicación de sangría, operadores ternarios, notación infija, etc.

Pero la solución no es inventar su propia versión propietaria. De esa manera se encuentra la locura, ya que cada uno crea el suyo.


En general, la cosa número 1 que hace que el código Real World TM sea ilegible es su cantidad.

Entre un programa de 200 líneas no patológico y un programa de 1,600 líneas trivialmente idéntico, el más corto casi siempre será más fácil de analizar y comprender. Agradecería su cambio cualquier día.

Paul Draper
fuente
1

La mayoría de los desarrolladores podrán comprender la segunda forma con un vistazo. En mi opinión, la simplificación como en la primera forma es simplemente innecesaria.

Puede mejorar la legibilidad agregando espacios y llaves como:

obj.NeedsChange =    obj.Performance <= LOW_PERFORMANCE;

o

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

como lo mencionó Jacob Raihle.

Uday Shankar
fuente