2009-10-29 21 views
12

Durante una revisión del código, un desarrollador sénior comentó sobre el anidamiento que tenía en mi código. Sugirió que establezca un valor de bool para que nunca tenga más de un nivel de anidación. Creo que mi código es más legible pero quiero obtener la opinión de otros desarrolladores sobre esto. ¿Cuál es mejor estilo? ¿Se fundó su aversión instintiva a la anidación?¿Cuál es el mejor estilo de codificación?

A continuación se muestran algunos ejemplos de código simplificado.

anidada:

If(condition1) 
{ 
    If(condition2) 
    { 
     if(condition3) 
     { 
      return true; 
     } 
     else 
     { 
      log("condition3 failed"); 
     } 
    else 
    { 
     log("condition2 failed") 
    } 
} 
else 
{ 
    log("condition1 failed") 
} 

return false; 

o

Bool Driven:

bool bRC = false; 

bRC = (condition1); 
if(brc) 
{ 
    bRC = (condition2); 
} 
else 
{ 
    log("condition1 failed"); 
    return false; 
} 

if(bRC) 
{ 
    bRC = (condition3); 
} 
else 
{ 
    log("condition2 failed"); 
    return false; 
} 

if(bRC) 
{ 
    return true; 
} 
else 
{ 
    log("condition3 failed"); 
    return false; 
} 
+2

No culpe a su dev alto ;-) – JRoppert

+0

supongo que tendría que votar a favor de la opción 2, ya que se obtiene un error de compilación con el nº 1 – AndrewB

+2

favor informara cuál es la reacción de su dev alto cuando se les muestra en este tema:) –

Respuesta

32

I como la suya mejor, pero probablemente haría algo como:

if (condition1 && condition2 && condition3) 
{ 
    return true; 
} 
else if (!condition1) 
{ 
    log("condition1 failed"); 
} 
else if (!condition2) 
{ 
    log("condition2 failed"); 
} 
else 
{ 
    log("condition3 failed"); 
} 
return false; 

Si las condiciones son expresiones complejas entonces podría asignar las expresiones a denominarse adecuadamente las variables antes de evaluar el if para evitar tener que recalcula los valores en cada if.

Esto supone que el modo normal es que todas las condiciones son verdaderas y, por lo tanto, desea tener esa verificación primero. Si el modo normal es que una o más condiciones son falsas, entonces lo reordenaré y verificaré cada negación a la vez y simplemente devolveré verdadero si todas las comprobaciones fallaron. Eso también eliminaría la necesidad de variables temporales para tomar el lugar de expresiones complejas.

+0

Estoy a favor de esto también. – nullArray

+1

me gusta esto, pero si tiene funciones en la condición, PUEDE llamar a las funciones varias veces (a menos que aproveche la evaluación de cortocircuito) – mauris

+1

@Mauris - cierto, pero ese es probablemente un caso en el que evaluaría la condición y asignar a una variable local para evitar tener que volver a calcularla. – tvanfosson

6

generalmente prefiero jerarquizadas por mis condiciones; por supuesto, si mis condiciones anidadas se sangran demasiado a la derecha, tengo que empezar a preguntarme si hay una mejor manera de hacer lo que estoy intentando (refactorización, rediseño, etc.)

18

I personalmente encuentre el código anidado significativamente más fácil de leer.

+0

Mucho más fácil visualizar el flujo de programa IMO. –

+0

Y yo diría MUCHO más fácil de mantener. –

+4

El anidado habría sido menos propenso a errores. ¡Y reduce la necesidad de un booleano adicional! – mauris

3

El segundo estilo es absurdamente detallado: ¿realmente sugirió exactamente esto? No necesita la mayoría de esas declaraciones if, porque hay un return en la parte else.

Con el ejemplo anidado confía en no omitir incluir cualquier posible cláusula else.

Ninguno de estos me parece satisfactorio.

+1

Estoy de acuerdo - fugly ++ –

+0

Me estremezco cada vez que veo ese anti-patrón "bResult". –

2

El camino impulsado por bool es confuso. El anidamiento está bien si es necesario, pero puede eliminar parte de la profundidad de anidamiento combinando las condiciones en una declaración, o llamando a un método donde se realiza parte de la evaluación adicional.

0

El código debe replantear el problema en un idioma dado. Por lo tanto, mantengo que cualquiera de los fragmentos puede ser "mejor". Depende del problema que se modele. Aunque creo que ninguna de las soluciones será paralela al problema real. Si pone términos reales en lugar de condition1,2,3 podría cambiar completamente el "mejor" código.
Sospecho que hay una mejor manera (3d) de escribir todo eso juntos.

2

Creo que ambas formas son posibles y tienen sus pros y contras. Usaría el estilo impulsado por bool en casos en los que tendría una anidación realmente profunda (8 o 10 o algo así).En su caso con 3 niveles, elegiría a su estilo, pero para la muestra exacta de lo alto, me iría así:

 
void YourMethod(...) 
{ 
    if (condition1 && condition2 && consition3) 
    return true; 

    if (!condition 1) 
    log("condition 1 failed"); 

    if (!condition 2) 
    log("condition 2 failed"); 

    if (!condition 3) 
    log("condition 3 failed"); 

    return result; 
} 

... o gustaría que si usted prefiere un sólo punto de salida (como hago) ...

 
void YourMethod(...) 
{ 
    bool result = false; 

    if (condition1 && condition2 && consition3) 
    { 
    result = true; 
    } 
    else 
    { 
    if (!condition 1) 
     log("condition 1 failed"); 

    if (!condition 2) 
     log("condition 2 failed"); 

    if (!condition 3) 
     log("condition 3 failed"); 
    } 
    return result; 
} 

esta manera, usted recibirá toda la condición de fallo conectado a la primera carrera. En su ejemplo, obtendrá solo una condición fallida registrada incluso si hay más de una condición anómala.

+0

Comprobar de forma redundante las condiciones varias veces puede no ser favorable o posible; puede tener problemas de rendimiento o efectos secundarios, respectivamente. –

1

probablemente me voy con

if (!condition1)  log("condition 1 failed"); 
    else if (!condition2) log("condition 2 failed"); 
    else if (!condition3) log("condition 3 failed"); 
    // ------------------------------------------- 
    return condition1 && condition2 && condition3; 

que creo que es mucho más limpio y equivilent ...

Además, una vez que el cliente decide que todas las condiciones deben ser evaluados y registrados si fallan, no sólo el primero que falla, esto es mucho más fácil de modificar para hacerlo:

if (!condition1) log("condition 1 failed"); 
    if (!condition2) log("condition 2 failed"); 
    if (!condition3) log("condition 3 failed"); 
    // ------------------------------------------- 
    return condition1 && condition2 && condition3; 
1

Si el idioma es compatible con el manejo de excepciones, me gustaría ir con lo siguiente:

try { 
    if (!condition1) { 
     throw "condition1 failed"; 
    } 

    if (!condition2) { 
     throw "condition2 failed"; 
    } 

    if (!condition3) { 
     throw "condition3 failed"; 
    } 

    return true; 

} catch (e) { 
    log(e); 
    return false; 
} 

EDITAR de Charles Bretana: Por favor, vea Using Exceptions for control flow

+0

-1: estilísticamente lindo, pero una mala idea para muchos idiomas. Por ejemplo, en Java es costoso lanzar (en realidad crear) una excepción. –

+0

-1; si es caro en Java, es * exorbitante * en Objective-C –

+0

¿Por qué asumes que a cada bit de código debería importarle el rendimiento? Esto podría haber sido una lógica de inicialización que solo se ejecuta una vez al inicio. Inicializaciones complejas con múltiples puntos de falla son típicas de tales funciones de inicialización. Normalmente no tendrías tres puntos de falla en una función de manejo de vector de tiempo crítico, a menos que tus vectores estén equivocados. :) –

19

Si usted no tiene ningún reglas tontas sobre múltiples puntos de retorno, creo que esto es bastante agradable (y lo mismo ocurre con otra persona, pero su borrado respuesta por razones desconocidas):

if(!condition1) 
{ 
    log("condition1 failed"); 
    return false; 
} 

if(!condition2) 
{ 
    log("condition2 failed"); 
    return false; 
} 

if(!condition3) 
{ 
    log("condition3 failed"); 
    return false; 
} 

return true; 

Tal vez este es un igual aversión instintiva a super-anidación, pero es sin duda más limpio que su basura almacenar las condiciones booleanas en ciertos valores. Sin embargo, puede ser menos legible en contexto: considere si una de las condiciones fue isreadable(). Es más claro decir if(isreadable()) porque queremos saber si algo es legible. if(!isreadable()) sugiere si queremos saber si no es legible, lo cual no es nuestra intención. Ciertamente es discutible que haya situaciones en las que uno es más legible/intuitivo que el otro, pero yo también soy un fan de esta manera. Si alguien se colgó en las declaraciones, usted podría hacer esto:

if(!condition1) 
    log("condition1 failed"); 

else if(!condition2) 
    log("condition2 failed"); 

else if(!condition3) 
    log("condition3 failed"); 

else 
    return true; 

return false; 

Pero eso es más bien solapada, y menos "claro" en mi opinión.

+0

Una variante menor en su última alternativa: int rc = falso si es como antes; else rc = verdadero; el final de la función devuelve rc. Nada oculto; la función falla hasta que todo esté bien. –

+1

Esto es mucho mejor que el enfoque booleano, que yo llamaría programación de culto a la carga ** ... ** reaccionando a la evidencia superficial de complejidad pero implementando una alternativa igualmente compleja pero más oscura que reemplaza la anidación con algo peor. – DigitalRoss

+0

@Jonathan - Casi consideraría que es más secreto utilizar una variable innecesaria, pero probablemente no sea importante. –

1

Así es como lo implementaría, siempre que sus implementaciones realmente reflejen el comportamiento deseado.

if (!condition1) { 
    log("condition1 failed"); 
    return false; 
} 
if (!condition2) { 
    log("condition2 failed"); 
    return false; 
} 
if (!condition3) { 
    log("condition3 failed"); 
    return false; 
} 
return true; 

Sin embargo, creo que es más probable que todas las condiciones fallidas se registren.

result = true; 
if (!condition1) { 
    log("condition1 failed"); 
    result = false; 
} 
if (!condition2) { 
    log("condition2 failed"); 
    result = false; 
} 
if (!condition3) { 
    log("condition3 failed"); 
    result = false; 
} 
return result; 
5

Al igual que en la versión anidada, pero mucho más limpio para mí:

if not condition1: 
    log("condition 1 failed") 
else if not condition2: 
    log("condition 2 failed") 
else if not condition3: 
    log("condition 3 failed") 
else 
    return true; 
return false; 

Tenga en cuenta que cada condición se evalúa una vez.

+0

+1 esto es equivalente a la lógica origiaal y sustancialmente terser –

+0

¡Acabo de escribir esto! Supongo que no necesito publicarlo. +1 – DigitalRoss

1

No me gusta de ninguna manera. Cuando tienes tantos nidos, algo está mal. En el caso de una validación de formulario o algo que realmente requiera algo como esto, intente descubrir algo que sea más modular o compacto.

Un ejemplo sería una matriz que contiene las condiciones, a través de la cual podrá iterar por un tiempo, e imprimir/romper según sea necesario.

Existen demasiadas implementaciones según sus necesidades, por lo que crear un código de ejemplo no tendría sentido.

Como regla general, cuando su código parece demasiado complicado, apesta :). Intenta reconsiderarlo. Seguir las prácticas de codificación la mayoría de las veces hace que el código resulte mucho más estético y corto; y obviamente, también más inteligente.

0
if(condition1 && condition2 && condition3) 
    return true; 

log(String.Format("{0} failed", !condition1 ? "condition1" : (!condition2 ? "condition2" : "condition3"))); 
return false; 

De esta manera, no tiene que ver muchas líneas de código solo para iniciar sesión. Y si todas sus condiciones son ciertas, no pierda el tiempo evaluándolas en caso de que tenga que iniciar sesión.

Cuestiones relacionadas