Development Workflow
This guide covers the efficient development workflow for R package development.
The Fast Iteration Cycle
IMPORTANT: Follow this workflow to develop efficiently.
During Development (Fast Iteration Cycle)
Run these commands repeatedly while developing:
devtools::document()- Generate documentation from roxygen2 comments- Updates
man/directory - Updates
NAMESPACEwith exports and imports - Takes seconds to run
- Updates
devtools::load_all()- Load your package into memory- Equivalent to library(yourpackage) but uses development version
- Loads all functions, even unexported ones
- Takes seconds to run
devtools::test()- Run all tests- Runs testthat test suite
- Takes seconds to minutes depending on test count
- For single file:
devtools::test_active_file('R/yourfile.R')
This cycle is fast (seconds) and gives you immediate feedback.
Why This Works
# Typical workflow:
devtools::document() # Update docs and namespace
devtools::load_all() # Load updated code
devtools::test() # Verify it works
# Test your function interactively
your_function(test_data)
# Find issue, fix code, repeatThis tight feedback loop lets you: - Catch errors immediately - Test interactively - Iterate quickly on design
Final Validation (Run Once at End)
devtools::check()- Full R CMD check
WARNING: Do NOT run check() during iteration.
Why avoid check() during development?
- Takes 1-2 minutes (sometimes longer)
- Runs many validations unnecessary during development
- Interrupts your flow
- Everything it checks is validated by the fast cycle
When to run check()
Only run check() once at the very end: - Before submitting to CRAN - Before creating a release - Before final code review - After all development is complete
check() validates: - Package structure - Documentation completeness - Code quality - Examples run correctly - Tests pass - No NOTEs or WARNINGs
Interactive Development
Testing individual functions
# Load your package
devtools::load_all()
# Test your function
result <- your_function(mtcars, mpg, hp)
result
# Check intermediate values
debug(your_function)
your_function(mtcars, mpg, hp)Using browser() for debugging
your_function <- function(data, ...) {
# Add browser() where you want to pause
browser()
# Rest of function
}
# Run function - it will pause at browser()
your_function(test_data)Common Workflow Patterns
Pattern 1: New Function Development
# 1. Write function in R/your-file.R
# 2. Add roxygen documentation
# 3. Document and load
devtools::document()
devtools::load_all()
# 4. Test interactively
your_function(test_data)
# 5. Write formal tests in tests/testthat/test-your-file.R
# 6. Run tests
devtools::test()
# 7. Fix issues, go to step 3Pattern 2: Fixing a Bug
# 1. Write a failing test that demonstrates the bug
# 2. Run tests to confirm failure
devtools::test()
# 3. Fix the code
# 4. Document and load
devtools::document()
devtools::load_all()
# 5. Verify test now passes
devtools::test()Pattern 3: Updating Documentation
# 1. Update roxygen comments in R code
# 2. Regenerate documentation
devtools::document()
# 3. Preview documentation
?your_function
# 4. Repeat until satisfiedKeyboard Shortcuts (RStudio)
Speed up your workflow with keyboard shortcuts:
Cmd/Ctrl + Shift + D-devtools::document()Cmd/Ctrl + Shift + L-devtools::load_all()Cmd/Ctrl + Shift + T-devtools::test()Cmd/Ctrl + Shift + E-devtools::check()
Best Practices
DO:
- Run the fast cycle (document, load, test) frequently
- Test interactively in console
- Write tests as you develop
- Fix issues immediately when found
- Use
browser()for complex debugging
DON’T:
- Run
check()during development (only at end) - Skip writing tests “for later” (write them now)
- Ignore warnings from
document()ortest() - Make many changes before testing
- Commit broken code to git
Troubleshooting
“could not find function”
Problem: Function exists in R code but not loaded
Solution: Run devtools::load_all()
“object not found in namespace”
Problem: Missing @export in roxygen or namespace not updated
Solution:
# Add @export to your roxygen block
devtools::document() # Update namespace
devtools::load_all() # Load updated packageTests fail but function works interactively
Problem: Test environment differs from interactive environment
Solution: - Check test data setup - Verify all required packages loaded in tests - Use devtools::load_all() before interactive testing
“no visible binding for global variable”
Problem: Using NSE without proper imports
Solution: See package-imports.md for proper namespace usage
Performance Tips
Speed up test runs
# Run only one test file
devtools::test_active_file()
# Run only tests matching a pattern
devtools::test(filter = "your_function")Skip slow tests during development
test_that("slow integration test", {
skip_if_not(interactive(), "Slow test - run manually")
# Expensive test here
})Use testthat snapshots for complex output
test_that("complex output matches", {
expect_snapshot(your_function(data))
})Git Workflow (Source Development)
If you’re contributing to tidymodels packages (recipes, yardstick, etc.), you’ll also need basic git workflow.
Initial Setup
# Clone the repository
git clone https://github.com/tidymodels/recipes.git
cd recipes
# Create a feature branch
git checkout -b feature/add-step-nameDuring Development
# Your fast iteration cycle (unchanged)
devtools::document()
devtools::load_all()
devtools::test()Committing Changes
# Check what changed
git status
git diff
# Add your changes
git add R/step_name.R tests/testthat/test-step_name.R
# Commit with descriptive message
git commit -m "Add step_name() for [brief description]"
# Push to your fork
git push origin feature/add-step-nameBefore Submitting PR
- Run full check:
devtools::check() - Update
NEWS.mdwith your changes - Ensure all tests pass
- Push final commits
Common Git Commands
# See current branch
git branch
# Switch branches
git checkout main
# Update from upstream
git pull origin main
# View commit history
git log --onelineNote: This is a minimal git guide. For complete git documentation, see the official Git documentation or GitHub guides.
Next Steps
- Learn testing patterns: package-extension-requirements.md#testing-requirements
- Set up proper documentation: package-roxygen-documentation.md
- Follow best practices: package-extension-requirements.md#best-practices