Introduction to Building (Better) R Packages
From scripts to packages: Making your code reusable and shareable
Overview
Beginner Friendly Package Development Best Practices
Transform your R scripts into professional packages! Learn the fundamentals of package development, from basic structure to documentation, testing, and sharing. By the end of this workshop, you will have made an R package!
What Youβll Learn
- π¦ Package structure - Essential components
- π§ Writing functions - Package-friendly style
- π Documentation - roxygen2 and examples
- β Testing - Ensuring code quality
- π Sharing - GitHub and CRAN
- π‘ Best practices - Professional development
Prerequisites
Required Knowledge:
- Basic R programming
- No prior package development experience needed!
- No function writing experience required!
Setup:
- R and RStudio
{devtools}and{usethis}packages
Key Packages
{devtools}
{usethis}
{roxygen2}
{testthat}
{pkgdown}
Workshop Materials
Why Build Packages?
Benefits
- β»οΈ Reusability - Use your code across projects
- π€ Sharing - Collaborate easily with others
- π Documentation - Built-in help pages
- β Testing - Ensure code reliability
- π― Organization - Structured project layout
Workshop Structure
Part 1: Package Basics (45 min)
Creating Your First Package:
library(usethis)
# Create package structure
create_package("~/mypackage")
# Your package now has:
# - DESCRIPTION file
# - NAMESPACE file
# - R/ directory
# - .Rproj fileEssential Components:
- DESCRIPTION - Package metadata
- NAMESPACE - Function exports
- R/ - Function code
- man/ - Documentation (auto-generated)
Part 2: Writing Functions (45 min)
Package-Friendly Function Style:
# R/my_function.R
#' Calculate Summary Statistics
#'
#' @param x A numeric vector
#' @param na.rm Logical. Should missing values be removed?
#'
#' @return A named vector of summary statistics
#' @export
#'
#' @examples
#' calculate_summary(c(1, 2, 3, 4, 5))
#' calculate_summary(c(1, 2, NA, 4), na.rm = TRUE)
calculate_summary <- function(x, na.rm = FALSE) {
if (!is.numeric(x)) {
stop("`x` must be numeric")
}
c(
mean = mean(x, na.rm = na.rm),
sd = sd(x, na.rm = na.rm),
min = min(x, na.rm = na.rm),
max = max(x, na.rm = na.rm)
)
}Best Practices:
- β Clear function names
- β Input validation
- β Informative error messages
- β Consistent parameter names
- β Return predictable output
Part 3: Documentation (30 min)
roxygen2 Documentation:
# Use roxygen2 comments above functions
#' (starts with #')
#'
#' @param parameter_name Description
#' @return What the function returns
#' @export Makes function available to users
#' @examples Usage examples
# Generate documentation
devtools::document()Creating README:
use_readme_md()Part 4: Testing (30 min)
Setting Up Tests:
# Initialize testing infrastructure
usethis::use_testthat()
# Create test file
usethis::use_test("my_function")Writing Tests:
# tests/testthat/test-my_function.R
test_that("calculate_summary works correctly", {
x <- c(1, 2, 3, 4, 5)
result <- calculate_summary(x)
expect_equal(result["mean"], 3)
expect_equal(result["sd"], sd(x))
expect_length(result, 4)
})
test_that("calculate_summary handles NA values", {
x <- c(1, 2, NA, 4)
expect_true(is.na(calculate_summary(x)["mean"]))
expect_false(is.na(calculate_summary(x, na.rm = TRUE)["mean"]))
})
test_that("calculate_summary validates input", {
expect_error(calculate_summary("not numeric"))
})Part 5: Sharing Your Package (30 min)
GitHub:
# Initialize git
usethis::use_git()
# Connect to GitHub
usethis::use_github()Package Website:
# Create pkgdown site
usethis::use_pkgdown()
pkgdown::build_site()CRAN Preparation:
# Check package
devtools::check()
# Spell check
devtools::spell_check()
# Check for CRAN policies
rcmdcheck::rcmdcheck()Pharmaceutical Package Considerations
Validation Requirements
- π Documentation - Comprehensive function docs
- β Testing - High test coverage (aim for 80%+)
- π Version control - Track all changes
- π Change log - Document updates
- π·οΈ Releases - Tagged versions
Example Structure for Pharma Package
mypharmapackage/
βββ DESCRIPTION # Package metadata
βββ NAMESPACE # Auto-generated
βββ R/ # Function code
β βββ data_processing.R
β βββ statistical_tests.R
β βββ plotting.R
βββ tests/
β βββ testthat/ # Unit tests
βββ vignettes/ # Long-form documentation
βββ data/ # Example datasets
βββ inst/
β βββ validation/ # Validation documents
βββ README.md
Hands-On Exercise
Build a Clinical Trial Utility Package:
Create a package with functions for:
- Subject disposition summary
- Adverse event frequency table
- Demographic summary table
Include:
- Proper documentation
- Input validation
- Unit tests
- Examples
- README
Best Practices Summary
Doβs β
- Write clear, focused functions
- Document everything with roxygen2
- Test your functions thoroughly
- Use meaningful names
- Include examples
- Keep dependencies minimal
- Version control with git
Donβts β
- Donβt use
library()inside functions - Donβt modify userβs options/settings
- Donβt write to userβs file system without permission
- Donβt use non-standard evaluation carelessly
- Donβt skip documentation
Advanced Topics (Time Permitting)
- Vignettes - Long-form documentation
- Data in packages - Including example datasets
- Package dependencies - Managing imports
- S3 methods - Object-oriented programming
- GitHub Actions - Automated checks
Learning Outcomes
By the end of this workshop, you will be able to:
β
Create a basic R package structure
β
Write package-friendly functions
β
Document functions with roxygen2
β
Write unit tests with {testthat}
β
Share your package on GitHub
β
Understand best practices for package development
β
Have created your own R package!
Resources for Continued Learning
- R Packages book (2nd ed): r-pkgs.org
- usethis documentation: usethis.r-lib.org
- Writing R Extensions: Official CRAN manual
- Pharmaverse packages: Examples of pharma-specific packages
Next Steps
After this workshop:
- Practice by packaging your existing code
- Contribute to open-source pharma packages
- Explore {pkgdown} for beautiful websites
- Learn about continuous integration (GitHub Actions)
- Join the pharmaverse community!
Similar Workshops
- R Validation Discussion - Validation for packages
- datasetjson - Example of well-built package
Next Steps
- After building: Learn validation
- Career impact: Package Development skills
- Contribute: Join pharmaverse
Last updated: November 2025 | R/Pharma 2025 Conference