Capítulo 8 Guía de estilo de código en R

Hay muchas formas de escribir código en R. Entre más código escribes y sobretodo entre más código tienes que leer, más apreciarás un estilo uniforme. Te permitirá leer tu propio código y volver a entenderlo más fácilmente después de un largo tiempo sin haberlo visto. Además, un estilo uniforme te permitirá trabajar más efectivamente con otros.

Cuando empiezas a trabajar en equipo es buena práctica ponerse de acuerdo de antemano sobre el estilo. Así quedará mas fácil entender el código de los demás y será más fácil cuando un nuevo miembro se una al equipo.

Aquí abajo presentamos los diferentes elementos que pueden estar en una guía de estilo. Está basado en el guía de estilo de Hadley Wickham. Este a su vez está basado en la guia de estilo de Google. Añado la sugerencias que son relevantes para hispanohablantes. Esto porque en el español estamos acostumbrados, entre otras cosas, a tildes, eñes y otros caracteres que necesitan su propia discusión.

Existen paquetes para formatear código automáticamente, especialmente formatR de Yihui Xie. Estos son útiles, pero pueden tener diferencias a lo acordado en tu equipo. En la práctica muchas veces es recomendable arreglar código a mano. Al leer y revisar código para verificar detalles de estilo muchas veces encuentras errores que de otra forma no habrías visto.

Para nuestros proyectos estas reglas no son opcionales. Buscamos tener una presentación uniforme de código a nuestros clientes y necesitamos poder leer nuestro código entre nosotros de forma eficiente.

Presentamos ésta guía con

8.1 Nomenclatura

Nombres de archivos deben tener un nombre descriptivo, no tener caracteres especiales (tildes, eñes) y terminar en .R

# Bien
modelo_predictivo.R
lectura_datos.R

# Mal
ModeloPredictivo2020.r
código-añejo.r
versiondellunes.r

Si tu solución o estudio requiere que los archivos se corran en una secuencia predeterminada, añade prefijos con numerales:

0-importar_datos.R
1-analisis_exploratorio.R
2-modelo_predictivo.R

8.1.1 Nombres de objetos

La guía de Google da una recomendación diferente a la de H. Wickam sobre el uso de guiones bajos (_) y guiones (-) para separar palabras. No hay un consenso (Baath 2012) entre autores, pero la recomendación de H. Wickam es la más actual. Él recomienda que en general nombres de variables y de funciones deben ser en minúscula y que se ha de usar un guión bajo (_) para separar palabras dentro de un nombre. Toma en cuenta de que no es fácil encontrar nombres que son cortos y auto explicativos a la vez, pero trata de encontrarlos. Wickham tambien recomienda Usa sustantivos para los nombres de las variables y verbos para las funciones. Nunca uses caracteres especiales como tildes y eñes en tus nombres de objetos. En general es mejor no usar los carácteres especiales que tenemos en el español

# Bien
primer_cuartil
cuartil_1

# Mal
primer-cuartil
CuartilUno
C1
está_en_el_primer_cuartil
DatosJunio18

Si usas nombres de funciones que ya están en uso es probable que generes confusión. Trata de evitarlo hasta donde sea posible.

# Bien
suma_dos <- function(x) {
   x + 2
}

# Mal
F <- TRUE
any <- 24
ls <- function(x) read.table(x)

8.2 Sintaxis

8.2.1 Espacios

Antes y después de todos los operadores infijos va un espacio (=, +, <-, etc). Esto aplica aún para el signo equivalente (=) en las llamadas de una función. No hay espacios antes de una coma, pero una coma siempre es seguida por un espacio.

# Bien
profundidad <- round((pies + pulgadas / 12), digits = 2)

# Mal
profundidad<-round((pies+pulgadas/12),digits=2)

La excepción a esta regla es cuando se usan :, :: y :::

# Bien
x <- 2:23
base::round

# Mal
x <- 2 : 23
base :: round

Antes del paréntesis izquierdo va un espacio, a no ser que estés llamando una función en cual caso no se usa un espacio.

# Bien
if (debug) do(x)
qplot(x, y)

# Mal
if(debug)do(x)
qplot (x, y)

Cuando quieras introducir más orden en el código alineándolo por ejemplo, sobre los símbolos de igualdad, está bien usar espacios para lograr tal efecto.

data.frame(
   nombres     = c("Maria", "José", "John"),
   resultados  = c(7, 3, 8),
   primera_vez = c(TRUE, FALSE, TRUE)
)

Los paréntesis y corchetes ([]) no llevan espacios a su alrededor. Si hay una coma, aplican las convenciones que se mencionaron antes.

# Bien
if (depurando) x <- 34 
resultados[5, 1]

# Mal

if ( depurando ) x <- 34# no pongas espacios alrededor de tu variable
resultados[1,]   # falta un espacio detrás de la coma
resultados[1 ,]  # un espacio demás antes y de menos después de la coma

8.2.2 Punto y coma

No uses punto y coma dentro del código. No es necesario y prácticamente ya no se usa.

# Bien
print("El resultado:")
print(x)

cat("El resultado: \n", x)

# Mal
print("El resultado:"); print(x)

8.3 Llaves

Abrir una llave nunca debería ocurrir en su propia linea y siempre se sigue con una linea nueva. Una llave que cierra siempre debe ir en su propia linea a menos que sea else. Siempre usa llaves cuando estas usando construcciones con “if,” aun cuando no es posible no hacerlo.

Para visualizar mejor de que se trata de un bloque, siempre usa sangría para el código dentro de llaves, aún cuando se trata de una sola línea.

# Bien
if (x != 0 && depurando) {
  cat("x no es 0 pero:", x)
}

if (x == 0) {
  0
  } else {
  z / x
}

# Mal
if (x != 0 && depurando) 
cat("x no es 0 pero:", x)

if (x == 0) {
0
} else {
z / x
}

8.4 Longitud de lineas

Trata de limitar tu código a una longitud de 80 caracteres por linea. Esto cabe cómodamente en una página impresa a un tamaño de la fuente razonable. Si encuentras que no tienes suficiente espacio, esto es una buena indicación de que deberías encapsular alguna parte del trabajo en una función separada.

8.5 Sangría

Usa dos espacios para añadir una sangría a tu código y nunca usa la tecla TAB. Si te encuentras con código que usa una mezcla de espacios y TABs, cámbialo inmediatamente al uso exclusivo de espacios.

Hay una excepción a esta regla cuando tu función corre sobre más de una linea. Para formatear el código de forma legible en esto casos, corre la sangría de la segunda linea para alinear los componentes de la función.

nombre_de_objecto_largo <- function(argumento_1 = "varias palabras"),
                                    argumento_2 = "que corren hasta la siguiente linea"
                                    argumento_3 = "pero se dejan leer de esta forma") {
  # desde aquí usamos la sangría de dos espacios otra vez
}

8.5.1 Asignación

Es mejor usar solo <- para asignación en vez de = y usar el símbolo de igualdad solamente para argumentos dentro de funciones.

# Bien
y <- 23

# Mal
y = 23

8.6 Organización

8.6.1 Guias para comentarios

Usa comentarios en tu código. Cada linea debe comenzar con un símbolo de comentario (#) y un solo espacio: #. Los comentarios deben explicar el por qué, y no el qué.

Para separar y estructurar el código en segmentos se puede usar cualquier carácter después de la tecla numeral (#). Común es el uso de más # o un separación con guiones - como aquí abajo. En ambos caso RStudio te va a ayudar a navegar el código.

Existe además el atajo ctrl + shift + r el cual creará un separador

### Gráfica principal ########################################################
# Añadimos comentarios para ayudar al lector del código

# Carga datos -----------------------------
# Lo importante de la separación no es como lo anotas pero donde lo pones.

# Con atajo de RStudio ----------------------------------------------------

8.6.2 Crear nombres válidos

Al trabajar en entornos con datos en español, a veces tenemos nombres de fila y columnas que contienen caracteres no-ASCII. La mayoría de funciones en R no tiene problemas con estos, pero a veces sí los dan. Para rápidamente cambiar los nombres a nombres válidos se puede hacer lo siguiente.

nombres <- ("Abóbora", "Almendrón de Guaduas", "Araça vermelho")

# Para cambiarlos a nombre sintácticamente válidos
make.names(nombres)

# Pare remover todo carácter no-ASCII
iconv(nombres, to='ASCII', sub='.')

En caso de que los nombres anteriores pertenezcan a un data frame, podemos hacer uso de la función clean_names() del paquete janitor:

datos <- janitor::clean_names(datos)

8.7 Código

8.7.1 ¿Cómo decidir sobre qué paquetes usar?

Por defecto usamos paquetes del tidyverse. La mayor razón es consistencia y estilo (ayuda a crear código fácil de leer). Y hablamos de tidyverse sensu lato, para incluir paquetes como naniar, lumberjack etc.

Aplicando el estilo de código arriba, al usar dpyr recomendamos después de cada pipe (%>%) seguir en una linea nueva:

iris %>% 
   clean_names() %>% 
   filter(sepal_length > 5) %>% 
   group_by(species) %>% 
   summarise(
      promedio = mean(petal_length, na.rm = TRUE),
      valor_maximo = max(petal_length, na.rm = TRUE)
   )

8.7.2 ¿Cómo hacer un buen commit?

Un buen commit consiste de:

  1. Un cambio claro (no mezclar demasiados cambios). Es mejor ser claro a través de la inclusión de varios pasos en un proceso hacia el objetivo / la solución que estas buscando en vez de tratar de arreglar todo antes de hacer el commit.
  2. Cambios, inclusive si los vez como temporales, ¡se adhieren a esta guía de estilo! Mejor código ordenado que no funcionó, a código que más o menos funciona pero es difícil de leer.
  3. Un título de máximo 50 caracteres y después un cuerpo si fuera necesario. Este post de Tim Pope explica porqué.