¿Debería haber aserciones en las versiones de lanzamiento?

20

El comportamiento predeterminado de asserten C ++ es no hacer nada en las versiones de lanzamiento. Supongo que esto se hace por razones de rendimiento y tal vez para evitar que los usuarios vean mensajes de error desagradables.

Sin embargo, argumentaría que esas situaciones en las que un assertdispararía pero se deshabilitaría son aún más problemáticas porque la aplicación probablemente se bloqueará de una manera aún peor en el futuro porque se rompió alguna invariante.

Además, el argumento del rendimiento para mí solo cuenta cuando es un problema medible. La mayoría de los asserts en mi código no son mucho más complejos que

assert(ptr != nullptr);

lo que tendrá un pequeño impacto en la mayoría del código.

Esto me lleva a la pregunta: ¿Deberían las afirmaciones (es decir, el concepto, no la implementación específica) estar activas en las versiones de lanzamiento? Por qué no)?

Tenga en cuenta que esta pregunta no se trata de cómo habilitar afirmaciones en compilaciones de lanzamiento (como #undef _NDEBUGo usar una implementación de afirmación autodefinida). Además, no se trata de habilitar afirmaciones en código de biblioteca estándar / de terceros sino en código controlado por mí.

Nadie
fuente
Conozco a un jugador global en el mercado de atención médica que instaló una versión de depuración de su sistema de información hospitalaria en los sitios de los clientes. También tenían un acuerdo especial con Microsoft para instalar allí las bibliotecas de depuración de C ++. Bueno, la calidad de su producto era ...
Bernhard Hiller
2
Hay un viejo dicho que dice "eliminar afirmaciones es un poco como usar un chaleco salvavidas para practicar en el puerto, pero luego dejar los chalecos salvavidas cuando su barco parte hacia mar abierto" ( wiki.c2.com/?AssertionsAsDefensiveProgramming ) . Personalmente, los mantengo habilitados en las versiones de lanzamiento de forma predeterminada. Desafortunadamente, esta práctica no es muy común en el mundo de C ++, pero al menos el reconocido veterano de C ++ James Kanze siempre solía argumentar a favor de mantener las afirmaciones en las versiones de lanzamiento: stackoverflow.com/a/12162195/3313064
Christian Hackl

Respuestas:

20

El clásico assertes una herramienta de la antigua biblioteca estándar de C, no de C ++. Todavía está disponible en C ++, al menos por razones de compatibilidad con versiones anteriores.

No tengo una línea de tiempo precisa de las bibliotecas estándar de C disponibles, pero estoy bastante seguro de que assertestaba disponible poco después del momento en que K&R C entró en funcionamiento (alrededor de 1978). En el clásico C, para escribir programas robustos, la adición de pruebas de puntero NULL y la verificación de los límites de la matriz deben realizarse con mucha más frecuencia que en C ++. Se puede evitar el grueso de las pruebas de puntero NULL usando referencias y / o punteros inteligentes en lugar de punteros, y al usar std::vector, la comprobación de los límites de la matriz a menudo es innecesaria. Además, el rendimiento alcanzado en 1980 fue definitivamente mucho más importante que hoy. Así que creo que es muy probable que la razón por la cual "afirmar" se diseñó para estar activo solo en las compilaciones de depuración de forma predeterminada.

Además, para el manejo de errores reales en el código de producción, una función que solo prueba alguna condición o invariante, y bloquea el programa si la condición no se cumple, en la mayoría de los casos no es lo suficientemente flexible. Para la depuración, eso probablemente esté bien, ya que el que ejecuta el programa y observa el error generalmente tiene un depurador a mano para analizar lo que sucede. Sin embargo, para el código de producción, una solución sensata debe ser una función o mecanismo que

  • prueba alguna condición (y detiene la ejecución en el ámbito donde falla la condición)

  • proporciona un mensaje de error claro en caso de que la condición no se cumpla

  • permite que el alcance externo tome el mensaje de error y lo envíe a un canal de comunicación específico. Este canal puede ser algo así como stderr, un archivo de registro estándar, un cuadro de mensaje en un programa GUI, una devolución de llamada de manejo de errores general, un canal de error habilitado para la red o lo que mejor se adapte a la pieza de software en particular.

  • permite que el alcance externo en una base por caso decida si el programa debe finalizar correctamente o si debe continuar.

(Por supuesto, también hay situaciones en las que terminar el programa de inmediato en caso de una condición no cumplida es la única opción sensata, pero en tales casos, también debería ocurrir en una versión de lanzamiento, no solo en una versión de depuración).

Dado que el clásico assertno proporciona estas características, no es una buena opción para una compilación de lanzamiento, se supone que la compilación de lanzamiento es lo que se implementa en producción.

Ahora puede preguntar por qué no existe tal función o mecanismo en la biblioteca estándar de C que proporciona este tipo de flexibilidad. En realidad, en C ++, hay un mecanismo estándar que tiene todas estas características (y más), y lo sabes: se llama excepciones .

Sin embargo, en C es difícil implementar un buen mecanismo estándar de propósito general para el manejo de errores con todas las características mencionadas debido a la falta de excepciones como parte del lenguaje de programación. Por lo tanto, la mayoría de los programas C tienen sus propios mecanismos de manejo de errores con códigos de retorno, o "goto", o "saltos largos", o una mezcla de eso. Estas son a menudo soluciones pragmáticas que se ajustan al tipo particular de programa, pero no son "de propósito general" para caber en la biblioteca estándar de C.

Doc Brown
fuente
Ah, me olvidé por completo de la herencia C (después de todo #include <cassert>). Eso tiene mucho sentido ahora.
Nadie
1
Estoy completamente en desacuerdo con toda esta respuesta. Lanzar una excepción cuando su aplicación descubrió que su código fuente tenía errores es el último recurso en lenguajes como Java que no pueden funcionar mejor, pero en C ++, por supuesto, finalice el programa inmediatamente en tal situación. Usted no quiere relajarse pila de causar cualquier otra operación que se ejecuten en ese punto. Un programa con errores puede escribir datos posiblemente corruptos en archivos, bases de datos o tomas de red. Simplemente bloquee lo antes posible (y posiblemente haga que el proceso sea reiniciado por un mecanismo externo).
Christian Hackl
1
@ChristianHackl: Estoy de acuerdo en que hay situaciones en las que la terminación de un programa es la única opción viable, pero también debería suceder en el modo de lanzamiento, y también assertes la herramienta incorrecta para esto (lanzar una excepción puede ser también la reacción incorrecta ) Sin embargo, estoy bastante seguro de que en realidad asserttambién se usó para muchas pruebas en C, donde en C ++ se usarían excepciones hoy.
Doc Brown
15

Si desea que las afirmaciones se hayan habilitado en una versión, le ha pedido a las afirmaciones que hagan el trabajo incorrecto.

El punto de las afirmaciones es que no están habilitadas en una versión. Esto permite la prueba de invariantes durante el desarrollo con código que de otro modo tendría que ser código de andamiaje. Código que debe eliminarse antes del lanzamiento.

Si tiene algo que cree que debe probarse incluso durante el lanzamiento, escriba un código que lo pruebe. La If throwconstrucción funciona muy bien. Si desea decir algo diferente a los otros lanzamientos, simplemente use una excepción descriptiva que diga lo que desea decir.

No es que no puedas cambiar la forma en que usas las afirmaciones. Es que hacerlo no te está dando nada útil, va en contra de las expectativas y no te deja una manera limpia de hacer lo que las afirmaciones deben hacer. Agregar pruebas que están inactivas en una versión.

No estoy hablando de una implementación específica de aserción, sino del concepto de una aserción. No quiero hacer mal uso de afirmar o confundir a los lectores. Quise preguntar por qué es así en primer lugar. ¿Por qué no hay release_assert adicional? ¿No hay necesidad de ello? ¿Cuál es la razón detrás de afirmar que se deshabilita en la versión? - nadie

¿Por qué no relase_assert? Francamente porque las afirmaciones no son lo suficientemente buenas para la producción. Sí, hay una necesidad, pero nada satisface esa necesidad. Oh, seguro que puedes diseñar el tuyo. Mecánicamente, su función throwIf solo necesita un bool y una excepción para lanzar. Y eso puede satisfacer sus necesidades. Pero realmente estás limitando el diseño. Es por eso que no me sorprende que no haya un sistema de lanzamiento de excepciones en su biblioteca de idiomas. Ciertamente no es que no puedas hacerlo. Otros tienen . Pero lidiar con el caso en que las cosas van mal es el 80% del trabajo para la mayoría de los programas. Y hasta ahora nadie nos ha mostrado una buena solución única para todos. Tratar eficazmente estos casos puede complicarse. Si hubiéramos tenido un sistema enlazado release_assert que no cumpliera con nuestras necesidades, creo que habría hecho más daño que bien. Estás pidiendo una buena abstracción que significaría que no tendrías que pensar en este problema. Yo también quiero uno pero no parece que estemos allí todavía.

¿Por qué se desactivan las afirmaciones en la versión? Las afirmaciones se crearon a la altura de la era del código de andamios. Código que tuvimos que eliminar porque sabía que no lo queríamos en producción, pero sabíamos que queríamos ejecutarlo en desarrollo para ayudarnos a encontrar errores. Las afirmaciones eran una alternativa más limpia al if (DEBUG)patrón que nos permitía dejar el código pero deshabilitarlo. Esto fue antes de que las pruebas unitarias despegaran como la forma principal de separar el código de prueba del código de producción. Las afirmaciones todavía se usan hoy en día, incluso por probadores expertos de la unidad, tanto para aclarar las expectativas como para cubrir los casos en que todavía funcionan mejor que las pruebas unitarias.

¿Por qué no simplemente dejar el código de depuración en producción? Debido a que el código de producción no debe avergonzar a la empresa, no formatear el disco duro, no dañar la base de datos y no enviar correos electrónicos amenazantes al presidente. En resumen, es bueno poder escribir código de depuración en un lugar seguro donde no tenga que preocuparse por eso.

naranja confitada
fuente
2
Supongo que mi pregunta es: ¿Por qué se debe eliminar este código antes del lanzamiento? Las comprobaciones no son una gran pérdida de rendimiento y si fallan definitivamente hay un problema sobre el que preferiría un mensaje de error más directo. ¿Qué ventaja me ofrece el uso de una excepción en lugar de una afirmación? Probablemente no quisiera que un código no relacionado pueda catch(...)hacerlo.
Nadie el
2
@ Nadie La mayor ventaja de no usar afirmaciones para necesidades que no son afirmativas es no confundir a sus lectores. Si no desea deshabilitar el código, no use modismos que indiquen que lo será. Es tan malo como usar if (DEBUG)para controlar algo más que el código de depuración. La micro optimización puede no significar nada en su caso. Pero el idioma no debe ser subvertido solo porque no lo necesitas.
candied_orange
Creo que no hice mi intención lo suficientemente clara. No estoy hablando de una implementación específica assertsino del concepto de una afirmación. No quiero abusar asserto confundir a los lectores. Quise preguntar por qué es así en primer lugar. ¿Por qué no hay más release_assert? ¿No hay necesidad de ello? ¿Cuál es la razón detrás de afirmar que se deshabilita en la versión?
Nadie
2
You're asking for a good abstraction.No estoy seguro de eso. Principalmente quiero tratar problemas donde no hay recuperación y eso nunca debería suceder. Tome esto junto Because production code needs to [...] not format the hard drive [...]y diría que para los casos en que los invariantes están rotos, tomaría una declaración de liberación sobre UB en cualquier momento.
Nadie
1
@Nadie "los problemas donde no hay recuperación" pueden tratarse lanzando excepciones y no atrapándolos. Puede observar que nunca deberían suceder en el texto del mensaje de la excepción.
candied_orange
4

Las afirmaciones son una herramienta de depuración , no una técnica de programación defensiva. Si desea realizar la validación en todas las circunstancias, realice la validación escribiendo un condicional, o cree su propia macro para reducir la repetitiva.

amon
fuente
4

assertes una forma de documentación, como comentarios. Al igual que los comentarios, normalmente no los enviaría a los clientes, ya que no pertenecen al código de lanzamiento.

Pero el problema con los comentarios es que pueden quedar desactualizados y, sin embargo, se quedan. Es por eso que las afirmaciones son buenas: se verifican en modo de depuración. Cuando la afirmación se vuelve obsoleta, la descubres rápidamente y sabrás cómo solucionarla. ¿Ese comentario que quedó obsoleto hace 3 años? Cualquiera lo adivina.

MSalters
fuente
1
Entonces, ¿abortar en una invariante fallida antes de que algo suceda no es un caso de uso válido?
Nadie
3

Si no desea que se desactive una "afirmación", no dude en escribir una función simple que tenga un efecto similar:

void fail_if(bool b) {if(!b) std::abort();}

Es decir, assertes para las pruebas en el que hacer desea que se vayan en el producto enviado. Si desea que esa prueba sea parte del comportamiento definido del programa, assertes la herramienta incorrecta.

Nicol Bolas
fuente
1
Soy muy consciente de esto. La pregunta es más similar a por qué el valor predeterminado es como es.
Nadie el
3

No tiene sentido argumentar qué afirmación debería hacer, hace lo que hace. Si quieres algo diferente, escribe tu propia función. Por ejemplo, tengo Assert que se detiene en el depurador o no hace nada, tengo AssertFatal que bloqueará la aplicación, tengo funciones bool Asserted y AssertionFailed que afirman y devuelven el resultado para poder afirmar y manejar la situación.

Para cualquier problema inesperado, debe decidir cuál es la mejor manera para que el desarrollador y el usuario lo manejen.

gnasher729
fuente
No era mi intención discutir sobre qué afirmación debería hacer. Mi motivación para esta pregunta fue encontrar que el razonamiento detrás de las afirmaciones no está en la versión de lanzamiento porque estoy a punto de escribir el mío y quiero recopilar información sobre casos de uso, expectativas y trampas.
Nadie el
Hm, ¿no verify(cond)sería la forma normal de afirmar y devolver el resultado?
Deduplicador el
1
Estoy codificando en Ruby, no en C, pero no estoy de acuerdo con la mayoría de las respuestas anteriores, ya que detener el programa con la impresión de una traza inversa funciona bien para mí como una técnica de programación defensiva ... mi comentario no encajaba tamaño máximo de comentario en caracteres, así que escribí otra respuesta a continuación.
Nakilon
2

Como otros señalaron, assertes el último bastión de defensa contra los errores del programador que nunca debería suceder. Son controles de cordura que, con suerte, no deberían fallar de izquierda a derecha en el momento de su envío.

También está diseñado para omitirse de las versiones de lanzamiento estables, por cualquier motivo que los desarrolladores puedan encontrar útil: estética, rendimiento, lo que quieran. Es parte de lo que separa una compilación de depuración de una compilación de lanzamiento, y por definición, una compilación de lanzamiento carece de tales afirmaciones. Por lo tanto, hay una subversión del diseño si desea lanzar la versión analógica "build build con aserciones en su lugar", que sería un intento de una versión de lanzamiento con una _DEBUGdefinición de preprocesador y no NDEBUGdefinida; ya no es una versión de lanzamiento.

El diseño se extiende incluso a la biblioteca estándar. Como un ejemplo muy básico entre numerosas, muchas implementaciones de std::vector::operator[]será assertuna comprobación de validez para asegurarse de que no está comprobando el vector fuera de límites. Y la biblioteca estándar comenzará a funcionar mucho, mucho peor si habilita tales comprobaciones en una versión de lanzamiento. Un punto de referencia del vectorusooperator[]y un controlador de relleno con tales afirmaciones incluidas en una matriz dinámica antigua simple a menudo mostrará que la matriz dinámica es considerablemente más rápida hasta que deshabilite tales comprobaciones, por lo que a menudo impactan el rendimiento de maneras muy, muy poco triviales. Una verificación de puntero nulo aquí y una verificación fuera de límites allí en realidad puede convertirse en un gasto enorme si tales verificaciones se aplican millones de veces sobre cada cuadro en los bucles críticos que preceden al código, tan simple como desreferenciar un puntero inteligente o acceder a una matriz.

Por lo tanto, es muy probable que desee una herramienta diferente para el trabajo y una que no esté diseñada para omitirse de las versiones de lanzamiento si desea versiones de lanzamiento que realicen tales controles de cordura en áreas clave. Lo más útil que personalmente encuentro es el registro. En ese caso, cuando un usuario informa un error, las cosas se vuelven mucho más fáciles si adjuntan un registro y la última línea del registro me da una gran pista sobre dónde ocurrió el error y cuál podría ser. Luego, al reproducir sus pasos en una compilación de depuración, también podría obtener un error de aserción, y ese error de aserción me da más pistas para optimizar mi tiempo. Sin embargo, dado que el registro es relativamente costoso, no lo uso para aplicar controles de cordura de nivel extremadamente bajo, como asegurarme de que no se acceda a una matriz fuera de los límites en una estructura de datos genérica.

Sin embargo, finalmente, y algo de acuerdo con usted, pude ver un caso razonable en el que es posible que desee entregar a los evaluadores algo parecido a una construcción de depuración durante las pruebas alfa, por ejemplo, con un pequeño grupo de evaluadores alfa que, por ejemplo, firmaron un NDA . Allí podría simplificar las pruebas alfa si le entrega a sus probadores algo más que una compilación de lanzamiento completo con información de depuración adjunta junto con algunas características de depuración / desarrollo, como pruebas que pueden ejecutar y resultados más detallados mientras ejecutan el software. Al menos he visto a algunas grandes compañías de juegos haciendo cosas así por alfa. Pero eso es para algo como alfa o pruebas internas en las que realmente intentas darle a los evaluadores algo más que una versión de lanzamiento. Si realmente está intentando enviar una versión de lanzamiento, entonces, por definición, no debería tener_DEBUG definido o de lo contrario eso es realmente confuso la diferencia entre una compilación "depuración" y "lanzamiento".

¿Por qué se debe eliminar este código antes del lanzamiento? Las comprobaciones no son una gran pérdida de rendimiento y si fallan definitivamente hay un problema sobre el que preferiría un mensaje de error más directo.

Como se señaló anteriormente, las comprobaciones no son necesariamente triviales desde el punto de vista del rendimiento. Es probable que muchos sean triviales, pero una vez más, incluso la lib estándar los usa y podría afectar el rendimiento de manera inaceptable para muchas personas en muchos casos si, por ejemplo, el recorrido de acceso aleatorio demora std::vector4 veces más en lo que se supone que es una versión de lanzamiento optimizada debido a sus límites de comprobación que nunca se supone que debe fallar.

En un antiguo equipo, en realidad teníamos que hacer que nuestra matriz y biblioteca de vectores excluyeran algunas afirmaciones en ciertas rutas críticas solo para hacer que las compilaciones de depuración se ejecutaran más rápido, porque esas afirmaciones estaban ralentizando las operaciones matemáticas en un orden de magnitud hasta el punto donde estaba comenzando a exigirnos que esperemos 15 minutos antes de que incluso podamos rastrear el código de interés. Mis colegas en realidad solo querían eliminar elassertsdirectamente porque descubrieron que solo hacer eso hizo una gran diferencia. En su lugar, decidimos simplemente hacer que las rutas críticas de depuración las eviten. Cuando hicimos que esas rutas críticas usaran los datos de vector / matriz directamente sin pasar por la verificación de límites, el tiempo requerido para realizar la operación completa (que incluía más que solo matemática de vector / matriz) se redujo de minutos a segundos. Es un caso extremo, pero definitivamente las afirmaciones no siempre son insignificantes desde el punto de vista del rendimiento, ni siquiera cercanas.

Pero también es así como assertsestán diseñados. Si no tuvieran un impacto tan grande en el rendimiento en todos los ámbitos, entonces podría favorecerlo si se diseñaron como algo más que una función de compilación de depuración o podríamos usarlo, vector::atque incluye la verificación de límites incluso en versiones de lanzamiento y lanzamientos fuera de los límites acceso, por ejemplo (pero con un gran éxito de rendimiento). Pero actualmente considero que su diseño es mucho más útil, dado su enorme impacto en el rendimiento en mis casos, como una función de depuración de solo compilación que se omite cuando NDEBUGse define. Para los casos en los que he trabajado al menos, hace una gran diferencia para una versión de lanzamiento excluir las comprobaciones de cordura que nunca deberían fallar en primer lugar.

vector::at vs. vector::operator[]

Creo que la distinción de estos dos métodos es esencial para esto, así como la alternativa: excepciones. vector::operator[]implementaciones típicamente assertpara asegurarse de que el acceso fuera de límites desencadenará un error fácilmente reproducible al intentar acceder a un vector fuera de límites. Pero los implementadores de la biblioteca hacen esto con el supuesto de que no costará ni un centavo en una versión de lanzamiento optimizada.

Mientras tanto, vector::atse proporciona que siempre realiza la verificación fuera de límites y lanza incluso en las versiones de lanzamiento, pero tiene una penalización de rendimiento hasta el punto en que a menudo veo mucho más uso de código vector::operator[]que vector::at. Gran parte del diseño de C ++ se hace eco de la idea de "pagar por lo que usa / necesita", y muchas personas a menudo prefieren operator[], lo que ni siquiera se molesta con los límites de verificación en las versiones de lanzamiento, en función de la idea de que no No es necesario que los límites verifiquen sus versiones de lanzamiento optimizadas. De repente, si las aserciones se habilitaran en las versiones de lanzamiento, el rendimiento de estos dos sería idéntico y el uso del vector siempre terminaría siendo más lento que una matriz dinámica. Por lo tanto, una gran parte del diseño y el beneficio de las afirmaciones se basa en la idea de que se vuelven gratuitas en una versión de lanzamiento.

release_assert

Esto es interesante después de descubrir estas intenciones. Naturalmente, los casos de uso de cada persona serían diferentes, pero creo que encontraría algún uso para el release_assertque realiza la comprobación y bloqueará el software que muestra un número de línea y un mensaje de error incluso en las versiones de lanzamiento.

Sería para algunos casos oscuros en mi caso donde no quiero que el software se recupere con gracia como lo haría si se lanzara una excepción. Me gustaría que se bloqueara incluso en el lanzamiento en esos casos para que el usuario pueda recibir un número de línea para informar cuando el software encontró algo que nunca debería suceder, aún en el ámbito de las comprobaciones de cordura para errores de programador, no errores de entrada externos como excepciones, pero lo suficientemente barato como para hacerse sin preocuparse por su costo de lanzamiento.

En realidad, hay algunos casos en los que sería preferible un bloqueo duro con un número de línea y un mensaje de error que recuperar con gracia una excepción lanzada que podría ser lo suficientemente barata como para mantenerla en una versión. Y hay algunos casos en los que es imposible recuperarse de una excepción, como un error encontrado al intentar recuperarse de una existente. Allí encontraría un ajuste perfecto para, release_assert(!"This should never, ever happen! The software failed to fail!");y, naturalmente, sería muy barato, ya que la verificación se realizaría dentro de una ruta excepcional en primer lugar y no costaría nada en las rutas de ejecución normales.


fuente
Mi intención no era habilitar afirmaciones en código de terceros, vea la edición aclaratoria. La cita de mi comentario omite el contexto de mi pregunta: Additionally, the performance argument for me only counts when it is a measurable problem.Entonces, la idea es decidir caso por caso cuándo sacar una afirmación de la publicación.
Nadie
Uno de los problemas con el último comentario es que la biblioteca estándar usa lo mismo assertque se basa en los mismos _DEBUG/NDEBUGdefs de preprocesador que usaría cuando usa la assertmacro. Por lo tanto, no hay forma de habilitar selectivamente las aserciones solo para una pieza de código sin habilitarla también para la biblioteca estándar, por ejemplo, suponiendo que use la biblioteca estándar.
Hay una comprobación de iterador STL que puede deshabilitar por separado, lo que deshabilita algunas de las afirmaciones, pero no todas.
Básicamente es una herramienta gruesa, no granular, y siempre con la intención de diseño de ser deshabilitada en el lanzamiento, por lo que sus compañeros de equipo podrían usarla en áreas críticas contra el supuesto de que no afectará el rendimiento del lanzamiento, la biblioteca estándar lo usa en áreas críticas, otras librerías de terceros lo usan de esa manera, etc. Y cuando desee algo, puede deshabilitar / habilitar más específicamente un código y no el otro, volvemos a buscar otra cosa que no sea assert.
vector::operator[]y vector::at, por ejemplo, tendría prácticamente el mismo rendimiento si se habilitaran las aserciones en las compilaciones de lanzamiento, y no tendría sentido usarlo operator[]más desde el punto de vista del rendimiento, ya que de todos modos estaría haciendo la comprobación de límites.
2

Estoy codificando en Ruby, no en C / C ++, por lo que no hablaré sobre la diferencia entre afirmaciones y excepciones, pero me gustaría hablar de eso como algo que detiene el tiempo de ejecución . No estoy de acuerdo con la mayoría de las respuestas anteriores, ya que detener el programa con la impresión de una traza inversa funciona bien para mí como técnica de programación defensiva.
Si hay una manera de invocar la rutina de aserción (absolutamente no importa cómo se escriba sintácticamente y si se usa o existe la palabra "afirmar" en el lenguaje de programación o dsl), eso significa que se debe hacer algún trabajo y el producto inmediatamente vuelve del "lanzamiento, listo para usar" a "necesita parche" - ahora reescríbalo en un manejo de excepciones real o repara un error que causa que aparezcan datos incorrectos.

Quiero decir que Assert no es algo con lo que debas vivir y llamar con frecuencia: es una señal de parada que indica que debes hacer algo para que nunca vuelva a suceder. Y decir que "la versión de lanzamiento no debería tener afirmaciones" es como decir "la versión de lanzamiento no debería tener errores" - amigo, es casi imposible, lidiar con eso.
O piense en ellos como "pruebas unitarias fallidas realizadas y ejecutadas por el usuario final". No puede predecir todas las cosas que el usuario va a hacer con su programa, pero si algo demasiado serio sale mal, debería detenerse; esto es similar a cómo construye las tuberías de compilación: detiene el proceso y no publica, ¿no es así? ? La afirmación obliga al usuario a detenerse, informar y esperar su ayuda.

Nakilon
fuente