Pregunta

Soy nuevo en la programación y me pregunto si hay una forma correcta de ordenar la lógica de su estructura de control.

Parece más natural verificar primero el caso más probable, pero tengo la sensación de que algunas estructuras de control no funcionarán a menos que comprueben todo lo falso para llegar a algo verdadero (¿deducción lógica?)

Sería difícil adaptarse a esta visión 'negativa', prefiero una perspectiva más positiva, suponiendo que todo es cierto :)

¿Fue útil?

Solución

En la mayoría de las situaciones, la legibilidad es más importante que la velocidad de ejecución. Por lo tanto intento para optimizar para facilitar la comprensión, utilizando el siguiente enfoque:

Todas las " afirmaciones " Los controles se realizan por adelantado. esto garantiza que todos los casos erróneos se resuelvan desde el principio. esto es especialmente importante para los controles de puntero nulo, por ejemplo,

    if(arg == null){ 
      throw new IllegalArgumentException();  // harsh (correct)
    }
    // or 
    if(arg == null){
        arg = "";  // forgiving (lazy)
    }

A continuación, trato de verificar 1 condición solo en cada sentencia if. en lugar de

    if(condition1 && condition2) {
        ...
    } else {
        ...
    }

generalmente prefiero

    if(condition1) {
        if(condition2) {
            ...
        } else {
            ...
        }
    } else {
        ...
    }

Este enfoque es más fácil para establecer puntos de interrupción y hace que la lógica sea más obvia.

Evito las negaciones; en lugar de

    if(! condition) {
        ...a...
    } else {
        ...b...
    }

las cosas están mejor reorganizadas para

    if(condition) {
        ...b...
    } else {
        ...a...
    }

Finalmente, todos los métodos que devuelven un resultado booleano deberían tener un " positivo " nombre que indica el significado de los resultados:

    boolean checkSomething(Something x){ ... }     // bad -- whats the result?
    boolean isSomethingInvalid(Something x){ ... } // better, but ...
    boolean isSomethingValid(Something x){ ... }   // best, no "mental negation"

Otros consejos

Hay una excelente discusión de este tema en el Code Complete de McConnell. Es un libro que recomiendo altamente. De todos modos, la discusión relevante está en las páginas 706-708 de la primera edición o pág. 749-750 de segunda edición (gracias plinto). De ese libro:

  

Organice las pruebas para que la que está   más rápido y más probable es que sea cierto   realizado primero Debería ser fácil   pasar por el caso normal, y si   hay ineficiencias, deberían   estar en el procesamiento de las excepciones.

Hay cosas que considerar además del valor de la declaración de condición. Por ejemplo, si los bloques de código tienen un tamaño significativamente diferente, es posible que desee colocar primero el bloque pequeño para que sea más fácil de ver. (Si el bloque más grande es realmente grande, es posible que deba ser refactorizado, o quizás retirado a un método separado).

if( condition is true ) {
    do something small;
} else { 
    do something;
    and something else; 
    . . .
    and the 20th something;
}

Dentro de la condición, sí, hay algunos idiomas que dejarán de evaluar una expresión una vez que una parte de ella sea falsa. Es importante recordar esto si incluye algún tipo de lógica definida en su código: si su idioma evalúa la expresión completa, debe hacer esto:

if( variable is defined ) {
    if( variable == value ) {
        ...
    }
}

en lugar de esto:

if( (variable is defined) && (variable == value) ) {
     ...
}

No creo que haya un " correcto " Manera de diseñar tus condiciones. Si está trabajando para una empresa que tiene estándares de codificación, debe verificar si está incluido en los estándares. (El último lugar donde trabajé tenía un número razonable de estándares definidos, pero no especificaba cómo escribir la lógica condicional).

Generalmente, primero verifico los elementos inesperados, lo que me obliga a lidiar con el flujo excepcional del programa.

De esa manera, puedo lanzar excepciones / abortar operaciones antes de comenzar " configuración " para el flujo normal del programa.

Mi objetivo es estructurar mis condiciones de manera de minimizar la cantidad de información que el lector debe admitir. A veces es más fácil probar si el negativo es positivo:

Un ejemplo: la prueba para ver si un período de 2 fechas se cruza con otro período de 2 fechas es más fácil de escribir como prueba de no intersección de 2 períodos

Si se trata de una simple pregunta de sí o error, normalmente estructuro las cosas para que la rama de manejo de errores sea la cláusula else. Si es una pregunta de sí o no (es decir, ninguna de las dos ramas es un error), es simplemente una decisión de juicio sobre lo que se siente más natural. Si hay muchas pruebas que se deben realizar antes de que se pueda ejecutar el corazón del código, generalmente trato de estructurar las cosas para que las pruebas negativas aparezcan primero y, de alguna manera, omita el código que sigue (regresar de la función, interrumpir o continuar desde un bucle).

Cualquiera / o. Aunque generalmente uso el enfoque 'negativo'.

si (! algo) {

}

Esto está un poco fuera del alcance de la pregunta, pero en general también quieres que tus métodos fallen rápidamente. Por esta razón, tiendo a hacer toda la validación de mis argumentos en la parte superior del método, incluso si no voy a usar el argumento hasta más adelante en el código. Esto duele la legibilidad, pero solo en el caso de que el método sea realmente largo (hay que desplazarse fuera de la pantalla para verlo). Por supuesto, eso es un olor de código en sí mismo y tiende a ser refactuado.

Por otra parte, si la verificación no es simple y lo pasaré a otro método que solo lo va a comprobar de todos modos, no repetiré el código para verificar el método actual. Como con la mayoría de las cosas, hay un equilibrio.

(Contexto: Java)

READABILITY1: la condición que se resuelve en un bloque de código más pequeño va primero

if (condition) {
  smallBlock();
} else {
  bigBlockStart();
  ........
  bigBlockEnd();
}

READABILITY2: la afirmación positiva va primero, ya que es más fácil no notar un signo de negación

TOMANDO EL SENTIDO: Afirma todas las condiciones previas para un método utilizando Assert.blabla () y usa condicionales solo para lo que hace el método.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top