sintaxis sintacticos semanticos semantico semanticas semantica que nuevas lexicos etiquetas estructura errores ejemplos definicion codigos codigo syntax coding-style code-review semantics
http://www.idesign.net/idesign/download/IDesign%20CSharp%20Coding%20Standard.zip

syntax - sintacticos - semantica html5 ejemplos



¿Cómo se ve mal el código? ¿Qué patrones usas para evitar errores semánticos? (21)

Evite los bucles anidados y evite la sangría del código más de un par de niveles.

Los bucles anidados o el código profundamente anidado generalmente se pueden refactorizar extrayendo el código anidado en una función / método. Esto generalmente hace que el código sea más fácil de razonar.

Desde que cometí el error de hacer una tarea por primera vez if siempre escribí mis ifs así:

if (CONST == variable) {

para evitar el error común (al menos para mí) de hacer esto:

if (variable = CONST) { //WRONG, assigning 0 to variable

Y desde que leí el ensayo de Joel Spolsky Making Wrong Code Look Wrong he intentado poner su consejo en práctica.

Entonces, ¿qué otros patrones usa para hacer que el código incorrecto se vea mal, o para forzar errores sintácticos si comete un error semántico?


La siguiente es una muy buena lectura de Juval Lowy sobre cómo diseñar tu código (C #). lo puede encontrar aquí: http://www.idesign.net/ en el lado derecho debajo de "Recursos"

o aquí hay un enlace directo (es un PDF comprimido): http://www.idesign.net/idesign/download/IDesign%20CSharp%20Coding%20Standard.zip

El estándar de codificación IDesign C #, para las pautas de desarrollo y las mejores prácticas de Juval Lowy

Tabla de contenido:

Prefacio
1. Convenciones y estilo de nombres
2. Prácticas de codificación
3. Configuración del proyecto y estructura del proyecto
4. Directrices específicas del marco
- 4.1 Acceso a los datos
- 4.2 ASP.NET y servicios web
- 4.3 Multithreading
- 4.4 Serialización
- 4.5 Remoting
- 4.6 Seguridad
- 4.7 System.Transactions
- 4.8 Servicios empresariales
5. Recursos


Me parece importante hacer que el código incorrecto se vea mal para el compilador . En la práctica (y solo cuando se usan lenguajes fuertemente tipados), esto significa omitir cualquier tipo de prefijos variables (incluso aplicaciones húngaras) a favor de distintos tipos. Para usar el ejemplo de Joel, si hay dos tipos distintos para representar las cadenas sin formato y las cadenas desinfectadas, y no hay una conversión implícita entre las dos, entonces el problema de que las direcciones de las aplicaciones húngaras ni siquiera puedan ocurrir.

Lo mismo ocurre con las coordenadas del documento de Word. En cierto modo, Apps Hungarian es solo una solución para compiladores / idiomas que no tienen la verificación de tipos lo suficientemente estricta.


No use nombres de variables que difieran solo en 1 o 2 caracteres. No use nombres de variables muy cortos. (Excepto por los bucles)

Use tan pocas variables globales como pueda. Es realmente un gran problema cuando tienes "int i" como global (sí, he visto algo como esto en un proyecto de la vida real :))

Usa siempre corchetes.


Otra medida de programación defensiva es usar siempre una declaración de switch en cada bloque de códigos de switch (es decir, no permita que una declaración de case "se desvíe" a la siguiente). La única excepción es si las declaraciones de casos múltiples deben manejarse de manera idéntica.

switch( myValue ) { case 0: // good... break; case 1: case 2: // good... break; case 3: // oops, no break... SomeCode(); case 4: MoreCode(); // WARNING! This is executed if myValue == 3 break; }

Hay momentos en que este puede ser el comportamiento deseado, pero desde el punto de vista de la lectura del código, yo argumentaría que sería mejor refactorizar ese código "compartido" para evitar esta ambigüedad.


Si el lenguaje de programación lo permite, solo declare las variables en el punto donde las inicializa. (En otras palabras, no los declare a todos en la parte superior de cada función). Si constantemente declara e inicializa en el mismo lugar, tiene muchas menos posibilidades de tener variables no inicializadas.


Si está jugando en HTML land, intente obtener código de validación, ha habido algunas veces que la pequeña x roja del complemento de validación de HTML me ha proporcionado un atajo útil para solucionar un problema que ni siquiera había notado todavía.

Puede que no siempre sea posible obtener HTML válido, pero por lo general vale la pena apuntar.


Siempre uso llaves en mi código.

Si bien puede ser aceptable escribir:

while(true) print("I''m in a loop")

Es más fácil de leer con las llaves en tacto.

while(true){ print("Obviously I''m in a loop") }

Creo que esto proviene principalmente de que Java es mi primer idioma.

golpe al golpe


Una práctica que uso (y una que no todos estarían de acuerdo) siempre está rodeando bloques de código (en C ++) con {y}. Entonces en vez de esto:

if( true ) DoSomething(); else DoSomethingElse();

Yo escribiría esto:

if( true ) { DoSomething(); } else { DoSomethingElse(); }

De esta forma, si yo (u otra persona) vuelvo a este código más tarde para agregar más código a una de las ramas, no tendré que preocuparme de olvidar rodear el código entre llaves. Nuestros ojos verán visualmente la sangría como pistas de lo que estamos tratando de hacer, pero la mayoría de los idiomas no lo harán.


heh, estaba a la mitad escribiendo esto y preguntándome si realmente fue tan útil, pero como Matt y Graeme publicaron respuestas sobre esto, continuaré.

Hace unos días, mientras agregaba un nuevo caso a un cambio, olvidé terminar el caso con un descanso. Una vez que encontré el error, cambié la sangría de mi declaración de cambio de:

switch(var) { case CONST1: statement; statement; statement; break; case CONST2: statement; statement; statement; case CONST3: statement; statement; break; default: statement; }

(que es cómo adivinan la mayoría de las personas que normalmente sangrarían) a esto:

switch(var) { case CONST1: statement; statement; statement; break; case CONST2: statement; statement; statement; case CONST3: statement; statement; break; default: statement; }

Para hacer que la ruptura faltante se destaque, y para que sea más probable que no olvide agregar una cuando agregue una nueva caja. (por supuesto no puedes hacer esto si estás rompiendo condicionalmente en más de un lugar, lo que he hecho en ocasiones)

Si solo estoy haciendo algo trivial, como establecer una variable o llamar funciones desde los enunciados de casos, a menudo los estructuraré así:

switch(var) { case CONST1: func1(); break; case CONST2: func2(); break; case CONST3: func3(); break; default: statement; }

Eso lo hace muy obvio si pierdes un descanso. Si sus declaraciones no tienen la misma longitud, agregue espacios en blanco hasta que se alineen los saltos, junto con cualquier otra cosa que tenga sentido:

switch(var) { case CONST1: func1("Wibble", 2); break; case CONST2: longnamedfunc2("foo" , 3); break; case CONST3: variable = 2; break; default: statement; }

Aunque si paso los mismos parámetros a cada función, usaría un puntero a la función (el siguiente es el código real de un proyecto de trabajo):

short (*fnExec) ( long nCmdId , long * pnEnt , short vmhDigitise , short vmhToolpath , int *pcLines , char ***prgszNCCode , map<string, double> *pmpstrd ) = NULL; switch(nNoun) { case NOUN_PROBE_FEED: fnExec = &ExecProbeFeed; break; case NOUN_PROBE_ARC: fnExec = &ExecProbeArc; break; case NOUN_PROBE_SURFACE: fnExec = &ExecProbeSurface; break; case NOUN_PROBE_WEB_POCKET: fnExec = &ExecProbeWebPocket; break; default: ASSERT(FALSE); } nRet = (*fnExec)(nCmdId, &nEnt, vmhDigitise, vmhToolpath, &cLines, &rgszNCCode, &mpstrd);


Las mejores cosas en mis libros es la reducción de ruido. Esta es la razón por la que me encanta la separación de preocupaciones, con excepciones que son un buen ejemplo de esto (asegurando que el manejo de casos de error no esté en línea).

Si el ruido se reduce, entonces el código que está buscando solo está allí para realizar el propósito particular que sugiere el método / nombre de función, esto hace que sea mucho más fácil detectar código incorrecto.


Una cosa que trato de usar, si es posible. es evitar el uso de tipos booleanos como parámetros para las funciones, especialmente si hay múltiples parámetros.

Que es más legible ...

compare("Some text", "Some other text", true);

...o...

compare("Some text", "Some other text", Compare.CASE_INSENSITIVE);

Ciertamente, esto puede ser un poco excesivo a veces, pero no es difícil de configurar, mejora la legibilidad y reduce las posibilidades de que el autor recuerde incorrectamente si ''verdadero'' significa ''Sí, haga una comparación de manera caseosa'' o '' Sí, haz una comparación de una manera que no distinga entre mayúsculas y minúsculas ''.

Por supuesto, casos como ...

setCaseInsenstive(true);

... es simple y lo suficientemente obvio como para dejarlo solo.


En mis aplicaciones de ingeniería, hago que las unidades de medida y los marcos de referencia formen parte de los nombres de las variables. De esa manera puedo detectar inconsistencias fácilmente. Ejemplos:

r1_m = r2_ft; //wrong, units are inconsistent (meters vs feet) V1_Fc = V2_Fn; //wrong, reference frames are inconsistent //(Fc=Local Cartesian frame, Fn=North East Down frame)


Usa un poco de húngaro

Puede ser útil etiquetar variables. Por ejemplo, si desinfecta las entradas del usuario, puede hacer algo como esto:

$username = santize($rawusername);

De esta forma, si va a decir echo $rawusername , se verá mal, porque así es.


He jugado con el truco (0 == variable), pero hay una pérdida en la legibilidad: tienes que cambiar las cosas mentalmente para leerlo como "si la variable es igual a cero".

En segundo lugar, la recomendación de Matt Dillard de poner llaves en condicionales de línea única. (¡Lo votaría si pudiera!)

Otro truco que uso cuando el rendimiento no es crítico: definiré

void MyClass::DoNothing() { }

y usarlo en lugar de declaraciones nulas. Un punto y coma desnudo es fácil de perder. Uno puede agregar los números del 1 al 10 (y almacenarlo en suma) de esta manera:

for (i = 1; i <= 10; sum += i++) ; //empty loop body

pero esta es una OMI más legible y auto-documentada:

for (i = 1; i <= 10; sum += i++) { DoNothing(); }


Siempre declare que las variables son "const" (o el equivalente en su lenguaje de programación) si no hay ninguna razón para que el valor cambie después de la inicialización.

Si lo conviertes en un hábito, eventualmente comenzarás a cuestionar cada vez que veas una variable no const.


@Zack:

Entonces, ¿está diciendo que en lugar de usar una convención de nomenclatura de prefijo para crear y usar siempre dos nuevas clases: SafeString y UnsafeString?

Parece una opción mucho mejor para mí. Los errores de compilación son mucho mejores que los errores de tiempo de ejecución.

Exactamente. Bruce Eckel escribió un ensayo argumentando que la escritura estática es superflua porque, de todos modos, estás escribiendo casos de prueba, ¿verdad? Incorrecto. Por supuesto que estoy escribiendo casos de prueba, pero escribir buenos casos de prueba es difícil y mucho trabajo. Es bueno tomar toda la ayuda que pueda obtener y la verificación del tipo de tiempo de compilación es, en gran medida, la mejor ayuda que puede obtener. Además, cuando se utilizan pruebas, incluso cuando se usa un proceso automático de prueba en el registro, la prueba fallida se señalará mucho más tarde que un error en tiempo de compilación, lo que ocasionará una corrección de errores retrasada. Los compiladores pueden dar una retroalimentación más directa.

Eso no quiere decir que no veo las ventajas de los lenguajes interpretados, pero la tipificación dinámica puede ser una gran desventaja. De hecho, me decepciona que no exista un lenguaje moderno interpretado con tipeo estático, porque como muestra Joel, esto hace que escribir el código correcto sea mucho más difícil y nos obliga a recurrir a hacks de segunda clase como Apps Hungarian.


En la misma línea que su ejemplo original es este truco de comparación literal de cadena. Si compara una variable de referencia de cadena con una cadena literal, tiene la posibilidad de arrojar una NullPointerException .

if(variable.equals("literal")) { // NullPointerExceptionpossible ... }

Puedes evitar esa posibilidad si cambias las cosas y colocas el literal primero.

if("literal".equals(variable)) { // avoids NullPointerException ... }


Al definir arreglos u objetos en JS (y similiares en otros idiomas) pongo el , delante del valor. Esto vino de muchas veces modificando una matriz / objeto y obteniendo un error de sintaxis por falta , - fácil de olvidar si las líneas son largas.

oPerson = { nAge: 18 ,sFirstName: "Daniel" ,sAddress: "..." ,... }

Similairy para la contacinación de cuerdas sobre líneas largas Puse el + en la parte delantera en vez del extremo "

sLongString = "..........................................................." + ".........................................................." + ".............." + "";


Konrad Rudolph escribió:

Apps Hungarian es solo una solución alternativa para compiladores / idiomas que no tienen la verificación de tipos lo suficientemente estricta.

Entonces, ¿está diciendo que en lugar de usar una convención de nomenclatura de prefijo para crear y usar siempre dos nuevas clases: SafeString y UnsafeString?

Parece una opción mucho mejor para mí. Los errores de compilación son mucho mejores que los errores de tiempo de ejecución.


@ Matt Dillard :

Otra medida de programación defensiva es usar siempre una declaración de interrupción en cada bloque de códigos de conmutación (es decir, no permita que una declaración de caso "se desvíe" a la siguiente). La única excepción es si las declaraciones de casos múltiples deben manejarse de manera idéntica.

A veces, manejar el caso X y el caso Y significa hacer casi lo mismo, en cuyo caso pasar al siguiente caso hace que el código sea más fácil de leer. Sin embargo, es una buena idea indicarlo específicamente con un comentario:

switch( type ) { case TypeA: do some stuff specific to type A // FALL THROUGH case TypeB: do some stuff that applies to both A and B break case TypeC: ... }

Si usa esta convención, todas las declaraciones de casos deben tener un descanso, una devolución, un continuar o un comentario que indique que se está cayendo. Sin embargo, un caso vacío sin el comentario está bien:

case TypeA: case TypeB: // code for both types