Los Go
creadores del lenguaje escriben :
Ir no proporciona afirmaciones. Son innegablemente convenientes, pero nuestra experiencia ha sido que los programadores los usan como una muleta para evitar pensar en el manejo adecuado de los errores y la presentación de informes. El manejo adecuado de errores significa que los servidores continúan operando después de errores no fatales en lugar de fallar. El informe de errores adecuado significa que los errores son directos y al grano, evitando que el programador interprete una gran traza de bloqueo. Los errores precisos son particularmente importantes cuando el programador que ve los errores no está familiarizado con el código.
Cuál es tu opinión acerca de esto?
reflect.DeepEqual
, ciertamente no lo necesitas . Es conveniente, pero a costa del rendimiento (las pruebas unitarias son un buen caso de uso). De lo contrario, puede implementar cualquier verificación de igualdad que sea apropiada para su "colección" sin demasiados problemas.for
bucle en Go (al igual que C). Se podría ser muy bueno tener operaciones rebanada genéricos, aunque la comparación se complica cuando los punteros y las estructuras son los involucrados.Respuestas:
No, no tiene nada de malo
assert
, siempre y cuando lo uses según lo previstoEs decir, se supone que es para detectar casos que "no pueden suceder", durante la depuración, en oposición al manejo normal de errores.
fuente
No, ni
goto
tampocoassert
son malvados. Pero ambos pueden ser mal utilizados.Afirmar es para controles de cordura. Cosas que deberían matar al programa si no son correctas. No es para validación o como un reemplazo para el manejo de errores.
fuente
goto
sabiamente?goto
por razones puramente religiosas, luego simplemente usa engoto
lugar de ofuscar lo que estás haciendo. En otras palabras: si puede demostrar que realmente lo necesitagoto
, y la única alternativa es promulgar una carga de andamios sin sentido que finalmente haga lo mismo pero sin alterar a la Policía de Goto ... entonces simplemente usegoto
. Por supuesto, una condición previa de esto es el bit "si puedes demostrar que realmente lo necesitasgoto
". A menudo, la gente no. Eso todavía no significa que sea algo inherentemente malo.goto
se usa en el kernel de Linux para la limpieza del códigoSegún esa lógica, los puntos de interrupción también son malos.
Las afirmaciones deben usarse como una ayuda de depuración, y nada más. "Mal" es cuando intentas usarlos en lugar de manejar errores.
Las afirmaciones están ahí para ayudarlo a usted, el programador, a detectar y solucionar problemas que no deben existir y verificar que sus suposiciones se mantengan verdaderas.
No tienen nada que ver con el manejo de errores, pero desafortunadamente, algunos programadores abusan de ellos como tales y luego los declaran "malvados".
fuente
Me gusta usar afirmar mucho. Me resulta muy útil cuando estoy creando aplicaciones por primera vez (tal vez para un nuevo dominio). En lugar de hacer una comprobación de errores muy sofisticada (que consideraría una optimización prematura) codifico rápido y agrego muchas afirmaciones. Después de saber más sobre cómo funcionan las cosas, reescribo y elimino algunas de las afirmaciones y las cambio para un mejor manejo de errores.
Debido a las afirmaciones, paso mucho menos tiempo codificando / depurando programas.
También he notado que las afirmaciones me ayudan a pensar en muchas cosas que podrían romper mis programas.
fuente
Como información adicional, go proporciona una función incorporada
panic
. Esto se puede usar en lugar deassert
. P.ejpanic
imprimirá el seguimiento de la pila, por lo que de alguna manera tiene el propósito deassert
.fuente
Deben usarse para detectar errores en el programa. No está mal la entrada del usuario.
Si se utiliza correctamente, son no el mal.
fuente
Esto surge mucho, y creo que un problema que confunde las defensas de las afirmaciones es que a menudo se basan en la verificación de argumentos. Considere este ejemplo diferente de cuándo podría usar una afirmación:
Utiliza una excepción para la entrada porque espera que a veces reciba malas entradas. Afirma que la lista está ordenada para ayudarlo a encontrar un error en su algoritmo, que por definición no espera. La afirmación está solo en la compilación de depuración, por lo que, aunque la verificación es costosa, no le importa hacerlo en cada invocación de la rutina.
Todavía tiene que hacer una prueba unitaria de su código de producción, pero esa es una forma diferente y complementaria de asegurarse de que su código sea correcto. Las pruebas unitarias aseguran que su rutina esté a la altura de su interfaz, mientras que las afirmaciones son una forma más precisa de asegurarse de que su implementación esté haciendo exactamente lo que espera que haga.
fuente
Las afirmaciones no son malas, pero pueden ser mal utilizadas fácilmente. Estoy de acuerdo con la afirmación de que "las afirmaciones a menudo se usan como una muleta para evitar pensar en el manejo y la notificación de errores adecuados". He visto esto con bastante frecuencia.
Personalmente, me gusta usar aserciones porque documentan suposiciones que podría haber hecho al escribir mi código. Si estos supuestos se rompen mientras se mantiene el código, el problema se puede detectar durante la prueba. Sin embargo, hago el punto de eliminar cada aserción de mi código cuando hago una compilación de producción (es decir, usando #ifdefs). Al eliminar las afirmaciones en la construcción de producción, elimino el riesgo de que alguien las use como una muleta.
También hay otro problema con las afirmaciones. Las afirmaciones solo se verifican en tiempo de ejecución. Pero a menudo ocurre que la verificación que le gustaría realizar podría haberse realizado en tiempo de compilación. Es preferible detectar un problema en tiempo de compilación. Para los programadores de C ++, boost proporciona BOOST_STATIC_ASSERT que le permite hacer esto. Para los programadores de C, este artículo ( texto de enlace ) describe una técnica que se puede utilizar para realizar aserciones en tiempo de compilación.
En resumen, la regla general que sigo es: No use aserciones en una compilación de producción y, si es posible, solo use aserciones para cosas que no pueden verificarse en tiempo de compilación (es decir, deben verificarse en tiempo de ejecución).
fuente
Admito haber usado afirmaciones sin considerar los informes de errores adecuados. Sin embargo, eso no quita que sean muy útiles cuando se usan correctamente.
Son especialmente útiles si desea seguir el principio "Crash Early". Por ejemplo, suponga que está implementando un mecanismo de conteo de referencias. En ciertas ubicaciones de su código, sabe que el recuento debe ser cero o uno. Y también suponga que si el recuento es incorrecto, el programa no se bloqueará de inmediato, pero durante el siguiente bucle de mensajes en ese punto será difícil descubrir por qué las cosas salieron mal. Una afirmación habría sido útil para detectar el error más cerca de su origen.
fuente
Prefiero evitar el código que hace cosas diferentes en depuración y lanzamiento.
Sin embargo, es útil romper el depurador en una condición y tener toda la información de archivo / línea, también la expresión exacta y el valor exacto.
Tener una afirmación que "evalúe la condición solo en la depuración" puede ser una optimización del rendimiento y, como tal, útil solo en el 0,0001% de los programas, donde las personas saben lo que están haciendo. En todos los demás casos, esto es perjudicial, ya que la expresión en realidad puede cambiar el estado del programa:
assert(2 == ShroedingersCat.GetNumEars());
haría que el programa hiciera cosas diferentes en depuración y lanzamiento.Hemos desarrollado un conjunto de macros de aserción que arrojarían una excepción, y lo hacen tanto en versión de depuración como de lanzamiento. Por ejemplo,
THROW_UNLESS_EQ(a, 20);
lanzaría una excepción con el mensaje what () que tiene tanto el archivo, la línea y los valores reales de a, y así sucesivamente. Solo una macro tendría el poder para esto. El depurador se puede configurar para que se rompa al 'lanzar' el tipo de excepción específico.fuente
No me gusta afirma intensamente. Sin embargo, no iría tan lejos como para decir que son malvados.
Básicamente, una afirmación hará lo mismo que una excepción no verificada, la única excepción es que la afirmación (normalmente) no debe mantenerse para el producto final.
Si construye una red de seguridad para usted mientras depura y construye el sistema, ¿por qué negaría esta red de seguridad a su cliente, a su servicio de asistencia o a cualquier persona que pueda utilizar el software que está construyendo actualmente? Use excepciones exclusivamente para afirmaciones y situaciones excepcionales. Al crear una jerarquía de excepciones apropiada, podrá discernir muy rápidamente una de la otra. Excepto esta vez, la afirmación permanece en su lugar y puede proporcionar información valiosa en caso de falla que de otro modo se perdería.
Así que entiendo completamente a los creadores de Go al eliminar las afirmaciones por completo y forzar a los programadores a usar excepciones para manejar la situación. Hay una explicación simple para esto, la excepción es solo un mejor mecanismo para el trabajo ¿por qué quedarse con las afirmaciones arcaicas?
fuente
Respuesta corta: No, creo que las afirmaciones pueden ser útiles.
fuente
Recientemente comencé a agregar algunas afirmaciones a mi código, y así es como lo he estado haciendo:
Divido mentalmente mi código en código de límite y código interno. El código de límite es un código que maneja la entrada del usuario, lee archivos y obtiene datos de la red. En este código, solicito la entrada en un bucle que solo sale cuando la entrada es válida (en el caso de la entrada interactiva del usuario), o lanzo excepciones en el caso de datos corruptos de archivos / redes irrecuperables.
El código interno es todo lo demás. Por ejemplo, una función que establece una variable en mi clase podría definirse como
y una función que recibe información de una red podría leerse como tal:
Esto me da dos capas de cheques. Cualquier cosa en la que los datos se determinen en tiempo de ejecución siempre recibe una excepción o un manejo inmediato de errores. Sin embargo, ese chequeo adicional
Class::f
con laassert
declaración significa que si alguna vez llama un código internoClass::f
, todavía tengo un chequeo de cordura. Es posible que mi código interno no pase un argumento válido (porque puedo haber calculado avalue
partir de una serie compleja de funciones), por lo que me gusta tener la afirmación en la función de configuración para documentar que, independientemente de quién llame a la función,value
no debe ser mayor que o igual aend
.Esto parece encajar en lo que estoy leyendo en algunos lugares, que las afirmaciones deberían ser imposibles de violar en un programa que funcione bien, mientras que las excepciones deberían ser para casos excepcionales y erróneos que todavía son posibles. Debido a que, en teoría, estoy validando todas las entradas, no debería ser posible que se active mi afirmación. Si es así, mi programa está equivocado.
fuente
Si las afirmaciones de las que está hablando significan que el programa vomita y luego existe, las afirmaciones pueden ser muy malas. Esto no quiere decir que siempre sean algo incorrecto, son una construcción que se usa mal fácilmente. También tienen muchas mejores alternativas. Cosas como esas son buenas candidatas para ser llamadas malvadas.
Por ejemplo, un módulo de terceros (o cualquier módulo realmente) casi nunca debería salir del programa de llamada. Esto no le da al programador de llamadas ningún control sobre el riesgo que el programa debería tomar en ese momento. En muchos casos, los datos son tan importantes que incluso guardar datos corruptos es mejor que perderlos. Las afirmaciones pueden obligarlo a perder datos.
Algunas alternativas para afirmar:
Algunas referencias:
Incluso las personas que abogan por la afirmación piensan que solo deberían usarse en el desarrollo y no en la producción:
Esta persona dice que las afirmaciones deben usarse cuando el módulo tiene datos potencialmente corruptos que persisten después de que se lanza una excepción: http://www.advogato.org/article/949.html . Sin duda, este es un punto razonable, sin embargo, un módulo externo nunca debe prescribir la importancia de los datos corruptos para el programa que realiza la llamada (al salir "para" ellos). La forma correcta de manejar esto es lanzando una excepción que deja en claro que el programa ahora puede estar en un estado inconsistente. Y dado que los buenos programas consisten principalmente en módulos (con un pequeño código de pegamento en el ejecutable principal), las afirmaciones son casi siempre algo incorrecto.
fuente
assert
es muy útil y puede ahorrarle mucho retroceso cuando se producen errores inesperados al detener el programa ante los primeros signos de problemas.Por otro lado, es muy fácil abusar
assert
.La versión correcta y correcta sería algo así como:
Entonces ... a la larga ... en el panorama general ... Debo estar de acuerdo en que
assert
se puede abusar de él. Lo hago todo el tiempo.fuente
assert
se está abusando para el manejo de errores porque se escribe menos.Por lo tanto, como diseñadores de idiomas, deberían ver que el manejo adecuado de errores se puede hacer con una escritura aún menor. Excluir afirmar porque su mecanismo de excepción es detallado no es la solución. Oh, espera, Go tampoco tiene excepciones. Demasiado :)
fuente
Sentí ganas de patear al autor en la cabeza cuando vi eso.
Utilizo afirma todo el tiempo en código y eventualmente los reemplazo cuando escribo más código. Los uso cuando no he escrito la lógica requerida y quiero recibir una alerta cuando me encuentro con el código en lugar de escribir una excepción que se eliminará a medida que el proyecto se acerque a su finalización.
Las excepciones también se mezclan con el código de producción más fácilmente, lo que no me gusta. Una afirmación es más fácil de notar que
throw new Exception("Some generic msg or 'pretend i am an assert'");
fuente
Mi problema con estas respuestas al defender la afirmación es que nadie especifica claramente qué lo hace diferente de un error fatal regular y por qué una afirmación no puede ser un subconjunto de una excepción . Ahora, con esto dicho, ¿qué pasa si la excepción nunca se detecta? ¿Eso lo convierte en una afirmación por nomenclatura? Y, ¿por qué querrías imponer una restricción en el lenguaje para que se pueda generar una excepción que / nada / pueda manejar?
fuente
func()
con un número negativo. Ahora, de repente con tus afirmaciones, me has quitado la alfombra y no me has dado la oportunidad de recuperarme, en lugar de decirme cortésmente que lo que estoy pidiendo no se puede hacer. No hay nada de malo en acusar al programa de portarse mal y emitir una citación: el problema es que está borrando el acto de hacer cumplir una ley y condenando al delincuente.Sí, afirma que son malvados.
A menudo se utilizan en lugares donde se debe utilizar el manejo adecuado de errores. ¡Acostúmbrese a escribir el manejo adecuado de errores de calidad de producción desde el principio!
Por lo general, se interponen en la escritura de pruebas unitarias (a menos que escriba una afirmación personalizada que interactúe con su arnés de prueba). Esto a menudo se debe a que se usan donde se debe usar el manejo adecuado de errores.
En su mayoría, se compilan a partir de versiones de lanzamiento, lo que significa que ninguna de sus "pruebas" está disponible cuando está ejecutando el código que realmente publica; Dado que en situaciones de subprocesos múltiples, los peores problemas a menudo solo aparecen en el código de lanzamiento, esto puede ser malo.
A veces son una muleta para diseños rotos; es decir, el diseño del código permite que un usuario lo llame de una manera que no debería llamarse y la afirmación "evita" esto. ¡Arregla el diseño!
Escribí más sobre esto en mi blog en 2005 aquí: http://www.lenholgate.com/blog/2005/09/assert-is-evil.html
fuente
No tanto mal como generalmente contraproducente. Hay una separación entre la comprobación de errores permanente y la depuración La afirmación hace que la gente piense que toda depuración debe ser permanente y causa problemas de legibilidad masivos cuando se usa mucho. El manejo permanente de errores debería ser mejor que eso cuando sea necesario, y dado que la afirmación causa sus propios errores, es una práctica bastante cuestionable.
fuente
Nunca uso aserción (), los ejemplos generalmente muestran algo así:
Esto es malo, nunca hago esto, ¿qué pasa si mi juego está asignando un montón de monstruos? ¿Por qué debería bloquear el juego? En su lugar, debes manejar los errores con gracia, así que haz algo como:
fuente
new
nunca vuelvenullptr
, tira.