Foto de Matheus Bertelli en Pexels.
La única forma de escribir buen código es escribir primero toneladas de código de mierda. Sentir vergüenza por el código malo te impide llegar al código bueno.
Presentaré una colección de cosas muy útiles que he aprendido en los últimos años.
Después de cada sección haré un resumen y te pediré que comentes.
Después, elige una cosa para mejorar en tu paquete.
Conoce a los paquete cli
variable <- 42
cli::cli_alert_info("Set {.field parameter} to {.val {variable}}")
#> ℹ Set parameter to 42
¿Cómo controlar la verbosidad?
argumento en cada función 😩
cli_alert_info <- function(...) {
if (!getOption("usethis.quiet", default = FALSE)) {
cli::cli_alert_info(...)
}
}
Para leer más: https://ropensci.org/blog/2024/02/06/verbosity-control-packages/
🧰 ¿Hay mensajes en tu paquete que podrías mejorar?
Consejos sobre el contenido en el guía de estilo de tidyverse con ejemplos.
Interfaz con cli::cli_abort()
🧰 Revisa los mensajes de error de tu paquete (busca stop()
y equivalentes). ¿Podrían mejorarse algunos de ellos aplicando la guía de la tidyverse?
Tipo de argumento del documento, por defecto.
Comprueba los argumentos. rlang::arg_match()
por ejemplo.
Más información: Comprobar las entradas de tus funciones en R por Hugo Gruson , Sam Abbott , Carl Pearson.
🧰 ¿Tu paquete documenta y valida los argumentos? Mejora esto en una sola función o más.
stop()
🎤Por favor, publícalo en el chat
¿Esta dependencia provoca alegría? 😉
Más información: Dependencias: Mentalidad y antecedentes en el libro R Packages de Hadley Wickham y Jenny Bryan.
En la Guía de desarrollo de rOpenSci
curl, httr2, crul, httr. No RCurl. Para un nuevo paquete, httr2 en vez de httr.
jsonlite. No rjson ni RJSONIO.
xml2. No XML
sf, suites espaciales desarrolladas por las comunidades r-spatial y rspatial. No sp, rgdal, maptools, rgeos.
🧰 ¿Hay dependencias que podrías añadir, sustituir o eliminar en tu paquete?
Feature creep: “ampliación o adición excesiva y continua de nuevas funciones en un producto” https://en.wikipedia.org/wiki/Feature_creep
Está bien dividir el paquete.
Está bien decir no a las peticiones de funciones. Ejemplo
🧰 ¿Hay peticiones de funciones a las que te gustaría decir que no? Guardar respuesta como Respuesta GitHub?
stop()
🎤Por favor, publícalo en el chat
👀
✨
do_this <- function() {
if (!is_that_present()) {
return(NULL)
}
# more code
blip
}
switch()
👀
switch()
✨
Para leer más: El código huele y se siente por Jenny Bryan
🧰 Examina la lógica de una o varias funciones. ¿Podrías simplificarla con retornos anticipados, funciones auxiliares? ¿Cambiar la ordén de las condiciones de ifelse?
lintr encuentra problemas en código.
flir también, puede reparar algunos.
Para leer más: Cómo uso lintr en mi blog.
🧰 Intenta mejorar tu paquete con flir y/o lintr
Algunos de ellos sólo son relevantes si ves código.
Alinea los argumentos en las definiciones de función.
¿Más alineación vertical? No soy sensible a ello 😇
Un párrafo = una idea (¡también sirve para escribir prosa!).
El espacio vertical es costoso (¿qué cabe en la pantalla?)
head <- collect_metadata(website)
head_string <- stringify(head)
body <- create_content(website)
body_string <- stringify(body)
En RStudio IDE o Positron. En cualquier caso, es bueno para indicar la estructura de alto nivel dentro de un script.
# Header level 1 ----
more
code
## Header level 2 ----
more
code
🧰 Abre uno o varios scripts, ¿puedes mejorar la estética? ¿Usar Air en todo el paquete?
Los comentarios son como pequeñas alertas. ¡No generes fatiga!
Los comentarios que repiten el código quedan desfasados.
# use only non empty strings
if (!is.na(x) && nzchar(x)) {
use_string(x)
}
is_non_empty_string <- function(x) {
!is.na(x) && nzchar(x)
}
if (is_non_empty_string(x)) {
use_string(x)
}
Más información: https://blog.r-hub.io/2023/01/26/code-comments-self-explaining-code/
🧰 ¿Existen posibilidades de hacer menos comentarios (¡o más comentarios!) en algunos de tus guiones?
stop()
🎤Por favor, publica en el chat
“DAMP (descriptive and meaningful phrases)”
“DRY (don’t repeat yourself)”
¡Un intercambio!
El código está cubierto por el código de tests, ¡así que podemos asumir más riesgos!
Autónomas.
Se pueden ejecutar de forma interactiva. testthat::test_path()
.
Sin “fugas”. {withr}. withr::local_options()
, withr::local_tempdir()
…
Exploremos https://github.com/maelle/swamp
🧰 ¿Algunas de tus tests tienen código de nivel superior? ¿Puedes crear archivos y funciones de ayuda, y repetir la creación de objetos en cada prueba?
Mi código
is_internet_down <- function() {
!curl::has_internet()
}
my_complicated_code <- function() {
if (is_internet_down()) {
message("No internet! Le sigh")
}
# blablablabla
}
¿Cómo comprobar el mensaje?
En el test,
test_that("my_complicated_code() notes the absence of internet", {
local_mocked_bindings(is_internet_down = function(...) TRUE)
expect_message(my_complicated_code(), "No internet")
})
Para leer más: https://www.tidyverse.org/blog/2023/10/testthat-3-2-0/#mocking
🧰 ¿tienes una situación de este tipo para probar?
stop()
🎤Por favor, publica en el chat
…¡con tu propio paquete! En salas de descanso.
Nos reuniremos en XX minutos como grupo para debatir.
¿Comentarios? ¿Preguntas?
Nos vemos en el #package-maintenance
canal? 😉