Introducción
Actualmente me encuentro haciendo auditoría de arquitectura y código Javascript dentro del TelefónicaLabs (antiguo I+D) de la mano de Aurigae. Y, como casi en todo proyecto ya iniciado, una de las principales debilidades con las que me encuentro es la falta de una guía de estilo concisa con la que todos los desarrolladores estén comprometidos.
Este punto, lejos de parecer una simple cuestión estética, tiene una importancia capital a la hora de gestionar el código por parte de terceros. El estilo es lo primero que salta a la vista cuando abrimos un fichero y determina en gran parte su contenido: una indentación correcta que delimite bloques funcionales, nombres de variables y funciones consistentes que nos den la pauta de su contenido y, si estuviésemos en un mundo ideal, comentarios a lo largo del código de modo uniforme y coherente que complementen la información del resto.
Es por eso que una de las primeras tareas a abordar en todo proyecto serio es la definición de un documento de estilo para el código con el que se está trabajando. Esto permite unificar los criterios personales de cada desarrollador permitiendo a los demás reconocer fácilmente procesos y estructuras tanto dentro de su trabajo como en el de otros…
Para alcanzar esta unidad semántica, existen multitud de guías de estilo disponibles presentadas, o bien por grandes compañías como Google, o bien por proyectos cuya envergadura les permiten tener una cierta posición dominante en el ámbito general de cada lenguaje. En Javascript, son varias las guías que podemos encontrar en Internet:
- Guía de estilo Javascript de Google
- Guía de estilo para jQuery
- Convenciones de estilo para el lenguaje Javascript, por Douglas Crockford
- Etc…
Sin embargo, una debilidad del lenguaje a día de hoy es que no existe un estándar reconocido como tal por la comunidad. Cada desarrollador puede acogerse a alguna de las directrices indicadas arriba o bien crearse su propia guía de estilo a partir de sus conocimientos en otros lenguajes donde si pueden existir esos estándares mejor establecidos.
NOTA: Hay ocasiones, como en PHP, que sin existir un estándar ‘oficial’, si hay organizaciones que tratan de establecer uno de facto. Es el caso, por ejemplo de los PSR-0, PSR-1 y PSR2 para todo el anillo del PHP-FIG.
Finalmente, hay ocasiones en las que una personalidad es tan influyente, que muchos desarrolladores utilizan sus reglas de estilo sin importar que éstas fueron creadas para otros lenguajes. Se tratan así como soluciones universales que a veces no terminan de casar bien con determinados lenguajes y que se complementan con otros estilos. Es el caso por ejemplo de las Reglas de Estilo GNU (GNU Coding Standards) de Richard Stallman inicialmente planteadas para los lenguajes C/C++. Podemos revisar estas normas en su correspondiente manual editado en OpenLibra: GNU Coding Standards.
NOTA: Sobre este último aspecto, el hecho de adoptar esta reglas para el lenguaje Javascript no son del todo desacertadas: nunca hay que olvidar que Javascript es un lenguaje que pertenece a la familia de C y que, por tanto, conserva muchas similitudes con éste.
Y, ¿cuál es mi opción personal a la hora de establecer una guía de estilo? Pues, como he comentado anteriormente, a falta de un estándar reconocido por la comunidad, suelo utilizar una adaptación de las líneas PSR de PHP a las que añado algunas de las recomendaciones de la guía Google. El resultado son una serie de reglas fácilmente identificables que dan cierta claridad a los códigos.
La referencia que muestro a continuación es la que aplicamos únicamente a la nomenclatura dentro de un archivo o, lo que es lo mismo, a la forma en que deberíamos llamar a objetos, variables, funciones, etc… Se recogen además, otros elementos estéticos como los separadores que ayudan a dotar de una mayor legibilidad al conjunto. Estas mismas reglas se aplicarán a la codificación de la v2 de OpenLibra.
La dejo aquí expuesta por si puede resultarle a alguien de ayuda o inspiración:
NOTA: Esta guía es un ejercicio completamente personal y puede (de hecho hay) puntos claramente discutibles. Para cualquier aclaración sobre el porqué de una determinada elección, o para proponer formas alternativas, utilizad los comentarios. Gracias!
Guía de estilo. Nomenclatura en archivos Javascript
1. General
- Los ficheros tienen que ser nombrados en minúsculas utilizando la forma ‘underscore‘.
- El objeto global se declara según la forma ‘UPPER_CASE’ con guión bajo como separador y precedido del signo de dolar ($).
- Los subojetos principales que categorizan las funcionalidades, se declaran según la forma ‘UPPER_CASE’ con guión bajo como separador.
- Las variables tienen que ser nombradas utilizando la forma ‘camelCase‘.
- Los constructores tienen que ser nombrados utilizando la forma ‘StudlyCaps‘.
- Las constantes, de haberlas, tienen que ser nombradas en ‘UPPER_CASE’ con guión bajo como separador.
- Las propiedades tienen que ser nombradas utilizando ‘camelCase‘.
- Los métodos tienen que ser nombrados utilizando ‘camelCase‘.
2. Nombres de Fichero
Los ficheros se nombrarán siempre en minúsculas para evitar errores con aquellas plataformas ‘sensitive-case’. Los ficheros tienen que concluir con la extensión .js, y no deben incluir signos de puntuación excepto – (guión medio) o _ (guión bajo), siendo preferible este último a la hora de separar palabras.
Ficheros correctamente nombrados:
jquery.js betacompany_utils.js namespace_example.js |
Ficheros mal nombrados:
ConfirmDialog.js finalconf.js contactStatus.js |
En los ejemplos anteriores, se está utilizando indistintamente los criterios ‘StudlyCaps‘, ‘nonseparation‘ y ‘camelCase‘ respectivamente.
3. Objeto Global.
El objeto global es aquel que envuelve a toda la aplicación y que evita la contaminación del entorno global. Para denotar su jerarquía, se declara en mayúsculas precedido del signo de dolar ($) y su nombre suele coincidir con el de la aplicación.
var $UDO = {}; |
4. Subojetos globales.
Los subojetos globales son aquellas subdivisiones principales del proyecto que actúan como categorías superiores. Suelen segmentar el código en bibliotecas o bloques más manejables.
$UDO.UI = {}; // Jerarquía superior para todos los elementos gráficos. $UDO.TICKETS = {}; // Jerarquía superior para todas las acciones de los tickets. $UDO.WINDOW = {}; // Jerarquía superior para todas las acciones que engloben ventanas. $UDO.UTILS = {}; // Jerarquía superior para utilidades. Aquí se suelen incluir bibliotecas varias. |
5. Variables.
Las variables tienen que declararse utilizando la forma ‘camelCase’. No deben ir precedidas de un guion bajo para indicar que se tratan de variables privadas.
Cuando se declaren más de una variable de forma consecutiva, solo se utilizará una única sentencia ‘var‘.
var myVar = foo; |
var myVar = 'foo', myVar2 = 'bar', myVar3 = 'foobar'; |
Las variables que vayan a contener una instancia de jQuery, se identificarán anteponiéndoles un signo de dolar ($).
var myVar = 'foo', $myLayer = $('#layer-one'), $myLayer2 = $('#layer-two'); |
6. Constructores.
Los constructores (también llamados clases) tienen que nombrarse siguiendo la forma ‘StudlyCaps‘ para diferenciarlos a simple vista del resto de estructuras.
var WindowFrame = function(col) { var that = this, color = col; this.getColor = function() { return color; }; } var blueWindow = new WindowFrame("blue"); |
7. Constantes.
Las constantes se nombran en mayúsculas y separando palabras con un guión bajo. Evitamos el uso del comando @const para evitar errores en Internet Explorer.
$UDO.UI.window.defaults = function() { var WINDOW_WIDTH = 400px, WINDOW_HEIGHT = 400px; /* ... */ } |
8. Propiedades.
Las propiedades se declaran utilizando ‘camelCase‘ al igual que las variables.
$UI.TICKETS.createNewTicket = function( params ) { var ticketType, ticketCreator = params.currentUser, startDate = params.currentDate, finishDate = undefined, ticketDetails; } |
9. Métodos.
Los métodos de los objetos tienen que ser nombrados utilizando ‘camelCase‘, al igual que las variables y propiedades.
$UDO.UI.printWindow = function( currentWindow ) { var retrievingData = function() { /* ... */ }, populatingWindow = function() { /* ... */ }, printingWindow = function() { /* ... */ } } |
Conclusión
Como indiqué más arriba, en Javascript no existe una guía de estilo definida como estándar y esto hace que cada desarrollador adopte la que crea más conveniente. Lo importante, sin embargo, es que nuestras aplicaciones presenten unas líneas uniformes y coherentes a lo largo de todos sus ficheros para facilitar su lectura.
El mantener esta coherencia es una marca de calidad en nuestros trabajos, extensible por supuesto a cualquier lenguaje (PHP, Java, CSS, …)
No se han discutido aquí las reglas de estilo para los comentarios, otra parte fundamental de un código, materia que me reservo para un próximo post.
Finalmente, para reconocer de un simple vistazo la claridad que unas reglas de estilo bien aplicadas otorgan a un código, aconsejo revisar algunos ejemplos brillantes que podemos encontrar en GitHub:
- Lodash: https://github.com/bestiejs/lodash/blob/master/lodash.js
- Impress.js: https://github.com/bartaz/impress.js/blob/master/js/impress.js
- Reveal.js: https://github.com/hakimel/reveal.js/blob/master/js/reveal.js
- Etc…
Todos los anteriores son buenos ejemplos de códigos legibles e incluso didácticos ya que no solo se limitan a comentar lo imprescindible sino que incluso hay ocasiones, como en Lodash, que el desarrollador comenta el porqué de una determinada función o comportamiento en lugar de otro.
Buen artículo, te falta por comentar un aspecto, la nomenclatura en los CSS. Utilizar la misma que en JS puede no ser la mejor aproximación ya que ambos lenguajes aparecen mezclados… y en estos casos conviene cambiar ligeramente el convenio para evitar errores y facilitar la lectura de código, una variación con la que me siento cómodo es en los CSS es cambiar el camelCase por guión medio
Si; la nomenclatura para CSS la abordaré en otro artículo, como la de los comentarios/documentación dentro del código Javascript.
Como adelanto, estoy de acuerdo contigo y yo también utilizo el guión medio en lugar de la notación ‘underscore’.
Son variaciones sutiles pero que buscan casar un poco mejor con el la filosofía de cada lenguaje.
Gracias por el comentario.
Saludos!
Excelente post, muy completo y las fuentes que ofrece para ampliar el conocimiento estan de lujo para practicar… quedo pendiente de las otras guias de estilo.
Gracias!!!
No me había planteado anteponer $ a las variables que almacenen jQuery, ¡a la caja de herramientas instantáneamente!
PD: ¿en el punto8, «$UI.Tickets» no debería ser «$UI.TICKETS»?
Si; el tema de la $ para indicar objetos jQuery es una buena práctica (muy útil) para identificar de un solo vistazo el tipo o contenido de la variable a la que acompaña.
Estás en lo cierto con respecto al punto 8; corregido!
Saludos.
Muy buen artículo Carlos!
Una pregunta, mirando el código que hacen la gente de twitter (http://twitter.github.com/bootstrap/)
Me he fijado en dos cosas que me han llamado la atención:
1) No usan el el punto y coma «;» al final de la líneas
2) Cuando utilizan al coma «,» para separar variables por ejemplo, esta en el principio de la linea:
var $tip
, inside
, pos
, actualWidth
, actualHeight
, placement
, tp
Que opinas, es útil incorporar estos dos conceptos.
Gracias y felicidades por el blog.
Buenas Marc;
buen aporte en cuanto al modo de trabajo en Twitter con su Bootstrap!
En cuanto a no terminar cada sentencia con punto y coma, personalmente lo considero un error importante en cuanto a codificación. El propio JSLint (http://www.jslint.com) ya advierte que esa omisión puede provocar errores inesperados cuando minificamos el código en, por ejemplo, un paso a producción. La guía de estilo Google explica perfectamente el problema:
Fuente: Guía de estilo Google
El caso de la coma precediendo a los elementos de una enumeración es una práctica común en diversas empresas y que si recogen varias guías de estilo. La razón práctica radica en dos aspectos clave: por un lado, evitamos las fatídicas ‘trailing commas’ que arrojan errores de interpretación en navegadores como IE:
Como vemos, si dejamos la última coma, rompemos el código. Más información al respecto en este hilo de StackOverflow.
Por otro lado, el poner las comas delante facilita la fase de desarrollo al permitirnos comentar líneas sin miedo a precisamente dejar comas huérfanas. Pensemos por ejemplo que, en el listado anterior, queremos comentar algunas variables para que no estén disponibles. Si añadimos la doble barra delante de cada una, comentamos también sus respectivas comas, por lo que salvamos el posible error anterior:
De este modo, podemos comprobar que es más sencillo el trabajo en las fases de desarrollo justificando así el uso de la coma delante. Finalmente, hay quienes ven ‘más estético’ el alinear las comas delante, pero eso es ya cuestión de gustos…
Personalmente, no me disgusta el anteponer las comas, pero no suelo hacerlo. No obstante, el apunte es interesante y no está de más el comentarlo aquí.
Saludos!
Muchas gracias por la respuesta Carlos!
Es de agradecer de respondas tan rápido y ampliamente con referencias y todo 😛
Saludos,
Marc
Y en cuanto a como declarar los métodos internos en un objeto?
He visto cosas así:
o mejor así?
Yo prefiero siempre utilizar la forma ‘clásica’ a la hora de declarar métodos:
Hay muchas formas de articular el objeto anterior y todas correctas; la cuestión es encontrar con la que te encuentres más cómodo manteniéndonos siempre dentro de unos parámetros de estilo y coherencia con respecto al resto del código.
Saludos!
Llevo bastante tiempo interesado en aprender a programar con javascript pero nosé donde alcanzar dichos conocimientos. ¿Alguien puede recomendarme donde aprender de manera eficaz y «rápida» este lenguaje?
Muchas gracias.
Comentaba estas formas de declarar los métodos por que function a(){} tengo entendido que es mejor si puedes usarlo que var a = function(){}. Aunque siempre estaba usando esta segunda forma de declararlas, empecé a questionarmelo por que veía scripts de otros, mucho más pro, y veía que las funciones dentro de su namespacing las ponian así.
Por otro lado es cierto que exponer los métodos, como en el primer ejemplo que pasé, no lo va a pasar JSLINT, ponerlos al principio, por que llamas a algo que aun no a sido declarado, o eso creo recordar, por mucho que sea de la forma function a(){} que en funcionalmente si funciona.
Me ha gustado el concepto del return final para exponer las cosas, aunque lo conocía no había caído en hacerlo, ya que encima así evitas el this todo el rato, de forma que además queda al final, pasando JSLINT mejor.
Gracias.