[1] "Hello World"
Setting up a research project you (and others) can rerun
February 1, 2027
renv to record which package versions a project usesBy the end of class, you will have a project skeleton on GitHub that is set up the way every project in this course will be.
You can write code in any text editor, then run it from the command line:
Then read the output, go back, make some edits, and repeat.
This works, but it is a slow and painful way to write code.
An IDE combines
Usually with some extras:
Examples: RStudio (R), Spyder (Python), Xcode (Apple apps), and Visual Studio Code (most languages)
This is a good question. Most R users use RStudio.
VS Code has…
It is free, lightweight, and customizable through extensions.
The icons down the left side switch between views.

Every screenshot from this tour, step by step, is in the VS Code Setup guide.
Search finds text across every file in the project.
clean_wages?”Source Control is a point-and-click interface to Git.

Every command in VS Code (and its extensions) in one search box.
Start typing and pick the command, for example:
Terminal: Create New TerminalR: Create R TerminalYou can almost always click your way to a command instead, but “run X in the Command Palette” is much easier to write in directions than “click A, then B, then C”.
The terminal pane at the bottom can hold several terminals at once.
ls, git, Rscript

Extensions add support for languages and tools.
Settings (the gear, or ⌘+, on Mac / ctrl+, on Windows)
When you open a folder in VS Code, it becomes a workspace. Workspaces…
.vscode/ folder)Always open the project folder itself, not a single file and not its parent folder. Code in this course assumes R starts in the project’s root folder.
If you are coming from RStudio, workspaces are similar to R projects (.Rproj files).
VS Code gives us both (1) an editor and (2) a terminal, in one window, for one project folder.
A basic text file has the extension “.txt”
This tells the computer that this file just has “plain” text
Here is some plain text.
We could put this in a file with a ".txt" extension
Most code files also just store plain text: “.R”, “.py”, “.jl”, “.do”, “.m”
You generally should not do this. You can break things.
But what if we change the file extension of a “.pdf” to a “.txt”?
Then we can open it in a text editor and see…
%PDF-1.5
%–‘≈ÿ
10 0 obj
<< /S /GoTo /D [11 0 R /Fit] >>
endobj
71 0 obj
<<
/Length 1322
/Filter /FlateDecode
>>
stream
x⁄ÌZKo9æ˚WË¥∞Vı~Ï≠§≈ÿn„‰VÏ!;yç̃I∞Ëø_R3í∆c'éùÿuà5¢HJ$?r§ôa‰ä0Ú©«:-áñCF§‘IMÑîCʉ≤wº$¥qK©ˇ-ô_ëvwÙ≥¥F√óµGöÁj≈î ¢≥8RRȰ‘*G™IÔéÙñÿ…
File extensions tell the computer (and other people) what format the data in a file uses.
Some formats, like PDFs and PNGs, are very far from plain text.
Others, like code files, are plain text. The extension just says which syntax highlighting to use and which software should run it.
Plain text files are what Git tracks best: it can show you exactly which lines changed.
Markdown is an “easy-to-read” and “easy-to-write” language for formatting plain text.
It is like LaTeX, but with an emphasis on code that is easy to read as-is.
You’ll see this extension on GitHub’s README documents: “README.md”
GitHub also renders Markdown in Issues and Pull Requests. Today, we will write a README for a research project.
Your code will be read and rerun by…
A good structure means someone can clone your repository and reproduce every table and figure without emailing you.
main.R runs everything, in order.The rest of this section shows what each of these looks like.
my-project/
my-project/
├── README.md # what this is and how to run it
├── main.R # runs the whole project, in order
├── code/
│ ├── 01-download-data.R
│ ├── 02-clean-data.R
│ ├── 03-estimate-models.R
│ └── 04-make-figures.R
├── data/
│ ├── raw/ # exactly as downloaded; never edited
│ └── derived/ # created by code in code/
├── output/
│ ├── figures/
│ └── tables/
├── .gitignore
├── .env.example # names of the secrets the project needs
└── renv.lock # package versions (more on this later)There is no single correct layout. What matters is that it is consistent and obvious to a stranger.
Data in data/raw/ stays exactly as you got it.
02-clean-data.R reads from data/raw/ and writes to data/derived/Then:
data/derived/ or output/ can be deleted and rebuiltA good test: delete data/derived/ and output/, run main.R, and check that you get everything back.
main.Rmain.R runs the whole project, in order.
main.R
source() runs another R file, top to bottommain.R like thisGood file names are easy to sort, read, and type.
Do
01-download-data.Rfig-unemployment-rate.png2027-02-01-meeting-notes.mdAvoid
Final Code (2).Ranalysis_v3_NEW_bc.Rfig1.pngYYYY-MM-DD sort in time order_v2, _final, or _final_finalAn absolute path only exists on one computer.
A relative path starts from the project root, wherever the project lives.
setwd() in project codeRscript main.R from the project root, tooREADME.md is the first thing anyone sees on GitHub. It should answer:
renv::restore()).env.example to .env)Rscript main.R, and roughly how long it takesREADME.md
# Unemployment and Job Openings
Estimates a Beveridge curve for the US using BLS JOLTS data, 2001-2026.
## Setup
1. Install R (4.6 or later).
2. In R, from the project root, run `renv::restore()`.
3. Copy `.env.example` to `.env` and add a FRED API key.
## Running
From the project root, run `Rscript main.R` (about 2 minutes).
Figures are saved to `output/figures/`, tables to `output/tables/`.
## Data
- `data/raw/jolts.csv`: BLS JOLTS, downloaded 2027-02-01 from <https://www.bls.gov/jlt/>
- Unemployment rate: downloaded from FRED by `code/01-download-data.R`Recall .gitignore from Lecture 1.
Track
main.RREADME.md.gitignore, .env.examplerenv.lock, .Rprofile, renv/activate.RIgnore
.env (secrets)renv/library/ (renv ignores it for you).Rhistory, .RDataIf you ignore a dataset, the README must say where to get it.
.gitignore.gitignore
Git does not track empty folders. To keep an empty folder in the repository, put an empty file named .gitkeep in it. The ! lines above are exceptions: ignore everything in the folder except .gitkeep.
Many data sources (FRED, the Census, WRDS) give you a key or a password.
Never put them in your code:
If you ever commit a key, treat it as leaked: revoke it on the provider’s website and get a new one.
.env and .env.exampleKeep secrets in a file called .env in the project root, and ignore it with .gitignore.
Commit a template, .env.example, with the names but no values.
A collaborator copies .env.example to .env and fills in their own keys.
readRenviron(".env") reads the file into R’s environment variablesfredr) look up their key automatically, so you never type itSys.getenv("NAME")Files starting with “.” are hidden in Finder and File Explorer, but VS Code’s Explorer shows them.
A package is a set of functions written outside your project (usually by someone else).
You will install and use your first packages next week. Today is about how projects keep track of them.
Packages are managed by someone else, and sometimes they update them.
If your code relies on v0.9 of some_function(), which always returned a boolean,
and now v1.0 returns an integer,
all of your code using some_function() just broke.
dplyr has a function called filter() which is used to filter rows from a data.frame.
Originally, filter_() was an option for standard evaluation, which allowed you to use strings instead of unquoted variable names.
In dplyr v1.0.0, filter_() was removed (and replaced by other methods of standard evaluation).
This change broke any code that used filter_(), unless its authors had recorded which version of dplyr they used.
filter_() was first deprecated in v0.7.0: marked for removal, with a warning, but still working. This is a common practice to give users time to update their code.
By default, R has one library of packages shared by all projects.
install.packages() puts packages in the library; library() loads them into a session.
There are actually two libraries:
“User” Library
“System” Library
There are two problems with R’s default package setup.
These are related, and renv (“R environments”) solves both.
renv Separates Project Librariesrenv gives each project its own isolated library.
Updating a package in Project 2 cannot break Project 1.
renv CacheTo avoid downloading and storing the same package many times, renv keeps a cache of every package version it has installed, and links each project library to it.
renvYou installed renv in Assignment 1. To start using it in a project, run this once, in an R terminal opened in the project root:
At first, the only package tracked is renv itself, along with your version of R.
Restart the R session; you should see a message from renv when it starts.
renv Filesrenv::init() creates:
renv.lock: the lockfile, listing each package and its version (commit it).Rprofile: activates renv whenever R starts in this folder (commit it)renv/activate.R, renv/settings.json: renv’s own setup (commit them)renv/library/: the project library itself (not committed; renv adds its own .gitignore)The lockfile is the only piece needed to recreate your packages, which is good, because the library can be large.
jsonlite, rlangAfter restarting, you may get a warning:
VSCode R Session Watcher requires jsonlite, rlang. Please install manually in order to use VSCode-R.
Why?
renv created an isolated library for the project.
The only package R can see is renv itself!
The packages you installed when setting up VS Code still exist on your computer, but this project cannot see them.
renv IssueInstall the packages VS Code needs into the project library:
If you have installed them with renv before, you will see “linked from cache”: no new download needed.
These are development tools: your code does not call them, so they will not be added to the lockfile. That is what we want.
renv::snapshot()The lockfile records the packages your code uses, not everything in the project library.
renv searches your project’s R files for packages (library(x), x::f()) and records their current versions in renv.lock.
renv::status()Everything consistent:

A package is used but not recorded:

When status() complains, run renv::snapshot(), then commit the new renv.lock.
renv::restore()On a new computer, or after cloning someone’s project:
This installs the exact package versions listed in renv.lock.
renv Summary
code/, data/raw/, data/derived/, output/README.md that explains how to run it.gitignore that keeps out .env and anything large or private.env.example listing the keys it needsrenv, with an up-to-date renv.lockmain.R that runs everythingThe final project requires all of these.
project-skeleton, with a README and the “R” .gitignore template. Clone it and open the folder in VS Code.code/, data/raw/, data/derived/, output/figures/, output/tables/1main.R with a comment saying what it will do, and one source() line for a script code/01-hello.R that prints a messageREADME.md with sections: what the project does, setup, how to run it, data.env.example with the line FRED_API_KEY=, and a .env with a fake key.env to the .gitignore (the R template already ignores .Rhistory and .RData)renv::init(), restart R, and fix the VS Code packagesRscript main.R.env is not listed. Stage, commit, and push..env is not theremain.R runs everything; relative paths from the project root.env (ignored), documented in .env.examplerenv records package versions: init, snapshot, status, restore.gitignore, .env.example, renv, and main.R