Existe una discusión en comp.lang.c ++. Moderada sobre si las afirmaciones, que en C ++ solo existen en las compilaciones de depuración de forma predeterminada, deben mantenerse en el código de producción o no.
Obviamente, cada proyecto es único, por lo que mi pregunta aquí no es tanto si se deben mantener las afirmaciones, sino en qué casos es recomendable / no es una buena idea.
Por afirmación, quiero decir:
- Una verificación en tiempo de ejecución que prueba una condición que, cuando es falsa, revela un error en el software.
- Un mecanismo por el cual se detiene el programa (tal vez después de un trabajo de limpieza realmente mínimo).
No estoy necesariamente hablando de C o C ++.
Mi propia opinión es que si usted es el programador, pero no posee los datos (que es el caso con la mayoría de las aplicaciones comerciales de escritorio), debe mantenerlos encendidos, porque una aserción fallida muestra un error, y no debe ir con un error, con el riesgo de corromper los datos del usuario. Esto lo obliga a realizar una prueba exhaustiva antes de enviar, y hace que los errores sean más visibles, por lo que es más fácil de detectar y corregir.
¿Cuál es tu opinión / experiencia?
Salud,
Carl
Ver pregunta relacionada aquí
Respuestas y actualizaciones
Hola Graham
Una afirmación es error, pura y simple y, por lo tanto, debe manejarse como tal. Dado que un error debe manejarse en el modo de lanzamiento, realmente no necesita afirmaciones.
Es por eso que prefiero la palabra "error" cuando hablo de afirmaciones. Hace las cosas mucho más claras. Para mí, la palabra "error" es demasiado vaga. Un archivo que falta es un error, no un error, y el programa debería solucionarlo. Intentar desreferenciar un puntero nulo es un error, y el programa debe reconocer que algo huele a queso malo.
Por lo tanto, debe probar el puntero con una aserción, pero la presencia del archivo con el código normal de manejo de errores.
Ligeramente fuera de tema, pero un punto importante en la discusión.
Como aviso, si sus afirmaciones entran en el depurador cuando fallan, ¿por qué no? Pero hay muchas razones por las que un archivo podría no existir que están completamente fuera del control de su código: derechos de lectura / escritura, disco lleno, dispositivo USB desconectado, etc. Como no tiene control sobre él, creo que las afirmaciones son no es la forma correcta de lidiar con eso.
Carl
Thomas
Sí, tengo Code Complete, y debo decir que estoy totalmente en desacuerdo con ese consejo en particular.
Supongamos que su asignador de memoria personalizado se arruina y pone a cero un trozo de memoria que todavía utiliza algún otro objeto. Sucede que pongo a cero un puntero que este objeto desreferencia regularmente, y uno de los invariantes es que este puntero nunca es nulo, y tiene un par de afirmaciones para asegurarse de que se mantenga así. ¿Qué haces si el puntero de repente es nulo? ¿Solo si () a su alrededor, esperando que funcione?
Recuerde, aquí estamos hablando del código del producto, por lo que no hay que irrumpir en el depurador e inspeccionar el estado local. Este es un error real en la máquina del usuario.
Carl
Respuestas:
Las afirmaciones son comentarios que no pasan de moda. Documentan qué estados teóricos están destinados y qué estados no deberían ocurrir. Si se cambia el código de modo que los estados permitieron el cambio, el desarrollador pronto es informado y necesita actualizar la afirmación.
fuente
Permítame citar el Código completo de Steve McConnell. La sección sobre Afirmaciones es 8.2.
Sin embargo, más adelante en la misma sección, se dan estos consejos:
Creo que siempre que el rendimiento no sea un problema, deje la afirmación, pero en lugar de mostrar un mensaje, haga que escriba en un archivo de registro. Creo que ese consejo también está en Code Complete, pero no lo estoy encontrando en este momento.
fuente
Deje las afirmaciones activadas en el código de producción, a menos que haya medido que el programa se ejecuta significativamente más rápido con ellos desactivados.
http://c2.com/cgi/wiki?ShipWithAssertionsOn
fuente
assert ref != null;
es diferente aif (ref == null) throw new IllegalArgumentException();
No debería usar el primero para condiciones previas que podrían ser falsas. Debe usarassert
para cosas que no pueden ser falsas. Ejemplo,int i = -1 * someNumber; i = i * i;
luego para recordarle a la gente quei
es positivo,assert i > 0;
Si incluso está pensando en dejar afirmaciones en producción, probablemente esté pensando en que están equivocadas. El objetivo de las afirmaciones es que puede desactivarlas en la producción, ya que no son parte de su solución. Son una herramienta de desarrollo, utilizada para verificar que sus suposiciones sean correctas. Pero cuando entre en producción, ya debería tener confianza en sus suposiciones.
Dicho esto, hay un caso en el que activaré las aserciones en producción: si encontramos un error reproducible en producción que estamos teniendo dificultades para reproducir en un entorno de prueba, puede ser útil reproducir el error con las aserciones activadas en producción, para ver si proporcionan información útil.
Una pregunta más interesante es esta: en su fase de prueba, ¿cuándo desactiva las afirmaciones?
fuente
Las afirmaciones nunca deben permanecer en el código de producción. Si una afirmación particular parece que podría ser útil en el código de producción, entonces no debería ser una afirmación; debe ser una comprobación de errores en tiempo de ejecución, es decir, codificado como esto algo:
if( condition != expected ) throw exception
.El término 'aserción' ha llegado a significar "una verificación solo en tiempo de desarrollo que no se realizará en el campo".
Si comienzas a pensar que las afirmaciones pueden llegar al campo, inevitablemente también comenzarás a hacer otros pensamientos peligrosos, como preguntarte si realmente vale la pena hacer alguna afirmación. No hay afirmación que no valga la pena hacer. Nunca debería preguntarse "¿debería afirmar esto o no?" Solo debes preguntarte "¿Hay algo que olvidé afirmar?"
fuente
A menos que el perfil muestre que las afirmaciones están causando problemas de rendimiento, digo que también deberían permanecer en la versión de producción.
Sin embargo, creo que esto también requiere que manejes las fallas de aserción de manera elegante. Por ejemplo, deberían dar como resultado un tipo general de diálogo con la opción de informar (automáticamente) el problema a los desarrolladores, y no simplemente cerrar o bloquear el programa. Además, debe tener cuidado de no usar aserciones para condiciones que realmente permite, pero que posiblemente no le gustan o consideran no deseadas. Esas condiciones deben ser manejadas por otras partes del código.
fuente
En mi C ++ defino REQUIRE (x) que es como afirmar (x), excepto que arroja una excepción si la afirmación falla en una versión de lanzamiento.
Dado que una afirmación fallida indica un error, debe tratarse seriamente incluso en una versión de lanzamiento. Cuando el rendimiento de mi código es importante, a menudo usaré REQUIRE () para código de nivel superior y afirmar () para código de nivel inferior que debe ejecutarse rápidamente. También uso REQUIRE en lugar de afirmar si la condición de falla puede ser causada por datos pasados del código escrito por un tercero o por corrupción de archivos (de manera óptima, diseñaría el código específicamente para que se comportara bien en caso de corrupción de archivos, pero nosotros no siempre tengo tiempo para hacer eso)
Dicen que no debe mostrar esos mensajes de afirmación a los usuarios finales porque no los entenderán. ¿Entonces? Los usuarios finales pueden enviarle un correo electrónico con una captura de pantalla o algún texto del mensaje de error, que le ayuda a depurar. Si el usuario simplemente dice "se bloqueó", tiene menos capacidad para solucionarlo. Sería mejor enviarte automáticamente los mensajes de fallo de aserción a través de Internet, pero eso solo funciona si el usuario tiene acceso a Internet y puedes obtener su permiso.
fuente
Si desea conservarlos, reemplácelos por manejo de errores. Nada peor que un programa simplemente desapareciendo. No veo nada malo en tratar ciertos errores como errores graves, pero deben dirigirse a una sección de su programa que esté equipada para tratarlos mediante la recopilación de datos, el registro y la información al usuario de que su aplicación ha tenido alguna condición no deseada y está saliendo
fuente
Siempre que se manejen como cualquier otro error, no veo ningún problema. Sin embargo, tenga en cuenta que las afirmaciones fallidas en C, como con otros lenguajes, simplemente saldrán del programa, y esto generalmente no es suficiente para los sistemas de producción.
Hay algunas excepciones: PHP, por ejemplo, le permite crear un controlador personalizado para las fallas de aserción para que pueda mostrar errores personalizados, hacer un registro detallado, etc. en lugar de simplemente salir.
fuente
Nuestro software de servidor de base de datos contiene afirmaciones de producción y depuración. Las afirmaciones de depuración son solo eso: se eliminan en el código de producción. Las afirmaciones de producción solo suceden si (a) existe alguna condición que nunca debería existir y (b) no es posible recuperarse confiablemente de esta condición. Una afirmación de producción indica que se ha encontrado un error en el software o se ha producido algún tipo de corrupción de datos.
Dado que este es un sistema de base de datos y estamos almacenando datos potencialmente críticos para la empresa, hacemos todo lo posible para evitar datos corruptos. Si existe una condición que puede hacer que almacenemos datos incorrectos, afirmamos de inmediato, revertimos todas las transacciones y detenemos el servidor.
Dicho esto, también tratamos de evitar aserciones de producción en rutinas críticas de rendimiento.
fuente
Veo afirmaciones como pruebas unitarias en línea. Útil para una prueba rápida durante el desarrollo, pero en última instancia, esas afirmaciones deben ser refactorizadas para ser probadas externamente en pruebas unitarias.
fuente
Creo que es mejor manejar todos los errores que están dentro del alcance, y usar aserciones para los supuestos que estamos afirmando SON verdaderos.
es decir, si su programa está abriendo / leyendo / cerrando un archivo, entonces no se puede abrir el archivo está dentro del alcance; es una posibilidad real, que sería negligente ignorar, en otras palabras. Entonces, eso debería tener un código de verificación de errores asociado.
Sin embargo, supongamos que su fopen () está documentado como siempre devolviendo un identificador de archivo abierto válido. Abre el archivo y lo pasa a su función readfile ().
Esa función de readfile, en este contexto, y probablemente de acuerdo con su especificación de diseño, puede suponer que obtendrá un ptr de archivo válido. Por lo tanto, sería un desperdicio agregar un código de manejo de errores para el caso negativo, en un programa tan simple. Sin embargo, al menos debe documentar la suposición, de alguna manera, asegurarse de alguna manera, de que este es realmente el caso, antes de continuar su ejecución. En realidad, no debe suponer que siempre será válido, en caso de que se llame incorrectamente, o se copie / pegue en otro programa, por ejemplo.
Entonces, readfile () {afirmar (fptr! = NULL); ..} es apropiado en este caso, mientras que el manejo completo de errores no lo es (ignorando el hecho de que leer el archivo requeriría algún sistema de manejo de errores de todos modos).
Y sí, esas afirmaciones deben permanecer en el código de producción, a menos que sea absolutamente necesario desactivarlas. Incluso entonces, probablemente debería deshabilitarlos solo dentro de las secciones críticas de rendimiento.
fuente
Supongamos que una pieza de código está en producción y llega a una afirmación que normalmente se activaría. La afirmación ha encontrado un error! Excepto que no, porque la afirmación está desactivada.
¿Qué pasa ahora? O bien el programa (1) se bloqueará de manera poco informativa en un punto más alejado de la fuente del problema, o (2) se ejecutará alegremente hasta su finalización, probablemente dando un resultado incorrecto.
Ninguno de los escenarios es atractivo. Deje las afirmaciones activas incluso en la producción.
fuente
Raramente uso aserciones para otra cosa que no sea la verificación de tipo de tiempo de compilación. Usaría una excepción en lugar de una aserción solo porque la mayoría de los idiomas están diseñados para manejarlos.
Ofrezco un ejemplo
en contra
¿Cómo manejaría la aplicación la afirmación? Prefiero el viejo
try catch
método de tratar con errores fatales.fuente
La mayoría de las veces, cuando uso la aserción en Java (la palabra clave de aserción) automáticamente agrego algunos códigos de producción después. Según el caso, puede ser un mensaje de registro, una excepción ... o nada.
Según yo, todas sus afirmaciones son críticas en el lanzamiento del desarrollador, no en la producción. Algunos de ellos deben mantenerse, otros deben descartarse.
fuente
Las ASERCIONES no son errores y no deben tratarse como errores. Cuando se lanza una afirmación, esto significa que hay un error en su código o, alternativamente, en el código que llama a su código.
Hay algunos puntos para evitar habilitar las aserciones en el código de producción: 1. No desea que su usuario final vea un mensaje como "ERROR EN LA ASERCIÓN MyPrivateClass.cpp línea 147. El usuario final NO es su ingeniero de control de calidad. 2. La ASISTENCIA podría influir en el rendimiento
Sin embargo, hay una razón importante para dejar afirmaciones: ASSERTION puede influir en el rendimiento y el tiempo, y lamentablemente esto a veces es importante (especialmente en los sistemas integrados).
Tiendo a votar por dejar la afirmación en el código de producción pero asegurándome de que estas impresiones de las afirmaciones no estén expuestas al usuario final.
~ Yitzik
fuente
Una afirmación es error, pura y simple y, por lo tanto, debe manejarse como tal.
Dado que un error debe manejarse en el modo de lanzamiento, realmente no necesita afirmaciones.
El principal beneficio que veo para las afirmaciones es una ruptura condicional: son mucho más fáciles de configurar que explorar a través de las ventanas de VC para configurar algo que requiere 1 línea de código.
fuente