A reproducible meta-analysis examining the relationship between Repetitions in Reserve (RIR) (proximity to failure) and resistance training outcomes (strength and hypertrophy).
This project implements a multi-level meta-regression analysis to investigate whether training closer to muscular failure produces superior strength and hypertrophy adaptations compared to training with repetitions in reserve.
- Does training to failure (RIR = 0) produce greater strength gains than training with repetitions in reserve?
- Does training to failure produce greater muscle hypertrophy than training with repetitions in reserve?
- What is the dose-response relationship between RIR and training outcomes?
# Prerequisites: R 4.4.2+, Quarto, pre-commit
# 1. Clone and setup
git clone <repository-url>
cd deadlift-study
make setup
# 2. Run analysis pipeline
make pipeline
# 3. Generate reports
make reportsdeadlift-study/
├── R/ # Source code (R6 classes, box modules)
│ ├── __init__.R # Module exports
│ ├── domain/ # Business entities (DDD layer)
│ │ ├── study.R # Study entity
│ │ ├── treatment_group.R # TreatmentGroup entity
│ │ └── effect_size.R # EffectSize value object
│ ├── calculators/ # Service layer
│ │ └── effect_size_calculator.R # SMCR/ROMC calculators
│ ├── models/ # Meta-analysis models
│ ├── validators/ # Data validation (pointblank)
│ └── utils/ # Shared utilities
│ ├── config.R # Configuration management
│ ├── logging.R # Logging utilities
│ └── seed.R # Reproducibility helpers
├── config/ # YAML configuration
│ ├── default.yml # Base configuration
│ └── studies/ # Study-specific configs
│ ├── strength_rir.yml
│ └── hypertrophy_rir.yml
├── data/ # Data files (DVC tracked)
│ ├── raw/ # Original datasets
│ └── processed/ # Analysis-ready data (parquet)
├── analyses/ # Quarto analysis documents
│ └── index.qmd # Main analysis notebook
├── tests/ # Test suite
│ └── testthat/
│ ├── setup.R # Test fixtures
│ ├── test-treatment_group.R
│ └── test-effect_size_calculator.R
├── docs/ # Documentation
│ ├── 01_CURRENT_EXPERIMENT_PLAN.md
│ ├── 02_METHODOLOGICAL_IMPROVEMENTS.md
│ ├── 03_PROJECT_ARCHITECTURE_PLAN.md
│ └── 04_RUNBOOKS.md
├── reports/ # Generated reports
├── pelland/ # Legacy analysis scripts
├── _targets.R # Pipeline definition
├── _quarto.yml # Quarto configuration
├── Makefile # Automation commands
├── .pre-commit-config.yaml # Pre-commit hooks
└── .Renviron # Environment variables
The project follows Domain-Driven Design with R6 classes:
Domain Layer (R/domain/)
├── Study # Research study entity
│ ├── study_id, first_author, publication_year
│ ├── add_treatment_group() → chainable
│ └── validate() → {is_valid, errors}
├── TreatmentGroup # Experimental group within study
│ ├── group_id, rir, mean_pre, mean_post, sd_pre, n
│ ├── calculate_mean_change()
│ └── validate()
└── EffectSize # Calculated effect size (value object)
├── effect_estimate, sampling_variance
└── to_list()
Service Layer (R/calculators/)
├── SMCRCalculator # Standardized Mean Change (Raw)
│ ├── calculate(TreatmentGroup) → EffectSize
│ └── calculate_batch(list) → list<EffectSize>
└── ROMCCalculator # Response Ratio (log scale)
├── calculate(TreatmentGroup) → EffectSize
└── calculate_batch(list) → list<EffectSize>
Code is organized using box for Python-like explicit imports:
# In _targets.R
box::use(
R/utils/config[load_config, get_param],
R/domain/study[Study],
R/calculators/effect_size_calculator[SMCRCalculator]
)┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Stage 1: │────▶│ Stage 2: │────▶│ Stage 3: │
│ Configuration │ │ Data Loading │ │ Transformation │
│ │ │ │ │ │
│ config_file │ │ raw_data_file │ │ treatment_grps │
│ analysis_cfg │ │ raw_study_data │ │ effect_sizes │
│ random_seed │ │ │ │ meta_data │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
┌─────────────────┐ │
│ Stage 5: │◀────────────┘
│ Meta-Analysis │
│ │
│ (Models TBD) │
└─────────────────┘
│
┌─────────────────┐
│ Stage 6: │
│ Outputs │
│ │
│ processed_data │
│ pipeline_done │
└─────────────────┘
| Document | Description |
|---|---|
| 01_CURRENT_EXPERIMENT_PLAN.md | Original analysis methodology from Pelland script |
| 02_METHODOLOGICAL_IMPROVEMENTS.md | Proposed enhancements: Bayesian, causal, conformal |
| 03_PROJECT_ARCHITECTURE_PLAN.md | Technical architecture and design patterns |
| 04_RUNBOOKS.md | SOPs, troubleshooting, and workflows |
| Category | Tool | Purpose |
|---|---|---|
| Language | R 4.4.2 | Statistical computing |
| OOP | R6 | Object-oriented design with reference semantics |
| Modules | box | Python-like explicit imports |
| Pipeline | targets | Workflow orchestration with caching |
| Packages | renv | Dependency management and lockfile |
| Validation | pointblank | Data quality checks |
| Reports | Quarto | Reproducible documents |
| Formatting | Air | Fast Rust-based code formatting |
| Linting | lintr/Jarl | Code quality checks |
| Testing | testthat + hedgehog | Unit + property-based tests |
| Config | config | YAML-based environment configs |
| Logging | logger | Production-grade logging |
R_CONFIG_ACTIVE=default # Options: default, debug, quick, full
DEADLIFT_SEED=42 # Reproducibility seed
DEADLIFT_LOG_LEVEL=INFO # Logging: DEBUG, INFO, WARN, ERROR| Profile | Use Case |
|---|---|
default |
Standard analysis settings |
debug |
Verbose logging, minimal iterations |
quick |
Fast development iterations |
full |
Production: 8 chains, 10k iterations |
# Setup
make setup # First-time setup (renv + hooks)
make install-r # Install R packages only
make install-hooks # Install pre-commit hooks
# Pipeline
make pipeline # Run analysis pipeline
make pipeline-parallel # Run with 4 parallel workers
make pipeline-viz # Visualize pipeline DAG
make pipeline-status # Check target status
make pipeline-clean # Invalidate all targets
# Quality
make check # Format check + lint + test
make format # Format code (Air)
make lint # Lint code (lintr/Jarl)
make test # Run all tests
make test-coverage # Run with coverage report
make check-coverage # Verify 90%+ coverage
# Reports
make reports # Render all Quarto reports
# Data
make validate-data # Run pointblank validation
make dvc-pull # Pull data from DVC remote
make dvc-push # Push data to DVC remote
# Docker
make docker-build # Build Docker image
make docker-run # Run analysis in container
# Help
make help # Show all commandsThis project adheres to:
- SRP: Each R6 class has one actor (statistician, data manager, analyst)
- OCP: Calculators extensible via strategy pattern
- LSP: All TreatmentGroup subtypes substitutable
- ISP: Minimal public interfaces (
calculate,validate) - DIP: Services depend on abstractions (EffectSize), not implementations
- Composable: Small classes (<10 public methods) that combine
- Unix: Each class does one thing well
- Predictable: Pure functions, parameterized seeds, immutable configs
- Idiomatic: R6 conventions, Pydantic-style validation
- Domain-based: Business terms (Study, EffectSize) not implementation (DataFrame, List)
- Reproducibility: Parameterized random seeds (never global
set.seed()) - Numerical stability: Safe division, variance bounds checking
- Statistical correctness: Hedge's g correction, REML estimation
- Data leakage prevention: Separate fit/transform methods
- Coverage: 90% minimum (enforced via
make check-coverage) - Functions: <30 lines (Extract Method refactoring)
- Classes: <10 public methods (Extract Class refactoring)
- Testing: TDD with classicist approach (real objects, no mocks)
- Add data file to
data/raw/ - Create study config in
config/studies/:
# config/studies/my_study.yml
inherits: default
data:
primary_dataset: "my_study_data.xlsx"
models:
frequentist:
random_structure: "~1|study/group"- Set environment:
R_CONFIG_ACTIVE=my_study - Run:
make pipeline
See 04_RUNBOOKS.md for:
- Development workflow
- Pre-commit hook configuration
- Testing guidelines
- Code review checklist
[Add appropriate license]
If you use this analysis, please cite:
@misc{deadlift-study-2024,
title = {Proximity to Failure and Resistance Training Outcomes: A Meta-Analysis},
author = {[Authors]},
year = {2024},
url = {[Repository URL]}
}