Software Crafters ® | Creado con 🖤 para elevar el nivel de la conversación sobre programación en español| Legal
"Programar es el arte de decirle a otro humano lo que quieres que el ordenador haga." -- Donald Knuth
En los últimos años, JavaScript se ha convertido en uno de los lenguajes más utilizados del mundo. Su principal ventaja, y a la vez su mayor debilidad, es su versatilidad. Esa gran versatilidad ha derivado en algunas malas prácticas que se han ido extendiendo en la comunidad, aún así, Javascript se encuentra en infraestructuras críticas de empresas muy importantes (Facebook, Netflix o Uber lo utilizan), en las cuales limitar los costes derivados del mantenimiento del software se vuelve esencial.
El coste total de un producto software viene dado por la suma de los costes de desarrollo y de mantenimiento, siendo este último mucho más elevado que el coste del propio desarrollo inicial. A su vez, como expone Kent Beck en su libro Implementation Patterns, el coste de mantenimiento viene dado por la suma de los costes de entender el código, cambiarlo, testearlo y desplegarlo.
Esquema de fórmula de costes de Kent Beck
La idea de este artículo es tratar de minimizar el coste relacionado con la parte de entender el código, para ello trataré de sintetizar y ampliar algunos de los conceptos relacionados con esto que exponen Robert C. Martin, Kent Beck, Ward Cunningham y otros autores aplicándolos a JavaScript.
Clean code o código limpio en español, es un término al que ya hacían referencia desarrolladores de la talla de Ward Cunningham o Kent Beck, aunque no se popularizó hasta que Robert C. Martin, también conocido como Uncle Bob, publicó su libro “Clean Code: A Handbook of Agile Software Craftsmanship” en 2008.
El libro, aunque sea bastante dogmático y quizás demasiado focalizado en la programación orientada a objetos, se ha convertido en un clásico que no debe faltar en la estantería de ningún desarrollador que se precie, aunque sea para criticarlo.
Viñeta de osnews.com/comics/ sobre la calidad del código
Existen muchas definiciones para el término clean code, pero yo personalmente me quedo con la de mi amigo Carlos Blé, ya que además casa muy bien con el objetivo del artículo.
"Código limpio es aquel que se ha escrito con la intención de que otra persona (o tú mismo en el futuro) lo entienda." -- Carlos Blé
Los desarrolladores solemos escribir código sin la intención explícita de que vaya a ser entendido por otra persona, ya que la mayoría de las veces nos centramos simplemente en implementar una solución que funcione y que resuelva el problema.
Tratar de entender el código de un tercero o incluso el que escribimos nosotros mismos hace tan solo unas semanas, se puede volver una tarea realmente difícil. Es por ello que hacer un esfuerzo extra para que nuestra solución sea legible e intuitiva es la base para reducir los costes de mantenimiento del software que producimos.
A continuación veremos algunas de las secciones del libro de Uncle Bob que más relacionadas están con la legibilidad del código. Si conoces el libro o lo has leído, podrás observar que he añadido algunos conceptos y descartado otros, además de incluir ejemplos sencillos aplicados a JavaScript.
“Nuestro código tiene que ser simple y directo, debería leerse con la misma facilidad que un texto bien escrito” -- Grady Booch
Nuestro código debería poder leerse con la misma facilidad con la que leemos un texto bien escrito, es por ello que escoger buenos nombres es fundamental. Los nombres de variables, métodos y clases deben seleccionarse con cuidado para que den expresividad y significado a nuestro código.
Viñeta de Commit Strip sobre el nombrado de variables.
A continuación veremos algunas pautas y ejemplos para tratar de mejorar a la hora de escoger buenos nombres:
Los nombres, imprescindiblemente en inglés, deben ser pronunciables. Esto quiere decir que no deben ser abreviaturas ni llevar guion bajo o medio, priorizando el estilo CamelCase. Por otro lado, debemos intentar no ahorrarnos caracteres en los nombres, la idea es que sean lo más expresivos posible.
//bad const yyyymmdstr = moment().format('YYYY/MM/DD'); //better const currentDate = moment().format('YYYY/MM/DD');
Debemos evitar a toda costa el uso de var, ya que define las variables con alcance global. Esto no ocurre con las variables definidas con let y const, ya que se definen para un ámbito en concreto.
La diferencia entre let y const radica en que a esta última no se le puede reasignar su valor (aunque sí modificarlo). Es por ello que usar const en variables a las que no tengamos pensado cambiar su valor puede ayudarnos a mejorar la intencionalidad de nuestro código.
// old school JavaScript var variable = 5; { console.log('variable); // 5 var variable = 10; } console.log(variable); // 10 variable = variable*2; console.log(variable); // 20 // modern JavaScript (let) let variable = 5; { console.log(variable); // error let variable = 10; } console.log(variable); // 5 variable = variable*2; console.log(variable); // 10 // modern JavaScript (const) const variable = 5; variable = variable*2; // error console.log(variable); // doesn't get here
Si estamos construyendo un software de tipo vertical (orientado a negocio), debemos intentar que los nombres no contengan información técnica en ellos, es decir, evitar incluir información relacionada con la tecnología, como el tipo de dato o la notación húngara, el tipo de clase, etc. Esto sí se admite en desarrollo de software horizontal o librerías de propósito general.
//bad class AbstractUser(){...} //better class User(){...}
Debemos usar el mismo vocabulario para hacer referencia al mismo concepto, no debemos usar en algunos lados User, en otro Client y en otro Customer, a no ser que representen claramente conceptos diferentes.
//bad getUserInfo(); getClientData(); getCustomerRecord(); //better getUser()
Arrays
Los arrays son una lista iterable de elementos, generalmente del mismo tipo. Es por ello que pluralizar el nombre de la variable puede ser una buena idea:
//bad const fruit = ['manzana', 'platano', 'fresa']; // regular const fruitList = ['manzana', 'platano', 'fresa']; // good const fruits = ['manzana', 'platano', 'fresa']; // better const fruitNames = ['manzana', 'platano', 'fresa'];
Booleanos
Los booleanos solo pueden tener 2 valores, verdadero o falso. Dado esto, el uso de prefijos como "is", "has" y "can" ayudará inferir el tipo de variable, mejorando así la legibilidad de nuestro código.
//bad const open = true; const write = true; const fruit = true; // good const isOpen = true; const canWrite = true; const hasFruit = true;
Números
Para los números es interesante escoger palabras que describan números, como “min”, “max”, “total”:
//bad const fruits = 3; //better const maxFruits = 5; const minFruits = 1; const totalFruits = 3;
Funciones
Los nombres de las funciones deben representar acciones, por ello que deben construirse usando el verbo que representa la acción seguido de un sustantivo. Estos deben de ser descriptivos y, a su vez, concisos. Esto quiere decir que el nombre de la función debe expresar lo que hace, pero también debe de abstraerse de la implementación de la función.
//bad createUserIfNotExists() updateUserIfNotEmpty() sendEmailIfFieldsValid() //better createUser(...) updateUser(...) sendEmail()
En el caso de las funciones de acceso, modificación o predicado, el nombre debe el prefijo get, set, e is, respectivamente. [i]
getUser() setUser(...) isValidUser()
Clases
Las clases y los objetos deben tener nombres formados por un sustantivo o frases de sustantivo como User, UserProfile, Account, AdressParser. Debemos evitar nombres como Manager, Processor, Data o Info.
Hay que ser cuidadosos a la hora de escoger estos nombres, ya que son el paso previo a la hora de definir la responsabilidad de la clase. Si escogemos nombres demasiado genéricos tendemos a crear clases con múltiples responsabilidades.