FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
||||
|
||||
Excepciones: uso y abuso de la instrucción try/except
Hola,
He dudado entre publicar este Hilo o no y es que lo que diré es, desde luego, interesante para mí, pero, no sé hasta qué punto podrá o no importarle a alguien más. Brevemente. Hasta anoche no supe bien el uso de la instrucción try/except no ya en Delphi, pero, supongo, en cualquier lenguaje que haga uso de esta instrucción o alguna similar. Algo he leído (reconozco que no lo que debiera) sobre el tema, empero, hasta anoche, tal como digo, no vi la luz, como suele decirse. Me alumbró Ian Marteens en un artículo suyo titulado Excepciones en Freya. Resulta que, como el autor menciona en el segundo o tercer párrafo del artículo susomentado: Cita:
Cita:
Pues nada. Que les recomiendo el artículo en cuestión y que espero que estos párrafos no sean del todo inútiles para quien los lea. Ah, casi se me olvidan: gracias a Ian Marteens por este y otros textos suyos. |
#2
|
||||
|
||||
No entendí. ¿Se supone que hay que usar siempre raise para propagar la excepción? En tal caso no me parece lógico. Si la excepción se arregla ¿qué es lo que seguimos propagando?
// Saludos |
#3
|
||||
|
||||
Hola,
Cita:
|
#4
|
||||
|
||||
Cita:
De cualquier forma todo este asunto del plan B me parece un poco raro. No es si tienes o no un plan B, es que debes tener un plan B, de una forma u otra; si hay un código susceptible de generar una excepción, entonces debes manejarla de alguna manera. // Saludos |
#5
|
||||
|
||||
Hola:
Yo siempre utilizo Try...Except, no sé para que sirve el raise..alguien sabe??
Saludos y hasta pronto.. |
#6
|
||||
|
||||
Para medio aclarar (que con plan A y plan B ya me dan ganas del plan C ):
El asunto con try..except es muy simple, realmente ... Uno solo debe usar except si: 1- Es un codigo transaccional: ie. Hay una serie de tareas, un commit y en caso de falla, un rollback. 2- Cuando la excepcion se usa para CORREGIR el problema. Ej, estamos haciendo una conexion a un lugar remoto, y nos salta un error. Supongamos un timeout, y el programa es un cliente FTP que aparte de timeout tiene reintentos... Si la conexion falla se puede corregir (o sea volver a conectar) hasta N reintentos Pero lo que nunca se debe olvidar (porque las dos reglas anteriores no son absolutas, y se puede resolver la segunda no con excepciones sino con funciones que devuelvan el resultado de la operacion) es que: JAMAS SE DEBE ESCONDER EL ERROR. NUNCA. Y eso es todo lo que hay que saber. Ya sea que se de "rollback" o que se "corriga" se debe NOTIFICAR que hubo error, ya sea por medio de un log, un mensaje (no intrusivo, en el caso de la correccione: e.j: El cliente FTP simplemente pone un mensaje que dice: La conexion falla, reintentando en 30 segundos...), un mesagebox o lo que sea. Si se esconde el error como: try AbrirArchivo; except result := false; Nos va a dar un total dolor de cabeza el luego adivinar que salio mal. Como siempre he dicho: Si el programa saca error, es que esta bueno (Miedo al que nunca lo saca!)
__________________
El malabarista. |
#7
|
||||
|
||||
Hola,
Cita:
Voy a trasladar aquí un buen trozo del artículo en cuestión, que en realidad es el meollo del mismo, al menos, en lo que se refiere a lo que traté yo de declarar en este Hilo: Cita:
Cita:
Piensa que se trata, en el ejemplo anterior, de mostrar un pequeño formulario que solo contenga un ComboBox, en el cual el usuario tuviera que elegir/escribir un número de línea a la que luego nosotros dirigirnos. Imagina que al usuario le da por escribir un caracter en lugar de un número en el ComboBox. ¿Para qué mostrarle el error? ¿es que no es evidente? ¿es que el usuario no ve por sus propios ojos que una línea se representa mediante su número y no una letra u otro caracter? Personalmente, en este caso, al menos, no muestro ningún error, ni siquiera creo que interese mostrar la excepción: simplemente ignorarla. El usuario percibirá rápidamente, en mi opinión, que la "acción" al cabo no produjo nada, y todo lo más mostrará de nuevo el formulario, verá que hay solamente números en donde escoger "cargados" en el ComboBox y escogerá uno, si quiere. Quiere decirse que, en este caso, repito, no creo interesante mostrarle el "EConvertError", porque es más que evidente para el usuario lo que realmente está ocurriendo: por si no lo fuera del todo, en cuanto se limite a escribir o elegir un número verá cómo todo va tal como se espera. Y aquí se ve a las claras que no hay plan B de por medio. Un plan B, por ejemplo, sería decir "muy bien, usuario, no sé qué escribiste que estoy aquí, dentro de la excepción, pero, para estos casos, tengo preparada una pequeña sorpresa: me dirigiré a la línea 0, para que te chinches". Eso ya sería un plan B, que, como puede verse arriba, no existe en este caso: el error, la excepción, simplemente es ignorada y punto pelota. Última edición por dec fecha: 15-07-2005 a las 15:00:52. Razón: (corrección del texto) |
#8
|
||||
|
||||
Cita:
__________________
Van Troi De León (Not) Guía, Code vB:=Delphi-SQL, ¿Cómo? Viajar en el tiempo no es teóricamente posible, pues si lo fuera, ya estarían aqui contándonos al respecto! |
#9
|
||||
|
||||
Hola,
Sí; llevas razón vtdeleon, efectivamente, hay que utilizar "StrToInt" para el caso. |
#10
|
||||
|
||||
Pues ya que hablamos del tema, les propongo este artículo el cual lo aborda de forma muy amplia, y saquen sus propias conclusiones
Saludos
__________________
Lo importante no es llegar primero, sino saber llegar. Para que puedas llegar mejor lee la Guia de Estilo |
#11
|
||||
|
||||
Hola.
Lucasarts nos ha dado un buen ejemplo de uno de los errores mas comunes a la hora del uso de try/except. Cita:
Supongamos por ejemplo, que la propiedad Year, aún cuando es de tipo string, valida que el valor asignado sea un número. La forma "normal" de "romper un contrato" (sigo con marteens) es elevar una excepción, dado que este no se ha cumplido al asignar la cadena "mil novecientos noventa y cinco" a la propiedad year (lo introducido por el usuario). En este caso la excepción será de la clase EConvertError. En este caso, el usuario segirá recibiendo el mensaje: Para cambiar el tag de un archivo,éste no debe estar ejecutandose Esto no orienta en nada al usuario a corregir su error. Hay que tomar en cuenta también que hay otra serie de excepciones que podrian ocurrir: El disco está lleno, quizas tenga sectores dañados. En windows no es inusual que el sistema se quede sin recursos... también podria ocurrir una guerra nuclear y el usuario obtendría siempre el mismo mensaje . Esto nos lleva a la situación mas general de comprender que podrá ocurrir una serie de condiciones de excepción para la que no estamos preparados. La regla general es entonces aplicar el "plan b" solo para aquellas que sabemos y queremos tratar, dejando pasar todas las demás.
Suponiendo que el método elevará la exepción EFileInUse. Ahora, cualquier otra condición de error seguirá abortando la ejecución del código hasta que haya un bloque que si sepa que hacer con ella. Cita:
Hasta luego.
__________________
Juan Antonio Castillo Hernández (jachguate) Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate |
#12
|
||||
|
||||
Cita:
Cita:
Hasta luego.
__________________
Juan Antonio Castillo Hernández (jachguate) Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate |
#13
|
||||
|
||||
Y quien GARANTIZA que el problema va a ser porque cbLinea.text <> Integral? Y si se quedo el programa sin memoria? Y si hay un overflow? Y si el numero EFECTIVAMENTE es uin integral pero del tipo BigInt? Y si el usuario escribe 1, luego lo borra y queda en ""?
O sea, si saca el error: Es porque cbLinea.text <> Integral o porque cbLinea.text <> vacio? Como ves, minimamente encontramos 2 estados de (posible) error. Y como sabe el usuario que es un numero? En ese caso, se debe 1)Poner una mascara 2) Ojala un edit que tenga algo que identifique es un numero, por ejemplo esos que desplegan una calculadora... En mis años de programador he visto que errores IMPOSIBLEs pasan.... las correcciones deben hacerse con bisturi, no con espada, porque cuando se va acumulando codigo asi, se complica la cosa.... Ahora analiza la opcion desde el punto de vista del usuario.... que GARANTIZA que va a saber que hacer? Si no saca un mensje, lo mas seguro es que se puede suponer, el campo es opcional, no obligatorio. Ahora si lo que quieres es eludir el molesto mensaje de error, hay muchas maneras: 1- Un beep 2- Poner un muñequito o asterisco rojo al lado del control, indicando que paso/que hacer 3- Flashear el control 4- Cambiar el mensaje de Excepcion por un messageboc informativo "Hey chico, es un numero, Ok?" 5- Construir el control para que definitiva y absolutamente, no pueda meter un numero NO integral Y esas si son soluciones. De lo contrario, llamara el usuario a preguntar que es lo que pasa o se quedara dando vueltas al asunto adivinando el comportamiento oculto del sistema....
__________________
El malabarista. |
#14
|
||||
|
||||
Hola,
Gracias yusnerqui por el artículo que has enlazado. Por él me he decidido a usar la función "TryStrToInt" en lugar de:
Cita:
Cita:
Cita:
Mira, podría hacer algo así: mostrar el formulario con un único ComboBox en el que el usuario tuviera que escribir el número de la línea a la que quiere llegar. Si el número fuera correcto, estupendo, adelante. Si no fuera un número u ocurriera un error de tipo "EConvertError" volverle a mostrar el formulario y en una "etiqueta" informarle de que es un número lo que tiene que indicar y no otra cosa. Sin embargo, en este caso, insisto, no veo la necesidad: no creo que sea tan complicado lo que se pretende hacer, creo que el usuario lo entiende perfectamente, no se trata de ningún punto "crítico" del programa que pudiera tener consecuencias catastróficas, en fin. Y, por cierto, no hay plan B en este caso: no hay para qué. ¿Qué sé yo a la línea que se quiere dirigir el usuario? No lo sé, por lo tanto, dejaré las cosas como están. |
#15
|
||||
|
||||
Yo voy de acuerdo con mamcx. Las excepciones jamás se deben esconder. Pero esto no significa, como dice mi amigo jachguate, que todas deban llegar a oídos (u ojos) del usuario. "tratar la exepción" no es sinónimo de mostrar un mensaje.
Por otra parte es también un error presuponer, como ya lo indicó mamcx que el código va a fallar por una sola posible causa. Para algo está la construcción:
cualquier otro error que no sepamos o podamos manejar o que ni siquiera tengamos previsto debemos dejar que se propague. También, sin ánimo de ofender, creo que al amigo dec le hace falta enfrentarse con usuarios de verdad. Es increible la cantidad de cosas obvias que algunos simplemente no entienden. No es tanto tratar al usuario como tonto, pero la aplicación si debe estar pensada para tontos. Cita:
Yo, como usuario, agradecería una notificación inmediata de lo que estoy haciendo mal para no perder mi tiempo buscando en el formulario dónde está el error. // Saludos |
#16
|
||||
|
||||
Hola,
Cita:
Cita:
Cita:
Recuerdo el caso: el usuario quiere ir a una línea. El usuario elige del menú la opción para ir a una línea. El usuario se encuentra con un formulario de 40x40 píxeles cuyo título es "número de línea" y que solo contiene un ComboBox que ya tiene cargadas todas las líneas disponibles y muestra la actual. El usuario escribe su nombre... Pues se cierra el formulario y santas pascuas. El usuario vuelve a abrir el formulario, esto es, vuelve a abrir el menú, selecciona la opción oportuna y se le muestra el mismo formulario de antes. Entonces el usuario escribe un número de línea o elige una y zas, se cierra el formulario y se le muestra el número de línea elegido. Al cabo me convencen y pongo un mensaje de error, en caso de que el usuario escriba su nombre o cualquier cosa que no sea un número de línea, y le digo: ¿no querías ir a un número de línea en concreto? ¿entonces para qué escribes tu nombre? Por favor, escribe o elige la línea a la que quieras dirigirte. En fin. Yo creo que aquí el tema no era este en absoluto, pues al cabo todo queda reducido a cómo me parece a mí esto y cómo me parece a mí lo otro. Inicié este Hilo con la sola intención de dar noticia del artículo de Ian Marteens el cual me puso de una vez claro el uso de try/except. Eso sí creo que no se puede discutir, aunque, leyendo el artículo que antes recomendó un compañero que también trata sobre el tratamiento de excepciones, a lo que parece, es un tema sobre el que sí se puede discutir y se lleva discutiendo no poco tiempo. No sé. Se me ocurre que acaso llegamos a un punto en que tratamos de cierto estilo de hacer las cosas, y esto, ¿quién puede medirlo? Quiero decir, ¿quién puede dar una guía de estilo para esto? ¿No se ve cómo se lee la guía de estilo de estos propios foros? Es probable que sirva de algo, evidentemente sirve, pero, ¿no sigue habiendo otras maneras de hacer las cosas de todos modos? Y no de hacer las cosas mal, porque puede uno saltarse a veces ciertas reglas para hacer las cosas bien, o como cree que están bien. Pero, bueno, esto ya es demasiado, menudo rollo que he soltado. Ahora, roman, por favor, hazme saber alguna de esas "cosas obvias que algunos simplemente no entienden". Gracias. Última edición por dec fecha: 15-07-2005 a las 20:46:05. Razón: corrección del texto |
#17
|
||||
|
||||
Cosas que he aprendido hoy:
+ Todas las entradas que haga el usuario son culpables hasta que se demuestre lo contrario. + Controla todo lo que puedas controlar con los controles (si no quieres letras, pon un control que no acepte letras ) + Controla solo los errores que sepas/puedas controlar. (me queda muy claro la excepción EErrorQueSeComoManejar ) + El usuario no es tonto, pero el programa debe estar diseñado para tontos. + Al usuario le gusta saber cuando hizo algo mal. (En algunos casos será necesario mostrar un mensaje, en otros casos con un BIP es suficiente; pero SIEMPRE indicarle al usuario que algo no resulto como debería). Tengo la confianza de que gracias a su ayuda y colaboración, seguiré aprendiendo. Gracias a todos.
__________________
|
#18
|
||||
|
||||
Cita:
Problema: El usuario no puede entrar al sistema, le dice que los datos son incorrectos; su hijo- que sabe computación -dice que el sistema está mal hecho. Razón: en el recuadro que dice: Escriba se fecha de nacimiento (dd-mm-aaaa) el usuario escribe 1983/05/31 (¿Qué no es obvio? ¡Le estoy indicando el formato de la fecha!) Conclusión: (desafortunadamente) el hijo tiene razón Solución: antes de mandar los datos al servidor, verificar el formato y mandar un mensaje pertinente en caso de que sea incorrecto. Problema: El alumno no pudo inscribirse, el sistema nunca le presentó el comprobante. Razón: El alumno cerró la ventana con el resumen de datos sin oprimir el botón que decía: "Para terminar su inscripción imprima su comprobante" Claro que estos errores no encajan directamente con las excepciones (de hecho el del combo tampoco), pero son verídicos y muestran el tipo de cosas que podemos dar por obvias y qe el usuario no las ve. Y el que sea un formulario de 40x40 no es pretexto. ¿Te imaginas qué pasaría si en un código de apenas unas cuantas líneas, el compilador no tuviera a bien decirnos: "Missing operator or semicolon" ¿Es obvio que los parámetros de una función deben ir separados por comas! Pero de cualquier forma, una construcción como
jamás debe hacerse. Me parece que ya lo dijo mamcx; al hacer esto escondes todas las excepciones posibles, no sólo las que uno prevee o piensa que pueden suceder. Cita:
Cita:
El mismo artículo, a mi no me queda claro. Cita:
// Saludos |
#19
|
|||||||
|
|||||||
Hola,
Los problemas que me has mostrado roman, aun con ser posibles y todo eso, no tienen nada que ver con lo que yo hago "para dirigir al usuario a una línea". De todos modos te agradezco los comentarios igual. Por eso he recalcado arriba que estaba refiriéndome a un caso en concreto sobre el que había tomado una decisión, un caso concreto, que, claro está, no tiene porqué parecerse a otros casos concretos, por eso son concretos. Cita:
De todas maneras ya dije más arriba que había pasado a utilizar la función "TryStrToInt" y ese patrón de uso de try/except no es algo habitual en lo poco que escribo. Cita:
Así que no entiendo eso de "El usuario no es tonto, pero el programa debe estar diseñado para tontos." ¿En qué quedamos? ¿El usuario es tonto o no lo es? Porque si no lo es no podemos diseñar un progama para tonto: ¿en qué quedamos? Cita:
Cita:
Y que tampoco se debe levantar una excepción dentro de una instrucción try/except, pues que sería levantar la misma excepción dos veces: para eso está raise. Que si no se tiene un plan B, es decir, si no se sabe o no se puede o no se quiere tratar una excepción la instrucción try/except sobra, porque, precisamente, sirve justamente para cuando hay un plan B. Con plan B se refiere Marteens a otra forma de hacer las cosas en caso de que de la primera forma que se pensó no salgan bien: puede que sea de perogrullo pero es que creo que no dirá el referido autor en vano que solamente para un 10% de las excepciones tenemos un plan B. Cita:
Cita:
Actualización: Cita:
Última edición por dec fecha: 15-07-2005 a las 22:08:45. Razón: (actualización) |
#20
|
||||
|
||||
Cita:
Cita:
__________________
Última edición por ContraVeneno fecha: 15-07-2005 a las 22:49:11. |
|
|
|