Best Practices & Style

48.1 Style (tidyverse style guide)

snake_case names; verbs for functions (clean_data()), nouns for objects.

<- for assignment; spaces around operators and after commas; 2-space indentation; lines ≤ 80 characters.

Use TRUE/FALSE, never T/F.

One pipe step per line.

Automate: styler (styler::style_file()), lintr (lintr::lint_dir()), air (fast R formatter).

48.2 Writing good R code

Write functions for anything you do more than twice; keep them small and pure.

Vectorize; avoid growing objects in loops.

Be explicit about missing values (na.rm, is.na).

Validate inputs (stopifnot, rlang::arg_match, checkmate).

Prefer seq_along()/seq_len() over 1:length(x) (breaks for length 0).

Use vapply/map_* for type stability; avoid sapply in package code.

Use [[ for single elements of lists; drop = FALSE in matrix/data-frame subsetting inside functions.

Avoid attach(), setwd(), rm(list = ls()) in scripts.

Use :: in packages and production scripts.

Set seeds and record sessionInfo()/renv.lock.

Comment *why*, not *what*.

Write tests (testthat) for important functions, even outside packages.

48.3 Common pitfalls

1:length(x) when x is empty floating-point == all.equal(), dplyr::near() any(), all(), or ifelse() growing vectors in loops pre-allocate or map() T/F overwritten always write TRUE/FALSE partial matching with $ on lists/data frames use [[ or tibbles check lengths; tidyverse functions error on bad recycling

sapply returning list or matrix unexpectedly vapply / map_dbl stringsAsFactors surprises (R < 4.0) upgrade or set explicitly hard-coded absolute paths Projects + here()