2008-11-06 10 views
15

Desde que escribí por primera vezprácticas de programación defensivas

if ($a = 5) { 
    # do something with $a, e.g. 
    print "$a"; 
} 

y pasó por la sesión desconcertante normal de

  • qué es el resultado siempre es cierto
  • qué es de $ a Siempre 5

hasta que me di cuenta, había asignado 5 a $ a, en lugar de realizar una comparación.

Así que me decidí a escribir ese tipo de condición anterior como

if (5 == $a) 

en otras palabras:

Coloque siempre el valor constante en el lado izquierdo del operador de comparación, lo que resulta en un error de compilación , si olvida agregar el segundo signo "=".

que tienden a llamar a este defensiva de codificación y tienden a creer que es un primo a de programación defensiva, no en la escala algorítmica, pero la palabra clave por palabra clave.

¿Qué prácticas defensivas de codificación ha desarrollado?


una semana más tarde:

Un gran "gracias" a todos los que respondieron o podría añadir otra respuesta en el futuro.

Desafortunadamente (¡o afortunadamente!) No hay una sola respuesta correcta. Para eso mi pregunta fue amplia, pidiendo más opiniones o aprendiendo de la experiencia, en lugar de hechos.

+0

Pensé que, si recuerdo haberlo hecho, puedo recordar el == (tristemente) – gbarry

+7

No me gusta la sacudida de la línea de pensamiento normal; No estoy probando 5, estoy probando $ a. Me resulta más fácil si la cantidad que se prueba está en primer lugar. Tal vez soy una minoría, pero no me gusta la técnica, aunque la recomiendan personas a las que respeto. –

+1

Sería mejor si no puede asignar nada a las variables en caso de comparación. Se creó Java y C# porque C++ estaba lleno de trampas como esa. Entonces, ¿por qué este problema de asignación todavía existe? – Silvercode

Respuesta

13

Esto es simple y obvio, NUNCA JAMÁS repito la misma cadena constante dos veces en mi código, porque SÉ que si lo hago escribiré una de ellas incorrectamente :) ¡Use constantes, gente!

4

he dejado de utilizar los idiomas en los que puede hacer

if a = 5: print a 

Esto me ha ahorrado un montón de dolores de cabeza =).

En una nota más seria ... Ahora siempre escribo las llaves después de escribir mis bucles if sy for, y luego los rellene después. Esto asegura que mis corchetes estén siempre alineados.

+0

Estoy de acuerdo ... pero en este mundo no tan perfecto, la elección del lenguaje de programación no es mía ... – lexu

8

Siempre coloque las llaves después de un if/for/while ... incluso si solo hay una sola declaración después. BTW D. Crockford piensa que es mejor también: Required blocks

+0

Perl ha ordenado llaves después de if (y elsif) y por eones. –

+0

Sí, pero Perl también tiene un operador unario, ¿no? No intentes convencerme de que Perl es un faro de legibilidad brillante :-) – endian

+0

Acabo de publicar una respuesta a otra pregunta señalando que el problema de "abrazar o no abrazar" está estrechamente relacionado con las prácticas correctas de sangrado. – staticsan

3

Devolviendo una copia de un objeto mutable, es decir, una copia de una matriz, no el objeto mutable en sí.

+0

Estoy de acuerdo, en mundos donde la velocidad y la memoria no son problemas. – billjamesdev

+0

... y esto no es una práctica * de codificación * defensiva ... – Rich

+0

¿Alguna vez tuvieron problemas con una referencia de fugas? – dhiller

16

Utilizar siempre los apoyos:

if(boolean) 
    oneliner(); 
nextLineOfCode(); 

no es lo mismo que:

if(boolean) 
{ 
    oneliner(); 
} 
nextLineOfCode(); 

Si oneliner() es una función #defined, y no se define entonces su siguiente línea de código repentinamente se vuelve sujeto al if(). Lo mismo se aplica a los bucles etc. Con los apoyos a continuación, la siguiente pieza de código nunca se convierte involuntariamente condicionada a la si/etc para

+1

Si se supone que oneliner() está # definido pero no lo es, entonces tiene una llamada a una función no declarada (un error en C++, permitido en C). Si el delineador() está # definido con un cuerpo vacío, entonces tienes un punto y coma que da un enunciado vacío después del if. En ambos casos, los constructos son iguales. –

+1

¡Oh Dios, SÍ! ¡Siempre use llaves! – endian

14

los 3 mejores prácticas de codificación defensivas que empleo son

  1. pruebas unitarias
  2. unidad de prueba
  3. pruebas unitarias

no hay mejor defensa por la calidad de su código que una buena prueba de la unidad para hacer copias de seguridad.

+1

Pero una prueba de unidad es algo que ocurre después de la codificación, no durante la codificación. Es una buena cosa, pero no una práctica de codificación. – Treb

+0

En mi opinión, las pruebas unitarias son una práctica de programación defensiva (¡una importante, no te vayas!), Pero no un ejemplo de codificación defensiva ... un error de codificación "opps-ative" en tu prueba no se detecta ... depende de las definiciones (realmente mías) de "codificación" y "programación" – lexu

+4

en muchos casos se escribe una prueba unitaria antes de la implementación. Sí, es una práctica de codificación. –

2

Evitar prueba innecesaria. Ejemplo

  1. si (bool == true)
  2. comprueba si Pointer (puntero)

EDIT:! Si (puntero) no se puede leer lo que hoy en día prefiero si (= NULL puntero)

+0

Estoy completamente de acuerdo con el punto 1, pero para el punto 2, prefiero que (puntero! = NULO) porque hace que el código sea más fácil de leer. – RobH

2

par de cosas:

  • Sí, los bloques de 1 línea. Usa los frenos ... diablos, la mayoría de los buenos IDE te harán em.
  • Comenta tu código después de escribirlo, o vuelve a leer tus comentarios si lo hiciste antes de tiempo. Asegúrate de que tu código todavía haga lo que dicen los comentarios.
  • Las pruebas unitarias son una excelente alternativa para volver a leer su código.
  • Siempre ingrese una excepción ... o, NUNCA capture una excepción sin decirlo, al menos en la depuración.
5
  • Siempre inicializar variables
  • Use const en lo que pueda (sin utilizar mutable)
  • Evitar la asignación dinámica desnuda de memoria u otros recursos
  • Siempre utilizar llaves
  • Código casos de uso y pruebas para cualquier clase antes de la implementación de la codificación
  • Active tantas advertencias útiles como pueda (-Wall -Wextra -ansi -pedantic -Werror como mínimo)
  • Utilice la herramienta más simple que resuelve el problema (en mi entorno actual, bash ->grep -> awk -> Python -> C++).
+1

+1 para inicializar siempre variables y llaves. –

5

Personalmente, me desagrada este estilo defensivo, hace que el código sea difícil de leer.

El nivel de advertencia del compilador de VC 4 detectará este (posible) error.
"advertencia C4706: asignación dentro de la expresión condicional"

Puede activar sólo esta advertencia del compilador específico, en cualquier nivel:

#pragma warning(3,4706) 
+0

GCC le avisará de manera predeterminada cuando haga esto; te aconseja poner una tarea dentro de parens anidados para aclarar tu intención. – Rich

+0

El compilador de C# también se quejará de esto: no puede convertir implícitamente el tipo 'xyz' a 'bool'. –

7

Al comparar una cadena con una constante, escribir

if ("blah".equals(value)){} 

en lugar de

if (value.equals("blah")){} 

para evitar una NullPointerException. Pero esta es la única vez que uso el estilo de codificación sugerido (porque "if (a = 1) ..." no es posible en Java).

+0

Mmm, lindo, me gusta. – endian

+0

Solo tenga cuidado si su lenguaje de programación ** hace una comparación entre cadenas de casos ** usando los operadores de igualdad (o el método igual). –

+0

No me gusta, ya que no captura valores nulos, lo que puede o no ser un error. – Cojones

7

Una de las cosas que siempre trato de recordar cuando estoy en el mundo Javascript es comenzar siempre el valor de retorno de una función en la misma línea que la palabra clave de retorno.

function one(){ 
    return { 
     result:"result" 
    }; 
} 

function two(){ 
    return 
    { 
     result:"result" 
    }; 
} 

Estas 2 funciones no devolverán el mismo valor. La primera función devolverá un Objeto con un conjunto de resultados de propiedades a "resultado". La segunda función devolverá undefined. Es un error muy simple y ocurre debido a la estrategia de inserción de Semi-Colon de JavaScript demasiado celosa. Los semi-puntos son semi-opcionales en Javascript y debido a esto, el motor de Javascript agregará semi-coons donde cree que debería estar. Como return es en realidad una declaración válida, se insertará un punto y coma después de la declaración de devolución y el resto de la función se ignorará esencialmente.

+4

Una razón más por la que Javascript es Evil. – endian

+2

Estoy muy en desacuerdo. Creo que se apresuró al mercado y no tenía tiempo en un laboratorio para el refinamiento. El populatiry explotó lo que significaba que no se podía arreglar sin romper cosas. Usado correctamente es un lenguaje genialmente adaptable y poderoso. Despotricar sobre. –

+0

¡Guau! ¡Nunca lo supe! Gracias por la info. Eso califica una pregunta/respuesta por sí mismo. –

5

Desde mi blog:

  1. Piensa en positivo y volver temprano, más profunda que no se peguen. En lugar de

    si (valor! = Null) { ... hacer algo con valor ...} retorno

    escritura

    si (valor == null) {} retorno ... hacer algo con valor ...

  2. Evite "constantes de cadena" (es decir, el mismo texto entre comillas en más de un lugar). Defina siempre una constante real (con un nombre y un comentario opcional lo que significa) y úselo.

1

Instalado ReSharper;) entonces no hay necesidad de escribir "5 == un" para obtener cuidado si hice algo mal :)

+0

¿Eso funciona con perl/python/bash ... autodisciplina ... y sí, eso es un argumento cojo en cierto modo .- ( – lexu

+0

@lexu: no, pero es una pregunta subjetiva, y no uso perl, python o bash :) – badbadboy

Cuestiones relacionadas