![]() |
![]() |
| Paypal | FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
|||||||
| Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Buscar | Temas de Hoy | Marcar Foros Como Leídos |
![]() |
|
|
Herramientas | Buscar en Tema | Desplegado |
|
|
|
#1
|
||||
|
||||
|
El caso es que Firebird añade información al mensaje de error, así que no queda más remedio que buscar texto y eliminar lo que no te hace falta.
El código intuyo que sería algo así:
Creo también aparecerá el texto "exception 1 NO_Borrar" en el mensaje... es que no tengo Delphi a mano para probar y hace mucho que no las uso. Si se te complica demasiado, en el texto de la excepción en Firebird, defínela como : Exception 1 = '##No puede borrar algo de sistema @@'; Así ya sabes que tienes que copiar solo entre las ## y las @@ ... por ejemplo.
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. |
|
#2
|
||||
|
||||
|
Voy a dar mi apreciacion:
Las excepciones no deben ser user friendly. Deben mostrar la mayor cantidad de detalle, por mas "tecnico" que sea, de cual fue la causa del error, el estado de los objetos que intervenian en ese momento.. mientras mas cosas mejor. Una buena excepcion no solo contiene eso, sino que tambien deberia indicar posibles soluciones o donde mirar. En tu codigo estas cometiendo el grave error de capturar todas las excepciones y mostrar "no pudiste borrar porque es un registro protegido por el sistema". Quiere decir que si ocurre una excepcion EOutOfMemory se va a mostrar ese mensaje, si ocurre una EAccesViolation te va a decir "no podes eliminar un registro protegido por el sistema". Estas basicamente escondiendo errores de implementacion que vaya a saber que repercusion tienen, que estados inconsistentes estas dejando por ahi, o que operaciones estas bloqueando por una razon que no es Escribe excepciones que sean amigables para el programador (tu mismo!!). Yo antes hacia cosas similares a esa, ponia un mensaje de error "generico" ej: "no se pudo grabar el cliente". Genial gracias, ahora porque no se pudo? Viole una primary o unique key? Deje un campo en null? Me quede sin memoria? No instancie un objeto o lo destrui antes sin querer? Error de sintaxis sql? La tabla no existe? Como puedo saberlo?????? Facil, te abres el Delphi, y que el depurador te lance la excepcion, para nada cool eh Considera este codigo:
Es una pequeña mejora al anterior. En realidad la pregunta que yo me hago es, porque existe la posibilidad de llegar a una situacion de "borrar un registro protegido por el sistema"? No es mejor que nunca se pueda llegar a tal cosa? Realmente, vas a iniciar una transaccion, hacer rollback o commit, solo para despues decir: "esto no lo puedes borrar"? Si hay un conjunto de registros que no se pueden borrar y otros si, entonces ahi la cuestion es, antes de intentar hacer cualquier cosa, validar que sea un registro protegido, y de ser asi, elevar una excepcion
Las excepciones son eso: excepciones. Algo realmente malo que no deberia pasar. Son casos raros (por evitar el abuso de la palabra, casos excepcionales). Y si algo de esto que no es normal que pase, lo mas logico seria obtener la mayor cantidad de informacion posible, puesto que en algunos casos un tonto EAccessViolation puede ser trivial (en otros no!), pero que tal si no se puede reproducir la excepcion siempre? Tu codigo es 100% deterministico? Última edición por AgustinOrtu fecha: 29-10-2015 a las 00:34:57. |
|
#3
|
||||
|
||||
|
Cita:
![]() El tratamiento de las excepciones es un libro gordo aparte jejeje. Mi punto de vista es distinto. Al usuario hay que darle un mensaje amigable, pero aprovecha ese mismo try except para escribir en un fichero log el error, la clase, la línea donde se produce, etc. Cuando programas es otro mundo, desde hace mucho tiempo se usan las directivas de compilación para eso, aunque los BDS lo popularizaron con el compilar para "release" o para "Debug", ya de sobra conocidos en los XE. Cnpack ya lo incluye en Delphi 7 con su depurador CnDebug y es bastante fácil hacerlo. Todo este rollo viene porque en el except, la rutina que hace un log, puedes incluir: - Si el IDE de delphi está en ejecución, entonces dame toda la información que necesito como programador, Nombre de tabla, campo, valor por defecto, clase del error, etc. y pégame un pantallazo con toda esa información. Incluída la pila de llamadas de la aplicación, porque muchas veces el error está en 3 procedimientos atrás, no en la linea que levanta el error. - Si el IDE no está, pues escribes en un fichero de log de la aplicación, la hora fecha y toda la información que quieras, pero al usuario déjalo vivir leyendo un mensaje comprensible para él. - Si la directiva de compilación está anulada (porque la desactivo antes de compilar la versión definitiva), ese código no va en el ejecutable y no molesta ni afecta al rendimiento. Teniendo todos estos ingredientes, es muy fácil ordenar las cosas. Gestionar las excepciones es hacer otro programa aparte: - herencia de las excepciones (crear tu propio árbol de excepciones tal y como haces con las clases de delphi). Algo que he pensado sobre la marcha y espero aclare lo que digo: Código:
EMiprograma (hereda de Exception)
EBBDD -> excepciones de la base de datos
EAdministrador -> Error que solo subsana el administrador de la BBDD,
o sea, el programador, cosas que nunca deberían ocurrir, pero ocurren: "shit happens"
EFacturar (hereda de EMiprograma) y ocurren en el módulo de facturación
- Si se han de mostrar o no al usuario (heredar de EAbort o de Exception). El concepto es muy simple y poderoso, una vez se levanta una excepción, va subiendo por la pila de llamadas de tu aplicación ejecutando el try ... except que lo contenga, si incluye un "raise ; " seguirá subiendo hasta llegar al nivel más alto, el TApplication.OnException, si no tienes ese componente en tu aplicación, el mensaje se muestra al usuario. Si tienes el componente, tú decides qué hacer en ese evento. Es cierto que una excepción tiene un coste: - Se corta el flujo normal del programa (saltos incondicionales del código, cambio de los valores de los registros de la CPU, cambio del contador del programa, etc...) - Se crean objetos que recopilan información extra. Pero en mi opinión, debido a la complejidad de las aplicaciones actuales (multiplataforma, con componentes de terceros, etc), ya no son casos tan "excepcionales", ocurren demasiado a menudo y tenemos que saber manejarlos. Por supuesto el típico "On E:Exception do" hay que erradicarlo, debemos controlar solo las excepciones que realmente nos interesan... como en este caso "On E: EUniError do". Estoy de acuerdo con AgustinOrtu que más vale prevenir que curar, es decir, si se puede evitar lanzar una excepción inhabilitando un botón en la pantalla de usuario, ocultar ese registro en pantalla o hacerlo de solo lectura... perfecto. Por otra parte, si un sistema Gestor de Bases de Datos, tiene excepciones, es porque ha hecho falta crear ese sistema de notificaciones. Hay sistemas donde se escribe más código en la BBDD que en el programa Delphi, y en ese caso lanzar una excepción, capturarla en un trigger o procedimiento almacenado y actuar en consecuencia, es la solución perfecta. Las herramientas las tenemos ahí, ahora solo hay que usarlas cuando "creamos que es necesario", y lo entrecomillo porque a veces, por desconocimiento, las usamos cuando no debemos, pero nos soluciona el problema. Saludos!
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. Última edición por Casimiro Noteví fecha: 29-10-2015 a las 21:21:10. |
|
#4
|
||||
|
||||
|
Yo también prefiero mostrar algo simple y amigable al usuario, mientras que guardo en un log toda la información posible. Pero esa no se muestra al usuario.
__________________
La otra guía de estilo | Búsquedas avanzadas | Etiquetas para código | Colabora mediante Paypal |
|
#5
|
||||
|
||||
|
Otra posibilidad es crear un "modo depuración". Si este está activo, entonces muestra toda la información de la excepción capturada (por ejemplo, llamando a TApplication.ShowException), y si está desactivado sólo muestra un mensaje más corto pero guardando el resto de información. Sería algo así como:
Nota importante: Acabo de fijarme en que la clase Exception definida por Free Pascal difiere ligeramente de la descrita por Delphi, y lo mismo pasa con otras clases y funciones relacionadas, así que puede variar un poquito la cosa. Aun así creo que queda clara la idea, ¿no?
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi! - BAScript - Multi Language Scriptable Development Environment |
|
#6
|
||||
|
||||
|
Gracias amigos por sus comentarios, voy hacer algunas pruebas y luego les cuento
... |
|
#7
|
||||
|
||||
|
El problema con esto es meter todo en la misma "bolsa". Las excepciones son problemáticas porque interrumpen el flujo de forma abrupta, y porque se supone que *no deberían usarse/suceder de forma frecuente* y por eso se desaconsejan (la unica excepcion que conozco es python, donde se considera idiomatico).
Ademas, son evidencias de deficiencias en los lenguajes, en especial si 1)No permiten devolver mas de un valor en RETURN 2) Son OO y no hay forma de hacer encadenado de funciones de forma natural, usando un discrimininador de tipo. El asunto es que los lenguajes normalmente asumen que esta bien retornar en la ruta OK mas de un tipo de valor, de cualquier clase, pero no en la ruta ERROR (ie: No se espera que sea idiomatico retornar errores!), lo que hace la vuelta a veces un poco molesta. En fin... ----- En obj-c/Coccoa tienen un concepto util: Hay EXCEPTIONS y hay ERRORS. ERRORS son destinados siempre al usuario (y si hay un EXCEPTION la idea es que se transforma en ERROR de ser el caso...). Asi que el primer paso es: 1- Separar lo que es de usuario y lo que no Y si ocurre una excepcion: 2- Transformar de esta a ERROR si es el caso Esta es la solucion mas sana en un lenguaje con las 2 limitantes anteriores. P.D: El poner o no LOG es *tangencial* al problema. El que algo se haga den DEBUG/RELEASE tambien es tangencial y no resuelve en nada el asunto. El usar dialogos o escribir en la consola/archivo es tambien tangencial. ---- Si hay soporte a retornar multiples valores, o se usa una estructura como TUPLAS o un RECORD, se puede hacer algo muy elegante (en este pseudocodigo delphi, que estoy oxidado):
En tal caso, se retorna no el valor como tal, sino el RECORD. Lo malo es que en Delphi no hay como forzar el uso del camino "correcto" como en F#: http://fsharpforfunandprofit.com/posts/exceptions/ Ir hasta el subtitulo: "Should functions throw exceptions or return error structures?". En los lenguajes como F#, es mas comun retornar estructuras, porque permite hacer encadenamientos y automatizar un monton todo el tema. ---- Releyendo esto me di cuenta que no deje nada muy en claro, asi que: Hay 2 escuelas de como manejar los errores: 1- Uso excepciones, que son GOTOS super-cargados y especiales (Delphi, Java, C#, etc) 2- Uso valores de retorno (C, GO) La escuela 2 permite hacer codigo mas robusto, pero es muy engorroso de manejar. La primera es mas facil, pero se pierde de vista muy rapido el error y su origen (aparte de que causo una interrupcion abrupta). La 2 es mas facil de entender, porque retornar un error es quasi-como retornar un valor normal. Lo malo, es que al estilo de C (usando un 0 para OK y otro valor para quien-sabe, a veces NO-OK otras hay que consultar la tabla de errores, que esta en otro lado) es un fiasco. Ahora bien, en lenguajes funcionales, como F#, tienen una variacion del 2, pero mas util: 2-pero-util: Retorno un valor error tal como un valor OK. Quien recibe el valor decide que hace con el. (F#, ML, Haskell, Elixir) Lo cual es mil-veces-mejor que C, pero mata la gracia de las excepciones: Que el cliente no tiene que decidir siempre que hacer. --- Al punto al que voy: Hacer 2) es mas practico para manejar "errores" donde debo tener control, mas 1) es mas practico en todos los demas casos porque no quiere tener el control todo el tiempo!
__________________
El malabarista. Última edición por mamcx fecha: 03-11-2015 a las 23:51:53. |
![]() |
| Herramientas | Buscar en Tema |
| Desplegado | |
|
|
|