Best Practices
## Learning Objectives
- Follow R coding style guidelines
- Write reproducible code
- Document your work
- Use version control
## R Style Guide
### Naming Conventions
```r
# Variables and functions: snake_case
my_variable <- 5
calculate_mean <- function(x) {}
# Constants: SCREAMING_SNAKE_CASE
MAX_ITERATIONS <- 1000
# Avoid single letter names (except in loops)
# Good:
for (i in seq_along(items)) {}
# Bad:
for (j in seq_along(items)) {}
# Be descriptive
# Good:
population_mean <- 45.2
# Bad:
pm <- 45.2
```
### Spacing
```r
# Spaces around operators
x <- 5 + 3 # Good
x<-5+3 # Bad
# Space after comma
# Good:
mean(x, na.rm = TRUE)
mean(x , na.rm = TRUE) # Bad
# Space before ( in function calls
# Good:
mean(x)
mean(x, na.rm = TRUE)
# Bad:
mean (x)
mean (x, na.rm = TRUE)
```
### Curly Braces
```r
# Opening brace on same line
if (x > 0) {
print("positive")
} else {
print("non-positive")
}
# Always use braces for multi-line blocks
if (x > 0)
print("positive") # Bad - error prone
if (x > 0) {
print("positive")
} # Good
```
### Line Length
```r
# Keep lines under 80 characters
# Break long function calls
result <- some_function(
argument1 = value1,
argument2 = value2,
argument3 = value3
)
# Use variables to break chains
intermediate_result <- step_one(data)
final_result <- step_two(intermediate_result)
```
### Indentation
```r
# Use two spaces for indentation
function_with_long_name <- function(argument1, argument2) {
if (condition) {
do_something()
} else {
do_something_else()
}
}
```
## Documentation
### Script Header
```r
# Title: Data Analysis Script
# Description: Performs analysis on customer data
# Author: John Doe
# Date: 2024-01-15
# Usage: Rscript analysis.R [input_file]
# Output: results.csv
# Load required packages -----------------------------------------
library(dplyr)
library(ggplot2)
# Main analysis ---------------------------------------------------
main <- function() {
# code here
}
# Run if executed as script
if (!interactive()) {
main()
}
```
### Function Documentation
```r
#' Calculate summary statistics
#'
#' Computes mean, standard deviation, and count for a numeric vector.
#'
#' @param x A numeric vector
#' @param na.rm Logical; if TRUE, remove NAs (default TRUE)
#' @param trim The fraction of values to trim from each end
#'
#' @return A named list with mean, sd, and n
#'
#' @examples
#' my_summary(c(1, 2, 3, 4, 5))
#' my_summary(c(1, 2, NA), na.rm = TRUE)
#'
#' @export
my_summary <- function(x, na.rm = TRUE, trim = 0) {
# implementation
}
```
### roxygen2 Tags
| Tag | Description |
|-----|-------------|
| @param | Parameter description |
| @return | What the function returns |
| @examples | Usage examples |
| @export | Export function |
| @import | Import from other packages |
| @note | Additional notes |
| @references | Related references |
## Project Organization
### Directory Structure
```text
project/
R/
R/
functions.R
helpers.R
DESCRIPTION
NAMESPACE
data/
raw/
processed/
output/
figures/
tables/
vignettes/
README.md
DESCRIPTION
.Rbuildignore
project.Rproj
```
### Use RStudio Projects
```r
# Create project in RStudio: File -> New Project
# Benefits:
# - Self-contained working directory
# - Easier package management
# - Version control integration
```
## Reproducible Research
### set.seed()
```r
# Set seed for random number generation
set.seed(42)
# Now results are reproducible
rnorm(5) # Always the same
rnorm(5) # Different without seed
```
### Session Info
```r
# Capture session info
sessionInfo()
# For reproducibility documentation
sink("session_info.txt")
sessionInfo()
sink()
```
### packrat / renv
```r
# Initialize renv for project
renv::init()
# Snapshot dependencies
renv::snapshot()
# Restore from snapshot
renv::restore()
```
### rmarkdown for Reports
```r
# Create .Rmd file for reproducible reports
# Combines code, output, and narrative
---
title: "Analysis Report"
output: html_document
---
{r setup, include=FALSE}
library(dplyr)
{r cars}
summary(cars)
{r plot, echo=FALSE}
plot(cars)
```
### Parameters in Rmarkdown
```r
# Use params for parameterized reports
---
params:
data_file: "data.csv"
threshold: 0.05
---
{r}
read.csv(params$data_file)
```
## Version Control with Git
### Initialize Repository
```bash
git init
git add .
git commit -m "Initial commit"
```
### Common Commands
```bash
git status # Check status
git add file.R # Stage file
git commit -m "Message"
git push # Push to remote
git pull # Pull from remote
git branch # List branches
git checkout -b new_feature # Create and switch
```
### .gitignore
```text
# R
.Rproj.user/
.Rhistory
.RData
.Ruserdata/
# Packages
packrat/lib/
renv/library/
# Output
*.pdf
*.png
output/
# OS
.DS_Store
Thumbs.db
```
## Package Development
### Package Structure
```text
mypackage/
DESCRIPTION
NAMESPACE
R/
function1.R
function2.R
man/
function1.Rd
tests/
testthat/
test_function1.R
vignettes/
intro.Rmd
```
### DESCRIPTION File
```text
Package: mypackage
Title: What the Package Does
Version: 0.1.0
Author: Your Name
Maintainer: Your Name
Description: Package description
License: MIT
Imports:
dplyr,
tidyr
Suggests:
testthat,
knitr
VignetteBuilder: knitr
```
### Use devtools
```r
library(devtools)
create_package("mypackage") # Create structure
load_all() # Load package
check() # Check package
document() # Generate documentation
build() # Build package
```
## Testing
### testthat Package
```r
library(testthat)
test_that("mean works correctly", {
expect_equal(mean(1:5), 3)
expect_equal(mean(c(1, 2, NA), na.rm = TRUE), 1.5)
})
test_that("error handling works", {
expect_error(calculate_stats("not numeric"))
})
```
### Running Tests
```r
# In package development
devtools::test()
# Run specific test file
test_file("tests/testthat/test_functions.R")
```
## Code Review Checklist
### Before Committing
- [ ] Code runs without errors
- [ ] Functions have documentation
- [ ] Variable names are descriptive
- [ ] No hardcoded paths or values
- [ ] set.seed() for random operations
- [ ] Comments explain why, not what
- [ ] No commented-out code
- [ ] Follows style guide
### For Functions
- [ ] Input validation
- [ ] Error handling
- [ ] Return value documented
- [ ] Examples provided
- [ ] Edge cases handled
## Summary
- Follow consistent naming conventions (snake_case)
- Document scripts and functions
- Use RStudio Projects for organization
- Make code reproducible with set.seed() and packrat/renv
- Use Rmarkdown for reproducible reports
- Version control with Git
- Write tests for important functions
- Review code before committing
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →