Acabo de descubrir un código encantador en la aplicación de nuestra compañía que usa bloques Try-Catch como operadores lógicos.
Es decir, "haz algo de código, si eso arroja este error, haz este código, pero si eso arroja este error, haz esto en tercer lugar".
Utiliza "Finalmente" como la declaración "else" que aparece.
Sé que esto está mal intrínsecamente, pero antes de ir a pelear, esperaba algunos argumentos bien pensados.
Y oye, si tienes argumentos para el uso de Try-Catch de esta manera, por favor dilo.
Para cualquiera que se pregunte, el lenguaje es C # y el código en cuestión tiene más de 30 líneas y está buscando excepciones específicas, no está manejando TODAS las excepciones.
error-handling
programming-logic
James P. Wright
fuente
fuente
try
'd'. No todos los casos excepcionales que justifican una excepción en general tienen que ser fatales en este caso específico. Entonces, ¿podría hacerlo de una manera más simple, igual o más robusta sin usar excepciones?Respuestas:
El manejo de excepciones tiende a ser una forma costosa de manejar el control de flujo (ciertamente para C # y Java).
El tiempo de ejecución hace mucho trabajo cuando se construye un objeto de excepción: obtener el seguimiento de la pila, averiguar dónde se maneja la excepción y más.
Todo esto cuesta en memoria y recursos de CPU que no necesitan expandirse si se utilizan declaraciones de control de flujo para el control de flujo.
Además, hay un problema semántico. Las excepciones son para situaciones excepcionales, no para el control de flujo normal. Uno debe usar el manejo de excepciones para manejar situaciones inesperadas / no anticipadas, no como un flujo de programa normal, porque de lo contrario, una excepción no detectada le dirá mucho menos.
Aparte de estos dos, está la cuestión de que otros lean el código. Usar excepciones de esa manera no es algo que la mayoría de los programadores esperarán, por lo que la legibilidad y la comprensión de su código se ven afectados. Cuando uno ve "Excepción", uno piensa: algo malo sucedió, algo que no se supone que suceda normalmente. Entonces, usar excepciones de esta manera es simplemente confuso.
fuente
¿Como sabes eso? Renuncié a todo ese tipo de "conocimiento" y ahora solo creo que el código más simple es el mejor. Suponga que desea convertir una cadena a Opcional que está vacía si falla el análisis. No hay nada malo con:
Estoy completamente en desacuerdo con la interpretación habitual de "Las excepciones son para condiciones excepcionales". Cuando una función no puede devolver un valor utilizable o un método no puede cumplir con sus condiciones posteriores, arroje una excepción. No importa con qué frecuencia se lanzan estas excepciones hasta que se demuestre un problema de rendimiento.
Las excepciones simplifican el código al permitir la separación del manejo de errores del flujo normal. Simplemente escriba el código más simple posible, y si es más fácil usar try-catch o lanzar una excepción, hágalo.
Las excepciones simplifican las pruebas al reducir el número de rutas a través del código. Una función sin ramas completará o lanzará una excepción. Una función con múltiples
if
declaraciones para verificar los códigos de error tiene muchas rutas posibles. Es muy fácil equivocarse en una de las condiciones u olvidarla por completo, de modo que se ignora alguna condición de error.fuente
int i; if(long.TryParse(s, out i)) return i; else return null;
. TryParse devuelve falso si no se pudo analizar la cadena. Si se puede analizar, establece el argumento de salida a los resultados del análisis y devuelve verdadero. No se producen excepciones (incluso internamente en TryParse) y, especialmente, no hay excepciones que sean de un tipo que signifique un error del programador, comoFormatException
siempre indica .NET .El trabajo de depuración y mantenimiento es muy difícil cuando el flujo de control se realiza utilizando excepciones.
Inherentemente, las excepciones están diseñadas para ser un mecanismo para alterar el flujo de control normal de su programa, de realizar actividades inusuales, causando efectos secundarios inusuales, como una forma de salir de un vínculo particularmente apretado que no se puede manejar con menos complicaciones. medio. Las excepciones son excepcionales. Esto significa que, dependiendo del entorno particular en el que esté trabajando, el uso de una excepción para el flujo de control regular puede causar:
Ineficiencia Los aros adicionales que el entorno tiene que atravesar para realizar de manera segura los cambios de contexto relativamente difíciles requeridos para las excepciones requieren instrumentación y recursos.
Dificultades de depuración A veces, la información útil (cuando se intenta depurar un programa) se arroja por la ventana cuando se producen excepciones. Puede perder la noción del estado o historial del programa que sea relevante para comprender el comportamiento en tiempo de ejecución
Problemas de mantenimiento El flujo de ejecución es difícil de seguir a través de saltos de excepción. Más allá de eso, se puede generar una excepción desde el código de tipo recuadro negro, que puede no comportarse de manera fácil de entender cuando se lanza una excepción.
Decisiones de diseño deficientes Los programas creados de esta manera fomentan un estado de ánimo que, en la mayoría de los casos, no se mapea fácilmente para resolver problemas con elegancia. La complejidad del programa final desalienta al programador de comprender completamente su ejecución y alienta a tomar decisiones que conducen a mejoras a corto plazo con altos costos a largo plazo.
fuente
He visto este patrón usado varias veces.
Hay 2 problemas principales:
goto
. Los saltos se consideran dañinos, por varias razones. Deben usarse, si todas las alternativas tienen desventajas considerables. De hecho, en todo mi código recuerdo solo 2 casos, donde los saltos fueron claramente la mejor solución.fuente
A veces las excepciones son más rápidas. He visto casos en los que las excepciones de objetos nulos fueron más rápidas incluso en Java que el uso de estructuras de control (no puedo citar el estudio en este momento, por lo que tendrá que confiar en mí). El problema surge cuando Java tiene que tomarse el tiempo y llenar el seguimiento de la pila de una clase de excepción personalizada en lugar de usar las nativas (que parecen estar al menos parcialmente en caché). Antes de decir que algo es unilateralmente más rápido o más lento, sería bueno compararlo.
En Python no solo es más rápido, sino que es mucho más correcto hacer algo que pueda causar una excepción y luego manejar el error. Sí, puede aplicar un sistema de tipos, pero eso va en contra de la filosofía del lenguaje; en su lugar, simplemente debe intentar llamar al método y obtener el resultado. (Probar si un archivo es editable es similar, solo intente escribir en él y detecte el error).
He visto momentos en los que es más rápido hacer algo estúpido como tablas de consulta que no estaban allí que averiguar si existe una tabla en PHP + MySQL (la pregunta donde comparo esto es en realidad mi única respuesta aceptada con votos negativos) .
Dicho todo esto, el uso de excepciones debe limitarse por varias razones:
try...catch
adherentes del flujo de control generalmente (en mi experiencia) no siguen la filosofía de "minimizar el código en el bloque de prueba".else if
bloqueo. Suficientemente dicho (y si alguien responde con un "Pero podrían usar diferentes clases de excepciones", mi respuesta es "Ve a tu habitación y no salgas hasta que hayas pensado en lo que has dicho").Exception
, para el resto del mundo (como no adherentes a latry...catch
filosofía del flujo de control), significa que algo ha entrado en un estado inestable (aunque quizás recuperable). Los estados inestables son MALOS y debería mantenernos despiertos a todos por la noche si realmente tenemos excepciones evitables (en realidad me asusta, sin mentiras).try...catch
el flujo de control va en contra de lo que comúnmente se consideran las mejores prácticas. Esto significa que se necesita más tiempo para que alguien nuevo en un proyecto aprenda el proyecto, lo que significa un aumento en la cantidad de horas hombre sin absolutamente ninguna ganancia.try{ obj.openSomething(); /*something which causes exception*/ obj.doStuff(); obj.closeSomething();}catch(Exception e){obj.closeSomething();}
. En unif...else
escenario más tradicional,closeSomething()
es menos probable (una vez más, experiencia personal) ser un trabajo de copiar y pegar. (Es cierto que este argumento en particular tiene más que ver con las personas que he conocido que la filosofía en sí misma).fuente
Mi argumento principal es que usar try / catch para la lógica interrumpe el flujo lógico. Seguir "lógica" a través de construcciones no lógicas es (para mí) contraintuitivo y confuso. Estoy acostumbrado a leer mi lógica como "si Condición entonces A otra B". Leer la misma declaración como "Intente A atrapar y luego ejecute B" se siente raro. Sería aún más extraño si la declaración
A
es una asignación simple, que requiere un código adicional para forzar una excepción sicondition
es falsa (y hacer eso probablemente requeriría unaif
declaración de todos modos).fuente
Bueno, solo es una cuestión de etiqueta, antes de "comenzar una discusión con ellos", como usted lo dice, le preguntaría amablemente "¿Por qué usan el manejo de excepciones en todos estos lugares diferentes?"
Quiero decir, hay varias posibilidades:
... Creo que todos estos son igualmente probables. Así que solo pregúntales amablemente.
fuente
Try Catch solo debe usarse para el manejo de excepciones. Más aún, manejo de excepciones específicas. Su intento de captura debe capturar solo las excepciones esperadas, de lo contrario, no está bien formado. Si necesita usar un catch all try catch, entonces probablemente esté haciendo algo mal.
EDITAR:
Motivo: puede argumentar que si usa try catch como operador condicional, ¿cómo va a contabilizar las excepciones REALES?
fuente
catch
cláusula diferente de la que capta excepciones "no reales"?Las excepciones son cuando suceden cosas excepcionales. ¿El programa funciona de acuerdo con el flujo de trabajo regular excepcional?
fuente
Motivo para usar excepciones:
Razones para no usar excepciones:
En el final:
El objetivo es escribir código que comunique lo que está sucediendo. Las excepciones pueden ayudar / dificultar eso dependiendo de lo que esté haciendo el código. Un try / catch en python para un KeyError en una referencia de diccionario es perfectamente (siempre que conozca el idioma) try / catch para el mismo KeyError a cinco capas de funciones es peligroso.
fuente
Yo uso try-> catch como control de flujo en ciertas situaciones. Si su lógica principal depende de algo que falla, pero no desea simplemente lanzar una excepción y salir ... Para eso está el bloque try-> catch. Escribo muchos scripts de Unix del lado del servidor no supervisados, y es mucho más importante para ellos no fallar, que fallar con precisión.
Por lo tanto, intente el Plan A, y si el Plan A muere, atrape y ejecute con el Plan B ... Y si el plan B falla, úselo finalmente para iniciar el Plan C, que solucionará uno de los servicios fallidos en A o B, o la página yo.
fuente
Depende del idioma y quizás de la implementación utilizada. El estándar en C ++ es que las excepciones deben guardarse para eventos verdaderamente excepcionales. Por otro lado, en Python una de las pautas es " es más fácil pedir perdón que permiso ", por lo que se fomenta la integración de los bloques try / except en la lógica del programa.
fuente
Es un mal hábito, pero lo hago de vez en cuando en Python. Al igual que en lugar de verificar si existe un archivo, solo trato de eliminarlo. Si arroja una excepción, lo atrapo y sigo adelante sabiendo que no estaba allí. <== (no necesariamente cierto si otro usuario posee el archivo, pero lo hago en el directorio de inicio de un usuario, por lo que esto NO DEBE suceder).
Aún así, el uso excesivo es una mala práctica.
fuente
Me gusta la forma en que Apple lo define : las excepciones son solo para errores de programador y errores fatales de tiempo de ejecución. De lo contrario, use códigos de error. Me ayuda a decidir cuándo usarlo, pensando para mí mismo "¿Fue esto un error del programador?"
fuente
Esto suena como usar el manejo de excepciones para construir una lógica de goto sobre un lenguaje que no tiene un comando goto.
Por las muchas razones por las que ir a la lógica es malo, puede consultar esta pregunta: https://stackoverflow.com/questions/46586/goto-still-considered-harmful
fuente