Todos los desarrolladores utilizan algún estilo de colocación de los elementos del código fuente dentro del texto que los contiene. Esto se define como el estilo de codificación. Las normas de indentación indican la posición en la que se deben colocar los diferentes elementos que se incluyen en el código fuente, por lo que forman parte del estilo de codificación. Otro ejemplo de ello es la separación con espacios en blanco entre los diferentes elementos que componen las líneas de código.
Objetivo de la indentación
El objetivo fundamental de la indentación del código fuente es facilitar su lectura y comprensión. Hay dos tipos de posibles lectores del código fuente: programas y personas. A los programas les da igual la indentación, leen bien nuestro código siempre que cumpla la sintaxis del lenguaje. Luego la indentación debe centrarse en la lectura y comprensión del código por personas.
Para entender cómo hay que indentar un código primero hay que entender cómo lo lee una persona. Actualmente la mayor parte de las personas que leen código fuente lo hacen con editores de texto simples o con la ayuda de los editores de los entornos de desarrollo. Por tanto nos vamos a centrar en este tipo de lectores.
Cuando una persona lee un código fuente, lo hace siguiendo una serie de patrones de lectura. Si queremos facilitar la lectura del código lo primero que hay que entender son estos patrones. La mejor bibliografía sobre patrones de lectura son los libros que enseñan sistemas de lectura rápida; dos puntos fundamentales de estos sistemas son el estudio de los patrones de movimiento de la vista y el reconocimiento de la estructura del texto.
Los patrones de lectura nos indican el movimiento que siguen los ojos al leer un texto. Cuando leemos un texto, la vista se desliza a saltos, no se desplaza de una manera continua. Nuestra vista capta la información y que haya alrededor del punto en que se detiene la vista. Un buen lector hace pocas paradas para leer una línea, aprovechando más su campo visual.
Por otra parte, al leer también utilizamos la visión periférica, aprovechando la estructura y disposición que tienen las letras para extraer información adicional del texto. Así, por ejemplo, instintivamente nos fijamos en el principio del párrafo para buscar la información relevante, y nos ayudamos de elementos como las listas, los tabuladores, tablas y otros elementos tipográficos al leer.
De estos puntos deducimos que la posición absoluta y relativa de los elementos que componen el texto del código fuente juegan un papel importante a la hora de facilitar la lectura y comprensión del mismo.
Requerimientos para definir un estilo de indentación
Vamos a enumerar los principales requisitos para poder definir un buen estilo de indentación. Algunos de los más importantes serán:
Que el posicionamiento de los elementos dentro del texto sea predecible. Cuanto más predecible es la posición, el movimiento de los ojos llega antes a los puntos relevantes del código fuente. El punto más relevante de información es siempre el principio de la línea, por lo que hay que tener especial atención en él.
Que la relevancia de la agrupación de los elementos refleje la relevancia de éstos dentro del programa.
Priorizar la identificación del flujo del programa frente al detalle de los elementos que lo componen. Por ejemplo es más importante siempre tener una visión global de lo que hace una función que del detalle de cómo se declaran sus variables.
Que los comentarios respeten la indentación de los elementos a los que van asociados, posicionándose de manera relativa a ellos según su relevancia. Si el lenguaje lo permite, hay que distinguir la relevancia de un comentario posicionándolo sobre el elemento (más importante) o al lado de él (menos importante). Es mejor situar los comentarios antes del elemento, ya que nos sirven de introducción a lo que va a continuación, y muchas veces nos permitirá saltarnos un bloque de código que no nos interesa.
Utilizar la indentación basada en tabuladores. La indentación basada en el uso de caracteres de espacio en blanco es menos flexible que la basada en tabuladores, ya que los editores y entornos de desarrollo modernos permiten adapatar con facilidad el ancho de los tabuladores al gusto de cada programador.
Mantener el tamaño de las líneas dentro de los márgenes de la pantalla, siempre que sea posible. Debemos tener en cuenta al lector potencial del código fuente. No se debe pensar que el lector tiene una pantalla demasiado pequeña o grande, sino asumir que el lector tiene una pantalla típica dentro del entorno de desarrollo habitual. Por ejemplo actualmente los desarrolladores suelen tener pantallas capaces de mostrar 40 líneas y 120 columnas de caracteres con facilidad. En este caso, utilizar el antiguo margen de 80 columnas por línea y 25 líneas por pantalla es más bien escaso.
Utilizar el menor número de normas de indentación requerido. Indentar elementos en exceso complica visualmente la lectura del código, si no son estrictamente necesarios.
Un ejemplo de indentaciones habituales para C++ y Java
En primer lugar vamos a examinar diferentes estilos de indentación de una función C++ con algunas sentencias if,for y llamadas a otras funciones.
void foo(int entrada)
{
int i=0;
if(i===0)
{
int result = obtener_resultado(“clase”,
“tipo”,
“valor”);
for(int j=1;j<10;++j)
{
string s = cargar(“dato inicial”,
“dato final”,
Trae
CARGAR_DE_BD);
cout << “j vale” << j << endl;
}
} else
{
Cout << “no entró” << endl;
}
}
Este estilo está muy extendido entre los programadores, y es el obligatorio para muchos proyectos. Analicemos un poco su estructura. Para ello vamos a resaltar algunos elementos.
void foo(int entrada)
{
|int i=0;
|if(i===0)
|{
|int result = obtener_resultado(“clase”,
“tipo”,
“valor”);
for(int j=1;j<10;++j)
|{
|string s = cargar(“dato inicial”,
“dato final”,
Trae
CARGAR_DE_BD);
|cout << “j vale” << j << endl;
|}
|} else
|{
|cout << “no entró” << endl;
|}
}
He introducido símbolos ‘|’ para que se vean los diferentes niveles de indentación. Además he resaltado en amarillo el texto que corresponde a la lista de parámetros pasados las funciones. Veamos qué requisitos no cumple. En primer lugar, la vista debe dar muchos saltos innecesarios. La vista va a saltar al menos a los elementos remarcados. Además algunos de los saltos no siguen un patrón definido, ya que las distancias entre saltos varían para el mismo tipo de sentencia.
Mejoremos este ejemplo un poco. Lo primero es reorganizar las llamadas a función, ya que son menos importantes que la estructura del flujo de la función.
void foo(int entrada)
{
|int i=0;
|if(i===0)
|{
|int result = obtener_resultado(“clase”, “tipo”,
valor”);
for(int j=1;j<10;++j)
|{
|string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
|cout << “j vale” << j << endl;
|}
|} else
|{
|cout << “no entró” << endl;
|}
}
Los parámetros de la función no son ahora tan visibles. La vista ya no va directamente a ellos al intentar seguir el flujo, tenemos que detenernos en ellos a propósito.
Ahora modificamos las llaves de apertura y corregimos el tamaño de los indentados: un tabulador para un nivel interior y dos tabuladores para escribir la parte de una sentencia que no nos cabe en una línea.
void foo(int entrada)
{
|int i=0;
|if(i===0)
|{
|int result = obtener_resultado(“clase”, “tipo”,
valor”);
for(int j=1;j<10;++j) {
|string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
|cout << “j vale” << j << endl;
|}
|} else {
|cout << “no entró” << endl;
|}
}
Como vemos la vista sigue ahora un patrón predecible. Pero todavía lo podemos mejorar más. Vamos a colocar las llaves de cierre en una posición poco usual. Las vamos a poner a la misma altura que las sentencias que engloban. Veréis el resultado.
void foo(int entrada)
{
|int i=0;
|if(i===0)
|{
|int result = obtener_resultado(“clase”, “tipo”,
valor”);
for(int j=1;j<10;++j) {
|string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
|cout << “j vale” << j << endl;
|}
|}
|else {
|cout << “no entró” << endl;
|}
}
Como vemos, las llaves de cierre forman columna con la sentencias a las que pertenecen. Si añadimos algunas sentencias más lo apreciareis mejor:
void foo(int entrada)
{
|int i=0;
|if(i===0)
|{
|int result = obtener_resultado(“clase”, “tipo”,
valor”);
for(int j=1;j<10;++j) {
|string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
|cout << “j vale” << j << endl;
|}
|llamadaAotraFuncion(parametro1, parametro2);
|cout << “otra funcion llamada” << endl;
|}
|else
|cout << “no entró” << endl;
}
Además en el último else he quitado las llaves, que no son necesarias. A los puristas les gusta tener puestas las llaves, por si hay que añadir código. Los más perezosos (¿inteligentes?) las ponemos sólo si hacen falta. Entonces te dirán: ¿y si el programador pone una llave de apertura y no la cierra? ¿Y cómo sabes si te falta alguna llave? Aquí hay varias respuestas. Primero, si el programador se olvida de llaves lo va a hacer le digas lo que le digas… Además no es bueno ponerse la venda antes de tener la herida. En segundo lugar, todos los compiladores te indican si hay llaves de más o de menos. Si el asunto es una llave mal colocada es fácil buscarla. En primer lugar si ves una llave de apertura rápidamente puedes buscar la de cierre. En el ejemplo vemos que es muy fácil ver que el último cout lleva la llave de cierre del if al que pertenece.
Veamos el texto sin resaltados.
void foo(int entrada)
{
int i=0;
if (i===0)
{
int result = obtener_resultado(“clase”, “tipo”,
valor”);
for (int j=1;j<10;++j) {
string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
cout << “j vale” << j << endl;
}
llamadaAotraFuncion(parametro1, parametro2);
cout << “otra funcion llamada” << endl;
}
else
cout << “no entró” << endl;
}
Como veis el código cumple todos los requisitos que hemos enumerado al principio. Es muy legible y la vista rápidamente identifica la estructura y flujo de la aplicación. Las llaves están colocadas de manera que no entorpecen pero se ven suficientemente (no hace falta esconderlas más), y los parámetros de las funciones no están tan destacados.
Comparemos ambos estilos de codificación.
void foo(int entrada)
{
int i=0;
if(i===0)
{
int result = obtener_resultado(“clase”,
“tipo”,
“valor”);
for(int j=1;j<10;++j)
{
string s = cargar(“dato inicial”,
“dato final”,
Trae
CARGAR_DE_BD);
cout << “j vale” << j << endl;
}
} else
{
Cout << “no entró” << endl;
}
} void foo(int entrada)
{
int i=0;
if (i===0)
{
int result = obtener_resultado(“clase”, “tipo”,
valor”);
for (int j=1;j<10;++j) {
string s = cargar(“dato inicial”,
“dato final”, Trae, CARGAR_DE_BD);
cout << “j vale” << j << endl;
}
llamadaAotraFuncion(parametro1, parametro2);
cout << “otra funcion llamada” << endl;
}
else
cout << “no entró” << endl;
}
Y ahora llegan las votaciones. ¿Con cuál te identificas más? ¿Cuál te gusta más?
Fuente: https://www.adictosaltrabajo.com/tutoriales/indentacion/
No hay comentarios:
Publicar un comentario