No creo que haya que hacer especial énfasis en la importancia de tener unas reglas de formateo claras que dejen el código claro y fácil de leer. Es una de esas cosas que estoy tan acostumbrado y doy tan por sentado, que cuando no se cumplen, chirría.

Nota personal: Les deberían cortar el meñique derecho a los que abren llaves en una línea nueva 🙂

El propósito del formateo

El formateo del código trata de la comunicación, y la comunicación es lo primordial para un buen programador, antes incluso que el código funcione.

El estilo de codificación y la legibilidad establecen precedentes que continúan afectando a la capacidad de mantenimiento y la extensibilidad mucho después de que el código original haya cambiado totalmente. Tu estilo y disciplina sobreviven, aunque tu código no.

Formateo vertical

¿Como de grande debe ser un archivo? El autor hace una comparación del número de lineas de los archivos de varias librerías famosas en java (tomcat, junit, ant,…). El grueso del código está escrito en archivos de menos de 200 líneas. Si ellos han podido ¿por que tu no? Obviamente no es una regla rigida, pero deberíamos ser capaces de crear archivos de no más de esas líneas. Solo con lo difícil que es encontrar algo en un archivo enorme, nos ahorraríamos mucho tiempo y esfuerzo.

La metáfora del periódico

Piensa en un artículo de un periódico (o blog, en los tiempos que corren) bien escrito. En la parte superior esperas una cabecera que cuenta de que va el artículo y te permite decidir si quieres leerlo o no. Los primero párrafos te dan una sinopsis de la historia, ocultando los detalles mientras te da los conceptos generales. Según continuas bajando se incrementan los detalles hasta que tienes todos los datos.

Así es como debería ser un fichero fuente. El nombre debe ser simple pero explicativo, lo suficiente para decirnos si estamos en el módulo adecuado o no. Las primeras líneas muestran los conceptos y algoritmos de alto nivel. Y el detalle se incrementa según bajamos.

Recuerda el último archivo que creaste entero ¿sigue este orden?

Separación vertical entre conceptos

Casi todo el código se lee de izquierda a derecha y de arriba a abajo. Cada línea representa una expresión, y cada grupo de líneas representa un concepto completo. Esos conceptos deben separarse unos de otros con líneas en blanco.

Ésta regla tan simple tiene un profundo efecto en la visualización del código. Cada línea en blanco es un señal visual que identifica un nuevo y separado concepto. Veamos un ejemplo comparativo:

Creo que no hace falta comentar las diferentes sensaciones al ver ambos códigos.

Densidad vertical

Si los conceptos se agrupan verticalmente, la densidad vertical implica una asociación cerrada. Comprueba como los comentarios rompen la asociación de las 2 variables:

En cambio al eliminarlos podemos ver el conjunto en un único golpe de vista, lo que aumenta la sensación de que están relacionados.

Distancia vertical

¿Cuantas veces has tenido que seguir la cadena de llamadas a funciones buscando la definición de la siguiente función en un archivo enorme y desordenado? Gastas más tiempo y energía buscando que entendiendo que hace el sistema.

Los conceptos relacionados no deberían estar lejos unos de otros en el mismo archivo. Y por supuesto, no deben estar en archivos diferentes (el autor comenta que este es uno de los motivos por los que las variables protegidas no tienen sentido). Cuanto más relacionados están, más cerca tienen que colocarse.

Declaración de variables: Deben declararse todas juntas en un mismo bloque al inicio de la función, excepto las variables de control de un bucle deberían declararse dentro de este.
Según el autor, en ocasiones se pueden declarar al principio de un bloque de código o antes de un bucle, pero para mi esa es una señal de que la función debería descomponerse en otras más pequeñas.

Variables de instancia: Deben declararse al principio de la clase. Si hay muchas variables, algunas se usan solo en unos métodos, o hay tantos métodos que la separación vertical es muy grande: reduce el tamaño de la clase.

Funciones dependientes: Si una función invoca a otra, deberían estar cerca y la invocada por debajo (aunque en algunos lenguajes esto no es posible). Esto hace que el flujo del programa sea natural y por tanto fácil de leer.

Afinidad: Ademas de por uso e invocación, hay otros motivos por los que el código tiene afinidad y por tanto debe estar cerca. Por ejemplo si su funcionalidad es similar:

Orden vertical

Al igual que en un artículo, esperamos que los conceptos importantes estén primero y según bajamos,se encuentren los detalles de bajo nivel. Esto nos permite conocer la funcionalidad principal de un archivo echando un vistazo a las primeras líneas.

Formateo horizontal

¿Como de larga debería ser una línea? El motivo por el que tradicionalmente se admite un máximo de 80 caracteres por linea es debido a que era la anchura de las tarjetas perforadas, quizá no tiene mucho sentido hoy en día. Aún así a mayor longitud más difícil es para el ojo captar toda la información. Hay quien usa 100 o 120, pero pon un límite bajo, nada de 200.
Personalmente sigo manteniendo los 80 caracteres, aunque uso un monitor grande, siempre tengo varias ventanas abiertas.

Separación horizontal y densidad

Utilizamos espacios en blanco horizontales para asociar cosas que están fuertemente relacionadas y disociar cosas que están más débilmente relacionadas.
Rodeando los operadores de asignación con espacios en blanco los acentuamos. Las declaraciones de asignación tienen dos elementos distintos y principales (izquierdo y derecho). Los espacios hacen que esa separación sea obvia.

Por otro lado, no puse espacios entre los nombres de las funciones y el paréntesis de apertura. Esto se debe a que la función y sus argumentos están estrechamente relacionados. Separarlos los hace parecer desunidos en lugar de unidos. Separo los argumentos dentro de la función llamada paréntesis para acentuar la coma y mostrar que los argumentos están separados. Otro uso del espacio en blanco es acentuar la precedencia de los operadores.

Los factores no tienen espacios en blanco entre ellos porque son de alta prioridad. Los términos están separados por espacios en blanco porque la suma y la resta son de menor prioridad.

Alineamiento horizontal

Usar un tipo de alineamiento para acentuar las estructuras hace que veamos la información agrupada:

Aunque inicialmente puede parecer que así queda más claro, la realidad es que leemos en vertical una columna y obviamos las demás, por lo que perdemos información. Leemos los nombres de las variables pero no el tipo, o los valores que asignamos a las variables, pero no el operador de asignación. Ademas, variar la longitud de los elementos repercute en tener que modificar las líneas a mano, ya que no se puede hacer automáticamente.
Mejor utilizar declaraciones sin alinear:

Indentado

Creo que no hay nada que explicar en este punto. Todos sabemos lo importante que es indentar.

Romper la indentación: En ocasiones tendemos a escribir un if muy corto en una sola línea, por ejemplo. ¿Qué se gana realmente con esto? ¿Reducir el tamaño del método? Saca lógica fuera y así no afectará a la legibilidad.

Ámbitos ficticios

En ocasiones el cuerpo de un bucle está vacío, lo que provoca confusión. El autor recomienda evitarlo y cuando no se puede hacer, incluir aún así las llaves, indentarlo correctamente y pasar el ; a la línea siguiente.

No recuerdo haberme encontrado un caso así, la verdad, por lo que no puedo dar mi opinión.

Reglas de equipo

Un equipo tiene que acordar que reglas de formateo se van a seguir. Si cada uno sigue las suyas va a ser fuente de problemas: añadiendo una carga cognitiva innecesaria al trabajar con el código de otro, o perdiendo tiempo en modificar el formateo.

 

Personalmente utilizo un formato automático, aunque no sea tan bueno como el descrito aquí, prefiero que lo haga todo solo. Y si puedo lo configuro para que se parezca lo máximo posible a este.

Espero que os haya sido útil y sirva para replantearse ciertas prácticas que tenemos interiorizadas sin pararnos a pensar en si realmente cumplen la función para la que las usamos, o si compensan.

Categorías: librosteoría

0 commentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *