연구 파이프라인
목표: 깨끗한 체크아웃과 원시 data/에서 bash pipeline/run_pipeline.sh를 실행하면 모든 처리된 데이터셋, 분석 결과, 보고서 및 원고 출력물이 재생성됩니다. 다운스트림에서 사용되는 출력물을 생성하는 모든 스크립트는 pipeline/ 아래의 어떤 스크립트에 의해 의존성 순서대로 호출됩니다.
레이아웃
pipeline/
_common.sh # 공유 헬퍼, 모든 run_*.sh에서 source됨 (직접 실행되지 않음)
run_pipeline.sh # 최상위 오케스트레이터: 단계 스크립트를 순서대로 호출
run_preprocessing.sh # 단계: src/prepro/*.R -> output/prepro/
run_analyses.sh # 단계: src/analysis/*.R -> output/analysis/
run_reports.sh # 단계: src/reports/*.qmd -> output/reports/
run_manuscript.sh # 단계: src/manuscript/* -> output/manuscript/
run_script.sh # 동일한 로깅으로 단일 .R / .qmd 실행
단계 이름은 프로젝트의 src/ 폴더를 따릅니다 (예: noh-survey는 src/manu/와 run_manu.sh를 사용). 존재하는 폴더에 대해서만 단계를 추가하고, 빈 단계는 만들지 마세요.
규칙
- 모든 스크립트에
#!/usr/bin/env bash와set -euo pipefail을 사용합니다. - 모든 스크립트에 헤더 주석을 작성합니다: 무엇을 하는지, 사용법 라인 (
bash pipeline/<name>.sh), 그리고 먼저 실행되어야 하는 단계 (Requires ...). _common.sh를 통해 스크립트가 프로젝트 루트로cd하므로, 어떤 디렉토리에서도 작동합니다. 모든 내부 경로는 프로젝트 루트를 기준으로 합니다.- 로깅:
run_pipeline.sh는PIPELINE_LOG_DIR=logs/run_pipeline_<timestamp>를 내보냅니다. 각 단계는${PIPELINE_LOG_DIR:-logs}/run_<stage>_<timestamp>/를 생성하므로, 파이프라인 실행 아래에 중첩되거나 단독 실행 시logs/아래에 저장됩니다. 각 R 스크립트/Quarto 문서는 자체<name>_<HH-MM-SS>.txt에 로그를 기록합니다. - 실패 시,
run_r/render_qmd는 실패한 스크립트, 로그 경로 및 로그의 마지막 20줄을 출력한 후 전체 파이프라인을 중지합니다. - 단계 내에서 의존성 깊이별로
echo "=== Layer N: <why> ==="헤더 아래에 호출을 그룹화합니다. 의존성이 명확하지 않은 호출에는 후행 주석을 추가합니다 (# needs output/prepro/redcap-joined.rds). 단계 간 의존성은 자체 레이블이 지정된 블록을 얻습니다 (예: PCA 결과가 필요한 전처리 스크립트는 PCA 이후 분석 단계에 위치). - 각 단계는 쓰기 작업을 수행하는 출력 디렉토리를
mkdir -p합니다. - Quarto는 소스 폴더에 렌더링되므로,
render_qmd는 결과를output/으로 이동합니다. 폴더의 모든 보고서가 동일한 방식으로 렌더링될 때for qmd in src/reports/*.qmd루프를 사용합니다 (템플릿 건너뛰기). - 느린 단계 앞에는
echo "NOTE: ... 시간이 오래 걸릴 수 있습니다"를 추가합니다. - 호출은 명시적으로 유지하고, 스크립트당 한 줄씩 작성합니다. R 스크립트를 glob으로 자동 발견하지 마세요: 순서는 의존성 그래프이며, 읽을 수 있어야 합니다.
템플릿
이 스킬의 templates/ 디렉토리에서 복사하여 채워 넣으세요:
| 템플릿 | 생성 파일 |
|---|---|
_common.sh | pipeline/_common.sh (있는 그대로 복사) |
run_pipeline.sh | pipeline/run_pipeline.sh |
run_stage.sh | 단계별로 하나의 pipeline/run_<stage>.sh |
run_script.sh | pipeline/run_script.sh (있는 그대로 복사) |
_common.sh는 다음을 제공합니다:
init_log_dir <stage-name>:LOG_DIR생성 및 설정run_r <script.R> [args...]: R 스크립트 실행, stdout+stderr를 로그로 (인수는 로그 이름에 추가됨, noh-survey의 그룹 루프와 같은 매개변수화된 실행용)run_r_console <script.R> <stdout-file>: stdout은 결과물로 저장 (예:output/manuscript/<name>-console.txt), stderr는 로그로render_qmd <doc.qmd> <dest-dir-or-file> [quarto args...]: 렌더링 후 출력 이동; 대상이 파일 경로인 경우 이름 변경 (예:-P group:...당 하나의 PDF)find_quarto: RStudio/Positron에 번들된 Quarto로 fallback
워크플로우
1. 프로젝트 조사
src/(그리고fns/,config/) 및 기존pipeline/을 나열합니다.pipeline/이 존재하면, 변경 전에 모든 스크립트를 읽고, 이 규칙과 다른 스타일이 있으면 유지합니다 (기존 파이프라인 마이그레이션 전에 물어보기).- 프로젝트의 CLAUDE.md / README에서 명시된 실행 순서를 읽습니다.
2. 의존성 순서 파악
src/의 모든 .R / .qmd에 대해, 읽는 파일과 쓰는 파일을 찾습니다:
grep -nE 'readRDS|read_rds|read_csv|read_excel|read\.csv|load\(|fread|readMat|source\(' <file>
grep -nE 'saveRDS|write_rds|write_csv|ggsave|save\(|writexl|write\.csv|pdf\(|png\(|tiff\(' <file>
각 읽기 작업을 해당 파일을 쓰는 스크립트와 연결합니다. 생산자가 없는 읽기는 data/의 원시 입력이어야 합니다. 그렇지 않은 경우, 플래그를 지정합니다 (누락된 파이프라인 단계이거나 수동으로 생성된 출력물입니다). 레이어를 할당합니다: Layer 0은 data/만 읽음; Layer N은 < N 레이어의 출력을 읽음. 명확하지 않은 경우, 스크립트를 작성하기 전에 결과 순서를 사용자에게 보여줍니다.
사용자가 달리 명시하지 않는 한 archive/, misc/, 템플릿 (*template*), 임시 스크립트는 건너뛰고, 건너뛴 항목을 나열합니다.
3. 스크립트 작성
템플릿을 복사하고, 단계와 레이어를 채운 다음, chmod +x pipeline/*.sh를 실행합니다.
4. 커버리지 및 구문 검사
bash <this-skill-dir>/scripts/check_coverage.sh <project-root>
이 명령은 모든 파이프라인 스크립트에 대해 bash -n 및 shellcheck (설치된 경우)를 실행한 후, 파이프라인 스크립트가 이름으로 언급하지 않은 src/ 파일을 나열합니다. glob 루프로 렌더링된 파일은 언급되지 않은 것으로 표시되므로, 수동으로 확인합니다. 나머지 모든 파일은 파이프라인에 추가되거나 의도적으로 제외되었음을 확인합니다.
5. 재현성 감사
src/를 grep하여 다음 항목을 보고합니다 (조용히 수정하지 않음):
setwd(또는 절대 경로 (/Users/,C:/,~/): 다른 시스템에서 작동하지 않음- 무작위성 (
sample(,rnorm(,boot,simr,set.seed없음)에set.seed()없음 - 대화형 전용 코드:
View(,file.choose(,readline(,browser( output/외부에 기록된 출력 (Quarto의 렌더링 후 이동 제외)rm(list = ls()): 스크립트가 단일 세션에서 실행될 때 누락된 의존성을 숨김
6. 실행
전체 파이프라인은 시간이 오래 걸리고 output/을 덮어쓸 수 있으므로, 실행 전에 물어보십시오. 먼저 단일 단계나 run_script.sh를 하나의 파일에 대해 실행하는 옵션을 제안합니다. 처음부터 재현성을 확인하려면 output/을 이동하고 (mv output output.bak, 삭제하지 않음), run_pipeline.sh를 실행한 후 비교합니다.
7. 문서화
프로젝트의 CLAUDE.md / README에 "파이프라인 실행" 섹션을 추가하거나 업데이트합니다: 단일 명령어, 각 단계의 역할, 단일 스크립트 실행 방법.
기존 파이프라인에 스크립트 추가하기
- 새 스크립트가 읽는 파일(2단계)을 찾아 어떤 단계와 레이어에 속하는지 결정합니다.
- 해당 위치에
run_r라인을 하나 추가하고, 명확하지 않은 경우 의존성 주석을 추가합니다. - 해당 출력이 이후 스크립트에 공급되는 경우, 해당 스크립트가 여전히 더 늦은 레이어에 있는지 확인합니다.
scripts/check_coverage.sh를 실행합니다.