Estándares de escritura de código
¿Alguna vez habéis programado en equipo? ¿Habéis tenido que entender el código de otra persona porque en vuestro trabajo continuáis con un proyecto que otro compañero vuestro comenzó a desarrollar? Si es así, conoceréis lo poco cómodo que es leer código del que no tienes ni idea, que para colmo no está escrito como a ti te gusta. Es evidente que no puedes entender un script simplemente con mirarlo un par de segundos, y que no tiene sentido esperar que todos escribamos el código de la misma forma (no sería la primera vez que discuto con alguien sobre si debes abrir las llaves en la línea de declaración de función o en nueva línea), pero aún así, guiarnos por unas mismas directrices agilizaría bastante el desarrollo conjunto.
Hoy mismo, en mi trabajo, he tenido que hacerme cargo de un proyecto bastante extenso con mucho código y por el que antes que yo han pasado otras 4 personas (y ni una sola está contenta con el aspecto del código). He tenido ganas de quemar el ordenador cuando me he encontrado con cientos de líneas de código, cada una de su programador, y en las cuales apenas había comentarios explicando el código. Algunos os hacéis a la idea. El resto, espero que jamás tengáis que ver nada semejante.
Así que realmente este artículo trata de dar unas directrices básicas sobre cómo escribir nuestro código (independientemente del lenguaje de programación, aunque siempre orientado a objetos). "Yo suelo trabajar solo", es una excusa que puede ponerse cuando nos negamos a hacer nuestro código más legible. Para los lobos solitarios: si alguna vez tenéis que releer vuestro propio código tras meses sin haberlo tocado, agradeceréis haberlo escrito bien. No me refiero únicamente a la documentación. Imaginad lo siguiente: tenemos un script muy extenso, con funciones extensas, que desconocemos por completo. Generalmente, para analizar cómo funciona, lo suyo suele ser cogerlo por partes. Pero si un mismo scope es muy extenso, es fácil olvidar qué funciones pertenecen a qué ámbito. Por ejemplo:
bool exito = false; int numero = 5; for(int i=0; i<miArray.length; i++) { numero+=miObjeto.hazAlgo(miOtroObjeto); } exito=numero+margen<8; return exito;
Aunque es algo difícil imaginarse el contexto, supongamos que este extracto pertenece a una función de nuestro código. Sin poder abarcar completamente la totalidad del código de un golpe de vista, es algo complicado saber a qué hacen referencia miArray, miObjeto, miOtroObjeto y margen. Podríamos haberlos declarado de forma local en esta función con anterioridad, podrían ser argumentos de la propia función, o podrían ser campos de nuestra clase. Es más, si hiciéramos el código lo suficientemente extenso, podríamos incluso olvidar si numero y exito son locales a nuestra función. Si quisiéramos entender el código, necesitaríamos saber qué estamos modificando en cada paso del código para entender las repercusiones en el programa.
El estilo de programación que voy a enfocar no es otra cosa que aprovechar los nombres de variables y funciones para hacerlas informativas con un simple golpe de vista. La solución pasa por saber distinguir el ámbito (o scope) de una variable simplemente por su nombre. Es cierto que la mayoría (o todos) los entornos de desarrollo actuales ofrecen información sobre una variable simplemente con pasar el ratón por encima, pero puede resultar muy tedioso y lento revisar constantemente las variables o utilizar el Outliner del IDE (Entorno de Desarrollo Integrado) para ver sus características.
Por ejemplo, llamaríamos a todos los campos públicos de nuestra clase con nombres que empiezan por mayúscula, y a los privados o protegidos con minúscula. Igual con las funciones. Las variables locales a una función, al ser temporales, comenzarían su nombre con t_ , y los argumentos de dichas funciones con a_ . Puede parecer que utilizar el carácter '_' quita tiempo, pero en la práctica compensa (hablo desde la experiencia). Retomemos el ejemplo anterior, aplicando estas directrices:
bool r_exito = false; int t_numero = 5; for(int b_i=0; b_i<MiArray.length; b_i++) { t_numero+=miObjeto.HazAlgo(a_miOtroObjeto); } r_exito=t_numero+a_margen<8; return r_exito;
Leyendo rápidamente el código, y conociendo las directrices explicadas anteriormente, es trivial que t_numero es una variable local, y que (aunque no está explicado en el párrafo anterior), r_exito es una variable local cuyo principal propósito es ser devuelta por la función por medio de un return. MiArray es un campo público de la clase. miObjeto es privado o protegido y b_i es una variable interna en una estructura de bucle (aunque en la práctica yo optaría por un nombre algo más descriptivo que b_i en función de la utilidad del bucle, pero eso ya es objeto de otros tutoriales). a_miOtroObjeto y a_margen son parámetros de la función en la que estamos trabajando.
Con un análisis rápido ya sabemos el ámbito de uso de cada una de nuestras variables (funciona de forma similar para funciones, aunque su utilidad es menos acusada (no obstante, recomendada), lo cual facilita mucho el comprender el funcionamiento del código si no recordamos cómo funciona o no lo hemos programado nosotros.
La idea es que estas directrices sean compartidas por las comunidades de programadores, de modo que ya sea entre programadores de un mismo proyecto/grupo o para desarrolladores de librerías abiertas para otros desarrolladores, todos escribamos un código "similar" y facilitemos la comprensión de nuestro código a los que tengan el valor de investigarlo. Estos estándares de escritura de código podrían firmar proyectos de software libre, ayudando a que elijáis trabajar con proyectos aparentemente similares únicamente porque tendréis más facilidad para comprender su funcionamiento.
Las directrices que he presentado en este tutorial no son ni mucho menos perfectas, pero las he desarrollado yo mismo a base de usarlas para facilitarme (al principio a mí mismo, pero luego también a mi equipo) el desarrollo y mantenimiento del código. Al ser yo mismo el fundador de este estándar, me he tomado la libertad de bautizarlo como "DCN" (utilizo el alias Dechcaudron como identificativo en la red), y quiero mantenerlo abierto a sugerencias y contribuciones por parte de la comunidad. Os invito a probarlo (cuesta acostumbrarse un poco al principio, pero deja de parecer raro bastante pronto) y a sugerir cambios y mejoras. Si no os gusta, siempre podéis crear un estándar vosotros mismos. Mantendré la fuente en este link.
/* Originally developed by Dechcaudron [Héctor Barreras Almarcha] First version published on 9/2/2015 Current version: v0.8 */ public Object PublicFoo; protected Object protectedFoo; private Object privateFoo; //Doesn't need a definition for Showcase purposes public Object PublicMethod(); protected Object protectedMethod(Object a_argumentFoo1, Object a_argumentFoo2) { Object r_returnFoo; Object t_localFoo1; Object t_localFoo2; for(int b_index=0; b_index<1000;b_index++) { //stuff(); } foreach(Object b_foo in fooArray) { //stuff(); } return r_foo; }
Gracias por leer este artículo. Espero que con herramientas como esta podamos organizarnos para mejorar nuestro código.
Sueño con leer un script que no es mío y comprenderlo sin dificultad