"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.

costes-software 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.

¿Qué es Clean Code?

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.  

clean-code 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.

Variables y nombres

“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.

costes-software 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:

Nombres pronunciables y expresivos

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');

Uso correcto de var, let y const

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

Evitar que los nombres contengan información técnica

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(){...}

Léxico coherente

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()

Usa el nombre adecuado según el tipo de dato

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.