Del libro Code Complete viene la siguiente cita:
"Poner el caso normal después del en
if
lugar de después delelse
"
Lo que significa que las excepciones / desviaciones de la ruta estándar deben colocarse en el else
caso.
Pero The Pragmatic Programmer nos enseña a "chocar temprano" (p. 120).
¿Qué regla debo seguir?
if
ramas regresa, úsala primero. Y evite elelse
resto del código, ya ha regresado si fallaron las condiciones previas. El código es más fácil de leer, menos sangría ...Respuestas:
"Crash early" no se trata de qué línea de código viene antes textualmente. Le indica que detecte errores en el primer paso de procesamiento posible , para que no tome decisiones y cálculos sin darse cuenta basándose en un estado ya defectuoso.
En una
if
/else
constructo, sólo uno de los bloques se ejecuta, por lo que tampoco se puede decir que constituye una o etapa "más adelante" "anterior". Por lo tanto, cómo ordenarlos es una cuestión de legibilidad, y "fallar temprano" no entra en la decisión.fuente
if/else
construcciones pequeñas , probablemente no importa. Pero los llamados en bucle o con muchas declaraciones en cada bloque podrían ejecutarse más rápido con la condición más común primero.Si su
else
estado de cuenta contiene solo un código de falla, lo más probable es que no esté allí.En lugar de hacer esto:
hacer esto
No desea anidar profundamente su código simplemente para incluir la comprobación de errores.
Y, como todos los demás ya han dicho, los dos consejos no son contradictorios. Uno es sobre el orden de ejecución , el otro es sobre el orden del código .
fuente
if
y el flujo excepcional en el bloque despuéselse
no se aplica si no tiene unelse
! Las declaraciones de protección como esta son la forma preferida para manejar condiciones de error en la mayoría de los estilos de codificación.Deberías seguir a ambos.
El consejo "Crash early" / fail early significa que debe probar sus entradas para detectar posibles errores lo antes posible.
Por ejemplo, si su método acepta un tamaño o un recuento que se supone que es positivo (> 0), entonces el aviso inicial de falla significa que usted prueba esa condición justo al comienzo de su método en lugar de esperar a que el algoritmo produzca tonterías. resultados.
El consejo para poner el caso normal primero significa que si realiza una prueba para una condición, entonces el camino más probable debe venir primero. Esto ayuda en el rendimiento (ya que la predicción de bifurcación del procesador será correcta con más frecuencia) y la legibilidad, ya que no tiene que omitir bloques de código al intentar averiguar qué está haciendo la función en el caso normal.
Este consejo realmente no se aplica cuando se prueba una condición previa y se rescata de inmediato (mediante el uso de afirmaciones o
if (!precondition) throw
construcciones), porque no se puede omitir el manejo de errores al leer el código.fuente
if(cond){/*more likely code*/}else{/*less likely code*/}
ejecuta más rápido queif(!cond){/*less likely code*/}else{/*more likely code*/}
debido a la predicción de rama. Creo que la predicción de rama no está sesgadaif
ni a laelse
declaración ni a la declaración, y solo tiene en cuenta el historial. Entonces, sielse
es más probable que suceda, debería ser capaz de predecir eso igual de bien. ¿Es esta suposición falsa?Creo que @JackAidley ya dijo lo esencial , pero déjame formularlo así:
sin excepciones (por ejemplo, C)
En el flujo de código regular, tiene:
En el caso de "error fuera temprano", su código de repente dice:
Si ve este patrón, un
return
en un bloqueelse
(o inclusoif
), modifíquelo de inmediato para que el código en cuestión no tenga unelse
bloque:En el mundo real…
Esto evita el anidamiento demasiado profundo y cumple el caso de "salir temprano" (ayuda a mantener limpia la mente y el flujo del código) y no viola el "poner lo más probable en la
if
parte" porque simplemente no hayelse
parte .C
y limpiezaInspirado por una respuesta a una pregunta similar (que se equivocó), así es como se realiza la limpieza con C. Puede usar uno o dos puntos de salida allí, aquí hay uno para dos puntos de salida:
Puede contraerlos en un punto de salida si hay menos limpieza que hacer:
Este uso de
goto
está perfectamente bien, si puede manejarlo; El consejo para evitar el usogoto
está dirigido a personas que aún no pueden decidir por sí mismas si un uso es bueno, aceptable, malo, con código de espagueti u otra cosa.Excepciones
Lo anterior habla de idiomas sin excepciones, que yo prefiero (puedo usar el manejo explícito de errores mucho mejor y con mucha menos sorpresa). Para citar a igli:
Pero aquí hay una sugerencia de cómo hacerlo bien en un idioma con excepciones, y cuándo quiere usarlos bien:
error de retorno ante excepciones
Puede reemplazar la mayoría de los primeros
return
s con una excepción. Sin embargo , el flujo normal de su programa, es decir, cualquier flujo de código en el que el programa no encontró, bueno, una excepción ... una condición de error o algo así, no generará ninguna excepción.Esto significa que…
... está bien, pero ...
… no es. Básicamente, una excepción no es un elemento de flujo de control . Esto también hace que las operaciones te parezcan extrañas ("esos programadores de Java ™ siempre nos dicen que estas excepciones son normales") y pueden dificultar la depuración (por ejemplo, decirle al IDE que simplemente se salte cualquier excepción). Las excepciones a menudo requieren que el entorno de tiempo de ejecución desenrolle la pila para producir trazas, etc. Probablemente haya más razones en su contra.
Esto se reduce a: en un lenguaje que admite excepciones, use lo que coincida con la lógica y el estilo existentes y se sienta natural. Si escribe algo desde cero, acuerde esto pronto. Si escribe una biblioteca desde cero, piense en sus consumidores. (No, nunca, use
abort()
en una biblioteca tampoco ...) Pero haga lo que haga, por regla general, no haga que se lance una excepción si la operación continúa (más o menos) normalmente después de eso.consejos generales wrt. Excepciones
Trate de obtener todo el uso del programa de Excepciones acordadas por todo el equipo de desarrollo primero. Básicamente, planifícalos. No los uses en abundancia. A veces, incluso en C ++, Java ™, Python, un retorno de error es mejor. A veces no lo es; úsalos con pensamiento.
fuente
goto fail;
escondido en la ideación.En mi opinión, 'Guard Condition' es una de las mejores y más fáciles formas de hacer que el código sea legible. Realmente odio cuando veo
if
al principio del método y no veo elelse
código porque está fuera de la pantalla. Tengo que desplazarme hacia abajo solo para verthrow new Exception
.Ponga los cheques al principio para que la persona que lee el código no tenga que saltar todo el método para leerlo, sino que siempre lo escanee de arriba a abajo.
fuente
(La respuesta de @mirabilos es excelente, pero así es como pienso en la pregunta para llegar a la misma conclusión :)
Estoy pensando en mí mismo (o en alguien más) leyendo el código de mi función más adelante. Cuando leo la primera línea, no puedo hacer ninguna suposición sobre mi entrada (excepto aquellas que no comprobaré de todos modos). Entonces mi pensamiento es "Ok, sé que voy a hacer cosas con mis argumentos. Pero primero vamos a" limpiarlos ", es decir, eliminar las rutas de control en las que no son de mi agrado". Pero al mismo tiempo , No veo el caso normal como algo condicionado; quiero enfatizar que es normal.
fuente
Este tipo de orden de condición depende de la importancia crítica de la sección de código en cuestión y de si hay valores predeterminados que se pueden usar.
En otras palabras:
A. sección crítica y sin valores predeterminados => Fail Early
B. sección y valores predeterminados no críticos => Usar valores predeterminados en otra parte
C. casos intermedios => decidir por caso según sea necesario
fuente