콘텐츠 대표 이미지 - R 패키지 개발, 너도 할 수 있어! 🚀 나만의 코드를 작품으로 만드는 여정

R 패키지 개발, 너도 할 수 있어! 🚀 나만의 코드를 작품으로 만드는 여정

스크립트 파일의 굴레에서 벗어나, 재사용과 공유가 가능한 나만의 R 패키지를 만들어봐요.
이 가이드 하나면, 당신도 오늘부터 R 패키지 개발자!

들어가며: 왜 우리는 R 패키지를 만들어야 할까? 🤔

안녕! R 좀 만져봤다 하는 우리 동지들. 아마 다들 비슷한 경험이 있을 거야. 어제 짰던 그 코드, 오늘 다시 쓰려니 어디에 저장했는지 가물가물...
분석 프로젝트마다 복사-붙여넣기 하던 `my_awesome_function.R` 파일이 수십 개가 되어버린 경험 말이야. 😱

이런 '코드 유목민' 생활, 이제 청산할 때가 됐어. 바로 R 패키지 개발을 통해서 말이지. "패키지 개발? 그거 완전 전문가들이나 하는 거 아냐?" 라고 생각했다면, 그 생각 잠시 접어둬도 좋아. 이 글은 바로 그런 당신을 위해 탄생했으니까.

R 패키지는 단순히 코드 덩어리를 예쁘게 포장하는 게 아니야. 이건 내 코드를 '작품'으로 만드는 과정이자, 미래의 나 자신과 동료들을 위한 최고의 선물이라고 할 수 있지.

R 패키지 개발, 이런 점이 좋아요!
  • 코드 재사용성 극대화: 언제 어디서든 `library(myPackage)` 한 줄이면 끝! 더 이상 `source()` 함수를 찾아 헤맬 필요가 없어.
  • 체계적인 관리: 함수, 데이터, 문서, 테스트 코드가 각자의 집에 깔끔하게 정리돼. 코드의 구조가 한눈에 들어오지.
  • 쉬운 공유와 협업: GitHub에 올리면 전 세계 누구나 당신의 코드를 쓸 수 있어. 협업이 훨씬 수월해지는 건 물론이고.
  • 품질 보증: 문서화와 테스트를 강제(?)하는 구조 덕분에 코드의 신뢰도가 수직 상승해. 버그 잡기도 훨씬 쉬워지지.
  • 성장의 발판: 패키지를 만들다 보면 R에 대한 이해도가 정말 깊어져. 진정한 R 고수로 가는 지름길이랄까?

이 가이드는 R 좀 다뤄봤지만 패키지 개발은 막막했던 당신을 위해, 친구가 옆에서 알려주듯 친절하고 재미있게 모든 과정을 안내할 거야. RStudio와 몇 가지 마법 같은 도구들만 있으면 충분해. 우리 함께 스크립트 파일에 불과했던 코드 조각들에 생명을 불어넣고, 멋진 R 패키지로 탄생시키는 여정을 떠나보자! 준비됐어? 😉

Part 1: 장비부터 챙기자! 🛠️ 개발 환경 세팅 A to Z

자, 위대한 여정을 떠나기 전엔 장비 점검이 필수지! R 패키지 개발도 마찬가지야. 다행히도 우리에게 필요한 장비는 아주 간단해. 바로 R과 RStudio, 그리고 우리의 개발 과정을 멱살 잡고 캐리해 줄 두 명의 슈퍼스타, `devtools`와 `usethis` 패키지야.

필수 준비물: R과 RStudio

이 글을 보고 있다면 R과 RStudio는 이미 설치되어 있겠지? 혹시라도 아직이라면, 지금 바로 설치하고 와줘. R은 우리 모험의 기반이 되는 땅이고, RStudio는 그 위에서 우리가 마음껏 뛰어놀 수 있게 해주는 최첨단 베이스캠프니까.

  • R: The Comprehensive R Archive Network (CRAN) 공식 홈페이지에서 최신 버전을 설치해줘.
  • RStudio: RStudio Desktop (Open Source License) 버전을 다운로드하면 돼. 무료인데 기능은 차고 넘쳐.

최신 버전으로 유지하는 거, 잊지 마! 개발의 세계에서는 '최신'이 곧 '안정'일 때가 많거든.

우리의 치트키: devtools와 usethis 패키지 🦸‍♂️

과거의 R 패키지 개발은 꽤나 고되고 번거로운 작업이었어. 수많은 명령어와 파일 구조를 일일이 외우고 수동으로 만들어야 했지. 하지만 이제 우리에겐 '해들리 위컴'이라는 신이 내려준 두 개의 선물이 있어. 바로 `devtools`와 `usethis`야.

  • `devtools` (Development Tools): 이름 그대로 개발에 필요한 모든 도구를 담고 있는 만능 공구함이야. 패키지를 설치하고, 테스트하고, 문서화하고, 체크하는 모든 과정을 이 친구가 도와줘.
  • `usethis` (Use This): `devtools`의 절친이자 비서 같은 역할을 해. "이것 좀 만들어줘" 하고 말하면 뚝딱하고 파일이나 코드 구조를 생성해주는 마법사지. 예를 들어, "테스트 파일 만들어줘!" 하면 `usethis::use_test("my_test")` 한 줄이면 끝!

이 둘만 있으면 우리는 개발의 본질, 즉 '좋은 코드를 짜는 것'에만 집중할 수 있어. 자, 그럼 우리의 치트키를 장착해볼까?

RStudio의 콘솔 창에 아래 코드를 입력하고 실행해줘.

install.packages(c("devtools", "usethis"))

설치가 완료되면, 이제 우리는 패키지 개발을 위한 최강의 무기를 손에 넣은 거야. 앞으로 이 두 패키지의 함수들을 정말 지겹도록 사용하게 될 테니, `library(devtools)`와 `library(usethis)`는 마음속에 항상 새겨두자고.

미래를 위한 보험: Git과 GitHub 연동 💾

"버전 관리? 그거 꼭 해야 해?" 응, 꼭 해야 해. 아니, 무조건 해야 해. Git은 우리 코드의 모든 변경 사항을 기록해주는 타임머신이야. 어젯밤에 멀쩡히 돌아가던 코드가 오늘 갑자기 안 될 때, Git이 있다면 "어제 저녁 7시로 돌아가자!" 하고 외칠 수 있지. 마법 같지 않아?

GitHub는 이런 Git 저장소를 온라인에 올려두고 다른 사람들과 공유하고 협업할 수 있게 해주는 웹사이트야. 우리가 만든 패키지를 세상에 선보이는 가장 쉽고 빠른 방법이기도 해.

잠깐! Git이 처음이라면?

Git을 처음 설치하고 설정하는 과정은 이 가이드의 범위를 조금 벗어나. 하지만 걱정 마! 인터넷에 좋은 자료가 정말 많아. 'Git 설치하기', 'RStudio Git 연동' 같은 키워드로 검색하면 스크린샷까지 포함된 친절한 가이드들을 쉽게 찾을 수 있을 거야. 딱 30분만 투자해서 기본 설정을 끝내고 오자. 미래의 내가 고마워할 거야!

RStudio에서 Git과 GitHub를 연동하는 건 아주 간단해.

  1. Git 설치 확인: RStudio의 `Tools > Global Options > Git/SVN` 메뉴로 들어가 봐. 'Git executable' 경로가 잘 잡혀있다면 성공! 아니라면 Git을 설치하고 경로를 지정해줘야 해.
  2. GitHub 개인 접근 토큰(PAT) 발급: 예전에는 아이디/비밀번호로 됐지만, 이제는 보안을 위해 토큰을 써. GitHub 웹사이트의 `Settings > Developer settings > Personal access tokens`에서 발급받을 수 있어.
  3. R에 토큰 등록: `usethis`가 이 과정도 도와줘. 콘솔에 `usethis::create_github_token()`을 실행하면 토큰 발급 페이지로 바로 이동하고, 발급받은 토큰을 `gitcreds::gitcreds_set()` 함수를 이용해 RStudio에 저장하면 끝!
# GitHub 토큰 발급 페이지로 이동 (웹브라우저가 열림)
usethis::create_github_token()

# 발급받은 토큰을 RStudio에 저장 (붙여넣기하라는 창이 뜰 거야)
# 예: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
gitcreds::gitcreds_set()

이 과정이 조금 번거롭게 느껴질 수 있지만, 딱 한 번만 해두면 앞으로의 패키지 개발과 공유가 정말 편해져. 이제 모든 장비 점검이 끝났어. 드디어 우리만의 패키지를 만들러 가볼 시간이야! 🚀

Part 2: 내 코드에 집을 지어주자! 🏡 R 패키지의 기본 구조

자, 이제 본격적으로 우리 코드에게 안락한 집을 지어줄 시간이야. R 패키지는 그냥 R 스크립트 파일을 폴더에 모아둔 게 아니야. 정해진 규칙에 따라 파일을 배치해야 하는, 잘 설계된 '건축물'과 같아. 하지만 걱정할 필요 없어. 우리에겐 건축가 `usethis`가 있으니까!

첫 삽 뜨기: `create_package()`로 프로젝트 시작

패키지를 만들고 싶은 경로로 이동해서, RStudio 콘솔에 마법의 주문을 외워보자. 나는 `myFirstPackage`라는 이름의 패키지를 만들어 볼게. 이름은 네 마음대로 정해도 좋아. 단, 영어로, 띄어쓰기 없이!

# 원하는 경로를 입력하거나, RStudio의 Files 탭에서 경로를 설정한 뒤 실행해줘.
usethis::create_package("myFirstPackage")

이 명령어를 실행하면 어떤 일이 일어날까?

  1. `myFirstPackage`라는 이름의 새 폴더가 생겨.
  2. 그 폴더 안에 패키지에 필요한 최소한의 파일과 폴더 구조가 자동으로 짠! 하고 만들어져.
  3. 새로운 RStudio 세션이 열리면서, 방금 만든 패키지 프로젝트가 로드될 거야.

이게 바로 `usethis`의 위대함이야. 우리는 복잡한 구조를 외울 필요 없이, 단 한 줄의 코드로 패키지 개발의 첫발을 내디딘 거지. 이제 우리 앞에 펼쳐진 파일과 폴더들이 각각 어떤 역할을 하는지 탐험해볼 시간이야.

R 패키지의 기본 구조 🏛️ myFirstPackage/ R/ 함수 코드 패키지의 심장 ❤️ man/ 도움말 파일 자동 생성됨 🤖 DESCRIPTION 패키지 신분증 🆔 가장 중요! NAMESPACE 출입 관리소 🚪 자동 생성됨 🤖 .Rproj RStudio 프로젝트 더블클릭! 이 외에도 `tests/`, `vignettes/`, `data/` 등필요에 따라 다양한 폴더들이 추가될 수 있습니다.

패키지의 심장: `R/` 폴더

이름 그대로, 우리가 작성하는 모든 R 함수 코드는 바로 이 `R/` 폴더 안에 `.R` 파일 형태로 저장돼. 패키지의 핵심 로직과 기능이 모두 여기에 담기는 거지. 지금은 비어있지만, 곧 우리의 멋진 함수들로 가득 채워질 공간이야. 보통 함수 하나당 하나의 `.R` 파일을 만들거나, 관련된 함수끼리 묶어서 하나의 파일로 만들기도 해.

패키지의 신분증: `DESCRIPTION` 파일 🆔

이 파일은 말 그대로 우리 패키지의 '신분증'이야. 패키지 이름이 뭔지, 누가 만들었는지, 버전은 몇인지, 어떤 다른 패키지를 필요로 하는지 등 패키지에 대한 모든 메타 정보가 담겨있어. `create_package()`를 실행하면 기본 템플릿이 만들어지는데, 이걸 우리 패키지에 맞게 수정해줘야 해.

파일을 열어보면 이런 내용이 보일 거야.

Package: myFirstPackage
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: 
    person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
    license
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.2.3
하나하나 뜯어보자! `DESCRIPTION` 파일 완전 정복
  • Package: 패키지 이름. `create_package()` 할 때 정한 이름이 들어가.
  • Title: 패키지의 역할을 한 줄로 요약하는 제목. 영문 Title Case(각 단어 첫 글자를 대문자로)로 쓰는 게 관례야. 예: `A Tidyverse-Style Package for Awesome Analysis`.
  • Version: 패키지 버전. `devtools`는 보통 `x.y.z.9000` 형식을 추천해. 마지막 9000은 개발 버전이라는 뜻! 정식 릴리즈할 때 `1.0.0` 처럼 바꿔주면 돼.
  • Authors@R: 패키지 제작자 정보. `person()` 함수를 이용해 이름, 이메일, 역할을 지정해. `aut`는 저자(author), `cre`는 관리자(creator)를 의미해. 보통 둘 다 지정하지.
  • Description: Title보다 좀 더 상세하게 패키지를 설명하는 문단. 이 패키지가 왜 필요하고, 어떤 문제를 해결하는지 등을 적어주면 좋아.
  • License: 이 패키지를 다른 사람이 어떤 조건 하에 사용할 수 있는지를 명시하는 라이선스. 코드를 공개할 거라면 반드시 지정해야 해! `usethis`를 쓰면 아주 쉬워. 예를 들어 MIT 라이선스를 적용하고 싶다면 콘솔에 `usethis::use_mit_license()` 라고 치기만 하면 돼.
  • Encoding: 인코딩 방식. 한글 주석 등을 사용하려면 `UTF-8`은 필수!
  • LazyData: 패키지에 포함된 데이터를 어떻게 로드할지에 대한 설정. `true`로 두면 `library()` 할 때 데이터가 메모리에 바로 올라오지 않고, 실제 사용할 때 로드돼서 효율적이야.
  • Imports / Suggests: (지금은 없지만 곧 추가될) 이 패키지가 의존하는 다른 패키지 목록. `Imports`는 패키지 작동에 필수적인 것, `Suggests`는 비네트나 예제 코드 등 부가 기능에만 필요한 것들을 적어. 이 부분은 나중에 `usethis`가 자동으로 관리해줄 거야!

지금 바로 `DESCRIPTION` 파일을 열어서 Title, Authors@R, Description 부분을 채워보자. 라이선스도 `usethis::use_mit_license("Your Name")` 같은 명령어로 정해주고!

출입 관리소: `NAMESPACE` 파일 🚪

이 파일은 우리 패키지의 '출입 관리소' 역할을 해. 조금 복잡하게 들릴 수 있지만, 딱 두 가지만 기억하면 돼.

  1. 외부로 내보낼 함수(수출): 우리 패키지에 함수가 100개 있더라도, 사용자가 직접 쓸 수 있는 함수는 몇 개 안 될 수 있어. 이처럼 외부(사용자)에 공개할 함수들을 `export(my_awesome_function)` 와 같은 형태로 등록하는 곳이야.
  2. 외부에서 가져올 함수(수입): 우리 패키지가 다른 패키지(예: `dplyr`)의 함수(예: `filter()`)를 사용한다면, 그 사실을 `importFrom(dplyr, filter)` 와 같이 명시해줘야 해.

"이거 너무 복잡한데? 내가 직접 다 써야 해?"
천만에! 이 `NAMESPACE` 파일은 절대, 절대, 절대로 우리가 직접 수정하지 않아. 앞으로 배울 `roxygen2`라는 문서화 도구가 우리 코드에 있는 특별한 주석을 읽어서 자동으로 이 파일을 생성하고 관리해줄 거야. 우리는 그냥 "아, 이런 게 있구나" 하고 개념만 이해하고 넘어가면 돼. 완전 편하지? 😉

기타 파일들: `.Rproj`, `.Rbuildignore`, `man/`

  • `myFirstPackage.Rproj`: RStudio 프로젝트 파일이야. 이 파일을 더블클릭하면 RStudio가 이 패키지 개발에 최적화된 상태로 열려. 작업 경로도 자동으로 설정되고 아주 편해.
  • `.Rbuildignore`: 패키지를 빌드(설치 가능한 파일로 만드는 과정)할 때 포함시키지 않을 파일이나 폴더 목록을 적는 곳이야. 예를 들어, 개인적인 메모나 임시 파일들을 여기에 등록하면 최종 패키지에는 포함되지 않아.
  • `man/`: 'manual'의 약자야. 함수 하나하나에 대한 상세한 도움말 파일(`.Rd` 확장자)이 저장되는 폴더야. `?mean` 처럼 우리가 R에서 도움말을 볼 때 나타나는 내용이 바로 이 폴더 안의 파일들이지. 이 폴더 역시 `roxygen2`가 자동으로 만들어주기 때문에 직접 건드릴 일은 없어.

어때? 처음엔 낯설어 보였던 파일과 폴더들이 이제 각자 어떤 역할을 하는지 조금 감이 오지? `usethis`가 뼈대를 만들어줬으니, 이제 우리는 가장 중요한 `R/` 폴더에 살을 붙이고, `roxygen2`로 멋지게 꾸며줄 일만 남았어. 다음 파트에서 본격적으로 함수를 만들고 문서화하는 방법을 알아보자!

Part 3: 코드는 거들 뿐, 진짜는 문서화! ✍️ roxygen2로 전문가처럼

자, 드디어 패키지의 심장인 `R/` 폴더를 채워볼 시간이야. 하지만 그냥 함수만 뚝딱 만들고 끝내면 '나만 아는 코드'가 될 뿐이야. 좋은 패키지는 '누가 봐도 이해하기 쉬운 코드'를 지향해야 해. 그리고 그 핵심에는 바로 문서화(Documentation)가 있어.

여기서 우리의 두 번째 영웅, `roxygen2` 패키지가 등판해. `roxygen2`는 코드 바로 위에 특별한 형식의 주석을 다는 것만으로, 앞서 봤던 `man/` 폴더의 도움말 파일(`.Rd`)과 `NAMESPACE` 파일을 자동으로 생성해주는 마법 같은 도구야.

첫 함수 만들기: `add_two_numbers`

백문이 불여일견! `R/` 폴더에 간단한 함수를 하나 만들어보자. `usethis`를 사용하면 함수 파일 생성도 아주 쉬워.

콘솔에 이렇게 입력해봐.

usethis::use_r("add_two_numbers")

이 명령은 `R/` 폴더 안에 `add_two_numbers.R`이라는 파일을 만들고, 그 파일을 바로 열어줘. 정말 친절하지? 이제 열린 파일에 간단한 덧셈 함수를 작성해보자.

add_two_numbers <- function(x, y) {
  x + y
}

좋아, 함수는 완성됐어. 하지만 이 상태로는 아무것도 할 수 없어. 이 함수를 패키지 사용자가 쓸 수 있게 외부에 공개하고, 도움말도 만들어줘야 해. 바로 여기서 `roxygen2` 주석이 등장할 차례야.

roxygen2 주석: 코드에 날개를 달아주자

`roxygen2` 주석은 일반 주석(`#`)과 달리, `#'` 로 시작해. 이 특별한 주석 안에 `@` 기호와 함께 특정 '태그'를 사용해서 함수의 정보를 알려주는 거야.

방금 만든 `add_two_numbers` 함수 위에 아래와 같이 주석을 추가해보자. RStudio에서는 함수 안에 커서를 두고 `Ctrl + Alt + Shift + R` 단축키를 누르면 주석 템플릿을 자동으로 만들어줘서 더 편해!

#' Add Two Numbers
#'
#' This function takes two numbers and returns their sum. It's a very
#' simple example function for our first package.
#'
#' @param x A number.
#' @param y Another number.
#' @return The sum of \code{x} and \code{y}.
#' @examples
#' add_two_numbers(1, 2)
#' add_two_numbers(10, -5)
#' @export
add_two_numbers <- function(x, y) {
  x + y
}

와, 뭔가 주석이 엄청 길어졌지? 하지만 이게 바로 전문가처럼 보이는 비결이야. 하나씩 차근차근 살펴보자.

roxygen2 핵심 태그 완전 정복 🧐
  • 첫 번째 줄 (Title): 함수 이름 바로 위에 있는 첫 번째 줄은 도움말의 제목이 돼. 간결하고 명확하게!
  • 두 번째 단락 (Description): 한 줄 띄고 작성하는 단락은 함수에 대한 상세 설명이 돼.
  • 세 번째 단락 (Details, 선택사항): 또 한 줄 띄고 작성하면 더 자세한 내용을 담는 Details 부분이 돼. 여기서는 생략했어.
  • @param [인자 이름] [설명]: 함수의 각 인자(parameter)가 무엇인지 설명해. 모든 인자에 대해 작성해주는 게 좋아.
  • @return [설명]: 함수가 무엇을 반환(return)하는지 설명해.
  • @examples: 이 함수를 어떻게 사용하는지 보여주는 예제 코드. 사용자들이 가장 좋아하는 부분이야! 이 코드는 실제로 실행 가능해야 해.
  • @export: 이게 제일 중요해! 이 태그가 있어야만 `roxygen2`가 이 함수를 `NAMESPACE` 파일에 등록해서, 사용자가 `library(myFirstPackage)` 후에 `add_two_numbers()`를 직접 호출할 수 있게 해줘. 마법의 주문 같은 거지.

이 외에도 정말 많은 태그들이 있어. 예를 들어, 다른 패키지의 함수를 코드 안에서 사용할 때는 `#' @importFrom [패키지명] [함수명]` 같은 태그를 사용해서 `NAMESPACE`에 수입 목록을 추가할 수 있지. 이건 나중에 의존성 관리 파트에서 더 자세히 다룰게.

마법의 주문: `devtools::document()`

자, 이제 우리가 정성껏 작성한 `roxygen2` 주석이 실제 결과물로 바뀌는 순간을 목격할 시간이야. 콘솔에 아래의 명령어를 입력하거나, RStudio의 `Build` 탭에서 `Document` 버튼을 클릭해봐.

devtools::document()

이 명령어를 실행하면 `roxygen2`가 우리 패키지 안의 모든 `R/` 폴더 파일을 스캔해서, `#'` 주석을 읽고 두 가지 중요한 작업을 수행해:

  1. `man/add_two_numbers.Rd` 파일 생성: `man/` 폴더를 확인해봐. `add_two_numbers.Rd` 라는 파일이 생겼을 거야. 이 파일을 열어보면 R의 도움말 페이지에서 사용하는 특수한 문법으로 가득 차 있어. 우리가 `roxygen2` 주석에 썼던 내용이 그대로 변환된 거지.
  2. `NAMESPACE` 파일 업데이트: `NAMESPACE` 파일을 열어봐. `@export` 태그 덕분에 아래와 같은 라인이 추가된 걸 볼 수 있어.
    export(add_two_numbers)
    이제 `add_two_numbers` 함수는 공식적으로 외부 세계와 소통할 준비를 마친 거야.

이제 모든 준비가 끝났으니, 우리 패키지를 실제로 설치하고 함수를 테스트해볼까? `devtools::install()` 또는 RStudio의 `Build` 탭에 있는 `Install and Restart` 버튼을 눌러봐.

devtools::install()

설치가 완료되고 R 세션이 재시작되면, 이제 우리 패키지는 R에 정식으로 등록된 거야. 콘솔에 직접 테스트해보자.

library(myFirstPackage)
add_two_numbers(5, 3)
# [1] 8

?add_two_numbers

어때? `add_two_numbers(5, 3)`이 8을 정확히 반환하고, `?add_two_numbers`를 실행하면 우리가 `roxygen2` 주석으로 작성했던 내용이 멋진 도움말 페이지로 나타나는 걸 볼 수 있어. 정말 뿌듯한 순간이지! 🎉

이게 바로 R 패키지 개발의 핵심 워크플로우야.

개발 워크플로우 요약 🔄
  1. `R/` 폴더에 함수를 작성하고 `roxygen2` 주석을 단다.
  2. `devtools::document()`를 실행해서 `NAMESPACE`와 `man/` 폴더를 업데이트한다.
  3. `devtools::install()`로 패키지를 설치하고 테스트한다.
  4. 수정할 부분이 생기면 1번으로 돌아가 반복한다.

이 과정을 계속 반복하면서 패키지에 살을 붙여나가는 거야. 처음에는 조금 어색할 수 있지만, 몇 번만 해보면 금방 익숙해질 거야. 이제 당신은 R 패키지에 함수를 추가하고, 문서화하고, 사용할 수 있게 만드는 가장 중요한 기술을 익혔어. 축하해! 🥳

Part 4: 혼자는 외로워! 🤝 다른 패키지와 협업하는 법 (의존성 관리)

우리가 만드는 모든 기능을 처음부터 끝까지 다 만들 수는 없어. 그건 바퀴를 재발명하는 것과 같지. R의 가장 큰 강점은 바로 CRAN에 있는 수많은 패키지 생태계야. 이미 만들어진 훌륭한 도구들을 잘 가져다 쓰는 것이 현명한 개발자의 덕목이지.

내 패키지가 다른 패키지의 함수를 사용할 때, 이걸 '의존성(Dependency)이 있다'고 말해. 그리고 이 의존성을 명확하게 관리하는 건 패키지 개발에서 정말, 정말 중요해. 왜냐하면 내 패키지를 설치하는 사용자 컴퓨터에 `dplyr`이 안 깔려있는데 내 코드가 `dplyr::filter()`를 호출하면 어떻게 될까? 당연히 에러가 나겠지! 💥

의존성 관리는 "제 패키지를 쓰려면, 이런이런 패키지들이 미리 설치되어 있어야 해요!"라고 R에게 알려주는 과정이야.

Imports vs. Suggests vs. Depends: 뭐가 다를까?

`DESCRIPTION` 파일에는 의존성을 명시하는 세 가지 주요 필드가 있어. `Imports`, `Suggests`, `Depends`. 많은 사람들이 헷갈려 하는데, 핵심만 기억하면 간단해.

  • Imports: 99%의 경우, 우리는 이것만 쓸 거야. "내 패키지가 작동하려면 이 패키지들이 *필수적*으로 필요해요"라는 의미. `Imports`에 명시된 패키지는 내 패키지를 설치할 때 자동으로 함께 설치돼. 가장 표준적이고 강력 추천하는 방법이야.
  • Suggests: "필수는 아닌데, 있으면 더 좋아요"라는 의미. 예를 들어, 패키지의 핵심 기능에는 필요 없지만, 비네트(사용 설명서)를 만들거나, 예제 코드를 실행하거나, 데이터를 시각화하는 함수처럼 부가적인 기능에만 필요한 패키지들을 여기에 넣어. `Suggests`에 있는 패키지는 자동으로 설치되지 않아.
  • Depends: 옛날 방식이고, 지금은 거의 사용하지 않아. "이 패키지를 `library()` 하면, `Depends`에 있는 패키지들도 함께 `library()` 해주세요"라는 강력한 요구야. 다른 패키지의 환경을 오염시킬 수 있어서, 해들리 위컴은 "절대 쓰지 마세요(Almost never use)"라고 말했어. 우리도 그냥 이런 게 있었다는 것만 알고 잊어버리자.
결론: 고민하지 말고 `Imports`를 사용하자!

`usethis::use_package()`로 스마트하게 의존성 추가하기

자, 그럼 `DESCRIPTION` 파일에 의존성을 어떻게 추가할까? 물론 직접 파일을 열어서 `Imports: dplyr` 이렇게 타이핑해도 돼. 하지만 우리에겐 더 스마트한 방법이 있지. 바로 `usethis`!

예를 들어, 우리 패키지가 `stringr` 패키지를 필요로 한다고 가정해보자. 콘솔에 이렇게 입력해봐.

usethis::use_package("stringr")

이 명령어를 실행하면 `usethis`가 `DESCRIPTION` 파일을 열어서 `Imports:` 필드에 `stringr`를 자동으로 추가해줘. 만약 `Imports`가 아니라 `Suggests`에 추가하고 싶다면?

usethis::use_package("ggplot2", type = "Suggests")

이렇게 `type` 인자를 지정해주면 돼. 정말 간단하지? 이렇게 `usethis`를 사용하면 오타를 낼 위험도 없고, 버전 명시 등 복잡한 규칙도 알아서 처리해주니 훨씬 안전하고 편해.

패키지 안에서 다른 패키지 함수 사용하는 법: `::`

의존성을 `DESCRIPTION`에 추가했다고 끝이 아니야. 이제 코드 안에서 실제로 그 패키지의 함수를 '어떻게' 호출할지가 중요해.

가장 좋은 방법은 `패키지명::함수명()` 형태로 사용하는 거야. 예를 들어, `stringr` 패키지의 `str_to_title()` 함수를 사용하고 싶다면, 코드에 `stringr::str_to_title("hello world")` 라고 명시적으로 적어주는 거지.

왜 이게 좋을까?

  • 명확성: 코드를 읽는 누구나 "아, 이 `str_to_title` 함수는 `stringr` 패키지에서 온 거구나!" 하고 바로 알 수 있어. 가독성이 엄청나게 올라가.
  • 충돌 방지: 만약 다른 패키지에도 우연히 `str_to_title`이라는 이름의 함수가 있다면? `::` 없이 그냥 썼다가는 어떤 함수가 호출될지 알 수 없어. `::`는 이런 이름 충돌(namespace conflict)을 완벽하게 막아줘.

자, 그럼 이걸 적용해서 새로운 함수를 하나 만들어볼까? `usethis::use_r("make_title")`로 새 파일을 만들고 아래처럼 코드를 작성해보자.

#' Make a String Title Case
#'
#' This function uses the \code{stringr} package to convert a string
#' to title case.
#'
#' @param text A character string.
#' @return A title-cased character string.
#' @importFrom stringr str_to_title
#' @export
#' @examples
#' make_title("hello world, this is my package!")
make_title <- function(text) {
  stringr::str_to_title(text)
}

`@importFrom`으로 `NAMESPACE` 관리하기

위 코드의 `roxygen2` 주석을 잘 봐. 새로운 태그가 등장했지? 바로 `#' @importFrom stringr str_to_title` 이야.

이 태그는 `roxygen2`에게 "이 함수 파일은 `stringr` 패키지의 `str_to_title` 함수를 사용하니까, `NAMESPACE` 파일에 `importFrom(stringr, str_to_title)` 이라고 적어줘!" 라고 알려주는 역할을 해.

이제 `devtools::document()`를 실행하면, `NAMESPACE` 파일이 이렇게 업데이트될 거야.

# Generated by roxygen2: do not edit by hand

export(add_two_numbers)
export(make_title)
importFrom(stringr, str_to_title)

이렇게 `::`와 `@importFrom`을 함께 사용하는 것이 현재 R 패키지 개발에서 가장 권장되는 '베스트 프랙티스(Best Practice)'야. 코드의 명확성과 패키지의 안정성을 모두 잡는 방법이지.

꿀팁! 파이프 연산자 `%>%`는 어떻게 쓰나요?

Tidyverse 스타일 코딩에 익숙한 우리에게 파이프 연산자 `%>%`는 공기와도 같지. 패키지 안에서 파이프를 쓰려면 어떻게 해야 할까? `usethis`가 이것도 해결해줘!

콘솔에 딱 한 번만 아래 명령어를 실행해줘.

usethis::use_pipe()

이 명령은 두 가지 일을 해:

  1. `DESCRIPTION` 파일의 `Imports`에 `magrittr` 패키지를 추가해.
  2. `R/utils-pipe.R` 이라는 파일을 만들고, 그 안에 `%>%`를 패키지 내부로 가져오는 코드를 자동으로 생성해줘.

이제 우리는 `roxygen2` 주석에 `#' @importFrom magrittr %>%`를 추가할 필요 없이, 패키지 내 모든 함수에서 자유롭게 `%>%`를 사용할 수 있어. 완전 편하지? 😉

의존성 관리는 처음엔 조금 복잡하게 느껴질 수 있지만, `usethis`, `::`, `@importFrom` 이 세 가지 원칙만 기억하면 돼. 이 원칙들을 잘 지키면, 당신의 패키지는 다른 어떤 환경에서도 안정적으로 작동하는 '잘 만든' 패키지가 될 거야. 이제 당신의 패키지는 더 이상 외톨이가 아니야. R 생태계의 다른 훌륭한 패키지들과 어깨를 나란히 하는 동료가 된 거지!

Part 5: 패키지에 데이터를 싣고 📦: `data/`와 `R/sysdata.rda`

함수만 있는 패키지는 조금 심심하지. 때로는 예제용 데이터나, 함수 내부에서 사용하는 보조 데이터가 필요할 때가 있어. 예를 들어, `ggplot2` 패키지에는 `mpg`, `diamonds` 같은 예제 데이터셋이 포함되어 있어서 사용자들이 쉽게 함수를 테스트하고 배울 수 있지.

우리 패키지에도 데이터를 포함시킬 수 있어. R 패키지에서 데이터를 다루는 방법은 크게 두 가지로 나뉘어. 바로 사용자에게 공개하는 데이터와 패키지 내부에서만 사용하는 데이터야.

사용자용 데이터: `data/` 폴더에 보관하기

사용자가 패키지를 로드한 뒤, `data(my_data)` 명령어나 그냥 `my_data`를 입력했을 때 바로 쓸 수 있는 데이터를 만들고 싶다면, 이 데이터를 `data/` 폴더에 `.rda` 파일 형식으로 저장해야 해.

이 과정 역시 `usethis`와 함께라면 식은 죽 먹기야. `iris` 데이터셋을 우리 패키지에 `flower_data`라는 이름으로 포함시켜 본다고 가정해보자.

Step 1: R 환경에 데이터 객체 만들기

먼저, 포함시키고 싶은 데이터를 R 세션의 전역 환경(Global Environment)에 객체로 만들어야 해.

flower_data <- iris
# 실제로는 여러분이 직접 만든 데이터프레임이나 리스트 등이 되겠지.
# 예: my_analysis_data <- read.csv("path/to/my/data.csv")

Step 2: `usethis::use_data()`로 데이터 저장하기

이제 마법의 주문을 외울 차례야. 콘솔에 아래와 같이 입력해봐.

usethis::use_data(flower_data)

이 명령은 다음과 같은 일을 자동으로 처리해줘:

  1. `data/` 라는 폴더가 없다면 새로 만들어줘.
  2. `flower_data` 라는 R 객체를 `data/flower_data.rda` 파일로 저장해. `.rda`는 R 전용 압축 데이터 형식이야.

이게 끝이야! 정말 간단하지?

Step 3: 데이터 문서화하기 (강력 추천!)

데이터를 포함시켰다면, 이 데이터가 무엇인지 설명하는 문서를 만들어주는 게 좋아. 그래야 사용자들이 `?flower_data`를 통해 데이터의 출처나 각 변수의 의미를 알 수 있으니까.

`R/` 폴더에 `data.R` 같은 파일을 하나 만들고 (`usethis::use_r("data-documentation")` 사용), 그 안에 아래와 같은 형식으로 `roxygen2` 주석을 작성해. 변수 없이, 데이터셋 이름만 따옴표로 감싸서 적는 게 특징이야.

#' Iris Flower Dataset
#'
#' A classic dataset containing measurements of 3 species of iris flowers.
#' This is included as an example dataset in myFirstPackage.
#'
#' @format A data frame with 150 rows and 5 variables:
#' \describe{
#'   \item{Sepal.Length}{Sepal length, in cm}
#'   \item{Sepal.Width}{Sepal width, in cm}
#'   \item{Petal.Length}{Petal length, in cm}
#'   \item{Petal.Width}{Petal width, in cm}
#'   \item{Species}{Factor with levels \code{setosa}, \code{versicolor}, \code{virginica}}
#' }
#' @source \url{https://en.wikipedia.org/wiki/Iris_flower_data_set}
"flower_data"
데이터 문서화 태그 톺아보기 🌿
  • @format: 데이터의 형식(예: 데이터프레임)과 차원(행/열 개수)을 설명해.
  • \describe{}: `\item{변수명}{설명}` 형식으로 각 변수(열)가 무엇을 의미하는지 상세히 기술할 수 있어.
  • @source: 데이터의 출처를 밝힐 때 사용해. 웹사이트 URL이나 논문 정보 등을 적어주면 좋아.

이제 `devtools::document()`와 `devtools::install()`을 실행하고 나면, `?flower_data`로 멋진 도움말을 볼 수 있고, 콘솔에서 바로 `head(flower_data)`처럼 데이터를 사용할 수 있게 돼. 멋지지?

개발자용 내부 데이터: `R/sysdata.rda`에 숨겨두기

때로는 사용자에게 직접 노출될 필요는 없지만, 패키지 내부의 함수들이 작동하는 데 필요한 데이터가 있을 수 있어. 예를 들어, 특정 계산에 필요한 고정된 계수 테이블이나, 에러 메시지 템플릿 모음 같은 것들 말이야.

이런 데이터는 `data/` 폴더에 넣으면 사용자를 혼란스럽게 할 수 있어. 이럴 때 사용하는 것이 바로 `R/sysdata.rda` 파일이야. 이 파일 안에 저장된 데이터 객체들은 패키지가 로드될 때 함께 로드되어서, 패키지 내의 함수들이 자유롭게 접근할 수 있지만, 사용자에게는 직접 보이지 않아.

`usethis`는 이 작업도 당연히 도와줘. `use_data()` 함수에 `internal = TRUE` 옵션만 추가하면 돼.

예를 들어, 우리 패키지 함수에서 사용할 비밀(?) 메시지를 저장한다고 해보자.

# R 환경에 내부 데이터 객체 생성
internal_messages <- list(
  welcome = "Welcome to myFirstPackage!",
  error = "Oops, something went wrong."
)

# internal = TRUE 옵션으로 저장
usethis::use_data(internal_messages, internal = TRUE)

이 명령을 실행하면 `R/sysdata.rda` 파일이 생성(또는 업데이트)되고, 그 안에 `internal_messages` 객체가 저장돼. 이제 `R/` 폴더 안의 다른 함수들에서는 `internal_messages$welcome` 같은 코드로 이 데이터에 바로 접근할 수 있어. 사용자들은 이 객체의 존재조차 모르게 말이지!

만약 기존 `R/sysdata.rda` 파일에 새로운 데이터를 추가하고 싶다면, `overwrite = TRUE` 옵션을 함께 사용하면 돼.

another_internal_data <- c(a = 1, b = 2)
usethis::use_data(internal_messages, another_internal_data, internal = TRUE, overwrite = TRUE)
`data/` vs. `R/sysdata.rda` 언제 뭘 쓸까? 🤔
  • 이 데이터를 사용자가 직접 보고 사용해야 하는가? (예: 예제 데이터)
    ➡️ Yes: `usethis::use_data(my_data)` (즉, `data/` 폴더)
  • 이 데이터는 오직 내 패키지 함수들만 사용하는가? (예: 내부 설정값, 룩업 테이블)
    ➡️ Yes: `usethis::use_data(my_internal_data, internal = TRUE)` (즉, `R/sysdata.rda`)

데이터를 패키지에 포함시키는 방법을 익혔으니, 이제 당신의 패키지는 훨씬 더 풍부하고 유용해질 수 있어. 사용자들을 위한 친절한 예제 데이터를 제공하거나, 복잡한 내부 로직을 깔끔한 데이터 테이블로 분리해서 코드의 가독성을 높일 수도 있지. 데이터는 패키지의 또 다른 강력한 무기가 될 거야!

Part 6: 버그는 못 참지! 🐞 `testthat`으로 철벽 방어하기

자, 우리 패키지에 멋진 함수들도 만들고, 데이터도 넣었어. 이제 슬슬 세상에 내놓을 준비가 된 것 같지? 하지만 잠깐! "내 컴퓨터에서는 잘 되는데?"는 개발자에게 가장 위험한 말이야. 내 코드가 다양한 상황에서 예상대로 정확하게 작동하는지 어떻게 보장할 수 있을까?

정답은 바로 '단위 테스트(Unit Testing)'에 있어. 단위 테스트는 함수 같은 코드의 작은 단위(unit)가 각각 올바르게 작동하는지 검증하는 자동화된 코드야. 그리고 R 세계에는 이 테스트를 아주 쉽고 재미있게 만들어주는 `testthat`이라는 멋진 패키지가 있지.

테스트 코드를 작성하는 건 귀찮은 일이 아니라, 미래의 나를 위한 최고의 보험이야. 나중에 코드를 수정했는데, 예전에 잘 되던 기능이 갑자기 망가지는 '회귀(regression)' 버그를 막아주거든. 테스트가 있다면, 코드 수정 후 테스트만 돌려보면 무엇이 잘못됐는지 바로 알 수 있어.

테스트 환경 설정: `usethis::use_testthat()`

우리 패키지에 `testthat`을 도입하는 것 역시 `usethis`와 함께라면 단 한 줄로 끝나.

usethis::use_testthat()

이 명령은 다음과 같은 구조를 만들어줘:

  1. `DESCRIPTION` 파일의 `Suggests` 필드에 `testthat`을 추가해. (테스트는 개발 과정에만 필요하므로 `Imports`가 아닌 `Suggests`가 적절해.)
  2. `tests/` 라는 최상위 폴더를 만들어.
  3. 그 안에 `tests/testthat/` 라는 하위 폴더를 만들어. 앞으로 우리의 모든 테스트 파일은 바로 여기에 저장될 거야.
  4. `tests/testthat.R` 이라는 파일을 만들어서, 테스트를 실행하기 위한 기본 설정 코드를 넣어줘.

이제 우리 패키지는 테스트를 맞이할 모든 준비를 마쳤어.

첫 테스트 코드 작성하기

테스트를 추가하고 싶은 함수가 있다면, `usethis`에게 말만 하면 돼. 예를 들어, 우리가 만들었던 `add_two_numbers` 함수에 대한 테스트를 만들어보자.

usethis::use_test("add_two_numbers")

이 명령은 `tests/testthat/test-add_two_numbers.R` 라는 파일을 만들고 열어줘. 파일 이름은 `test-`로 시작하는 게 규칙이야. 파일 안에는 기본적인 템플릿이 들어있을 거야.

test_that("multiplication works", {
  expect_equal(2 * 2, 4)
})

이게 `testthat` 테스트의 기본 구조야. 이걸 우리 함수에 맞게 수정해보자.

test_that("add_two_numbers works with positive numbers", {
  expect_equal(add_two_numbers(2, 3), 5)
  expect_equal(add_two_numbers(10, 100), 110)
})

test_that("add_two_numbers works with negative and zero", {
  expect_equal(add_two_numbers(-5, 5), 0)
  expect_equal(add_two_numbers(10, -20), -10)
  expect_equal(add_two_numbers(0, 0), 0)
})

test_that("add_two_numbers handles non-numeric input", {
  expect_error(add_two_numbers("a", 5))
  expect_error(add_two_numbers(10, "b"))
})
`testthat`의 핵심 구조: `test_that()`과 `expect_*()`
  • test_that("설명", { ... }): 관련된 테스트들을 하나로 묶어주는 블록이야. 첫 번째 인자로 들어가는 "설명"은 테스트가 실패했을 때 어떤 테스트에서 문제가 생겼는지 알려주는 중요한 역할을 해.
  • expect_*() 함수들: 실제 테스트를 수행하는 '기대(expectation)' 함수들이야. "나는 이 코드가 이런 결과를 낼 것이라고 기대한다!"라고 선언하는 거지.
    • expect_equal(결과, 기대값): 두 값이 같은지 확인해. 가장 많이 사용돼.
    • expect_true(조건) / expect_false(조건): 조건이 참/거짓인지 확인해.
    • expect_error(코드): 해당 코드를 실행했을 때 에러가 발생하는지 확인해. 잘못된 입력값에 대한 방어 로직을 테스트할 때 필수적이야.
    • expect_warning(코드) / expect_message(코드): 경고나 메시지가 발생하는지 확인해.
    • 이 외에도 `expect_length()`, `expect_type()`, `expect_s3_class()` 등 수많은 `expect` 함수들이 있어. 상황에 맞게 골라 쓰면 돼.

테스트 실행하고 결과 확인하기: `devtools::test()`

테스트 코드를 작성했으니, 이제 실행해볼 시간이야. 콘솔에 아래 명령어를 입력하거나, RStudio의 `Build` 탭에서 `Test Package`를 클릭해봐.

devtools::test()

이 명령을 실행하면 `testthat`이 `tests/testthat/` 폴더의 모든 `test-*.R` 파일을 찾아 실행하고, 그 결과를 예쁘게 보여줘.

모든 테스트를 통과했다면, 아마 이런 뿌듯한 메시지를 보게 될 거야.

[1] "add_two_numbers works with positive numbers"
[1] "add_two_numbers works with negative and zero"
[1] "add_two_numbers handles non-numeric input"

-- Test summary ----------------------------------------------------------------
PASS: 3 | FAILED: 0 | WARN: 0 | SKIP: 0

만약 테스트가 실패하면, 어떤 `test_that` 블록의 어떤 `expect` 함수에서 문제가 발생했는지, 실제 결과값과 기대값이 어떻게 달랐는지 아주 상세하게 알려줘. 덕분에 우리는 버그를 훨씬 빠르고 정확하게 찾아 수정할 수 있지.

최종 관문: `devtools::check()` 👑

단위 테스트가 개별 부품을 검사하는 과정이었다면, `devtools::check()`는 완성된 자동차가 도로에 나가기 전에 모든 부품이 잘 조립되었는지, 안전 기준을 통과하는지 종합적으로 검사하는 것과 같아.

이 명령은 CRAN(R 패키지 공식 저장소)에 패키지를 제출할 때 거치는 검사 과정을 내 컴퓨터에서 그대로 시뮬레이션해줘. `check()`는 정말 많은 것들을 검사해:

  • `DESCRIPTION` 파일의 형식은 올바른가?
  • 모든 함수에 문서(도움말)가 있는가?
  • 예제 코드는 에러 없이 실행되는가?
  • `testthat` 테스트는 모두 통과하는가?
  • 코드에 흔히 발생하는 문제점은 없는가?
  • 패키지 파일 구조는 표준을 따르는가?
  • ... 등등 수십 가지 항목을 체크해.

콘솔에 입력하거나, RStudio의 `Build` 탭에서 `Check` 버튼을 눌러 실행해보자.

devtools::check()

검사가 끝나면 결과를 세 가지 등급으로 알려줘: `ERROR`, `WARNING`, `NOTE`.

  • ERRORs: 치명적인 문제. 반드시 해결해야 해. 에러가 있으면 CRAN에 제출할 수 없어.
  • WARNINGs: 심각한 문제. 대부분의 경우 반드시 해결해야 해.
  • NOTEs: 잠재적인 문제일 수 있거나, CRAN 정책에 대한 제안 사항. 경우에 따라 무시할 수도 있지만, 가능한 한 모두 해결해서 '0 errors, 0 warnings, 0 notes' 상태를 만드는 것이 가장 좋아.

`check()`를 통과하는 것은 패키지의 품질을 보증하는 '품질 보증 마크'와 같아. 내 패키지를 다른 사람에게 자신 있게 공유하고 싶다면, `check()`를 습관화하는 것이 좋아. 코드를 조금 수정할 때마다 `check()`를 돌려보는 습관을 들인다면, 당신은 이미 훌륭한 R 패키지 개발자의 길을 걷고 있는 거야!

Part 7: 사용 설명서는 친절하게! 📖 비네트(Vignette)와 README 작성법

우리가 만든 패키지는 마치 새로운 가전제품과 같아. 기능이 아무리 훌륭해도 사용 설명서가 엉망이면 아무도 제대로 쓸 수 없지. R 패키지에서 이런 '사용 설명서' 역할을 하는 두 가지 중요한 문서가 바로 비네트(Vignette)와 README야.

개별 함수에 대한 도움말(`?function_name`)이 특정 버튼의 기능을 설명하는 것이라면, 비네트와 README는 제품 전체를 어떻게 활용하는지 보여주는 종합 가이드북이라고 할 수 있어.

장문의 튜토리얼: 비네트(Vignette) 만들기

비네트는 패키지의 주요 기능을 소개하고, 실제 문제를 해결하는 과정을 처음부터 끝까지 보여주는 긴 형식의 문서야. 보통 R 마크다운(`.Rmd`) 형식으로 작성되기 때문에, 설명 텍스트와 실행 가능한 R 코드, 그리고 그 결과(표, 플롯 등)를 한 문서 안에 모두 담을 수 있어.

사용자들은 비네트를 통해 패키지의 철학을 이해하고, 여러 함수들을 어떻게 조합해서 사용하는지 배울 수 있어. 잘 만든 비네트 하나가 열 개의 함수 도움말보다 더 효과적일 때가 많아.

자, 우리 패키지의 첫 비네트를 만들어볼까? 역시 `usethis`와 함께!

usethis::use_vignette("myFirstPackage-intro")

이 명령은:

  1. `DESCRIPTION` 파일의 `Suggests`에 `knitr`, `rmarkdown`을 추가하고, `VignetteBuilder` 필드를 설정해줘.
  2. `vignettes/` 폴더를 만들고, 그 안에 `myFirstPackage-intro.Rmd` 라는 R 마크다운 템플릿 파일을 생성해줘.

이제 `vignettes/myFirstPackage-intro.Rmd` 파일을 열어보자. 상단에는 YAML 헤더가 있고, 그 아래에는 R 마크다운 문법으로 내용을 채울 수 있는 공간이 있어.

---
title: "Introduction to myFirstPackage"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to myFirstPackage}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(myFirstPackage)
```

여기에 여러분의 패키지를 소개하는 멋진 글과 예제 코드를 작성하면 됩니다.
R 마크다운 문법을 그대로 사용할 수 있어요!

예를 들어, `add_two_numbers()` 함수는 이렇게 사용합니다.

```{r}
add_two_numbers(5, 10)
```

`make_title()` 함수를 사용하면 문장을 예쁘게 바꿀 수 있죠.

```{r}
text_example <- "this is a title"
make_title(text_example)
```

YAML 헤더의 `title`을 적절히 수정하고, 본문에 패키지 설치 방법, 주요 함수 소개, 실제 데이터 분석 예시 등을 자유롭게 작성하면 돼. R 마크다운을 써봤다면 아주 익숙할 거야.

비네트를 작성한 후에는 `devtools::build_vignettes()`를 실행해서 `.Rmd` 파일을 HTML 문서로 빌드할 수 있어. `devtools::install()`을 실행할 때도 비네트는 자동으로 빌드돼. 설치가 완료된 후 `browseVignettes("myFirstPackage")` 명령을 실행하면, 우리가 만든 멋진 튜토리얼을 웹 브라우저에서 확인할 수 있어!

패키지의 얼굴: README 파일 만들기

README 파일은 우리 패키지의 '얼굴'이자 '대문'이야. 특히 GitHub 저장소에 방문한 사람들이 가장 먼저 보게 되는 파일이지. 이 패키지가 무엇을 하는지, 어떻게 설치하는지, 가장 기본적인 사용법은 무엇인지를 간결하게 보여줘야 해.

README 역시 R 마크다운으로 작성해서 코드 실행 결과를 포함시키는 게 요즘 트렌드야. `usethis`는 이 작업도 기가 막히게 도와줘.

usethis::use_readme_rmd()

이 명령은 프로젝트 최상위 경로에 `README.Rmd` 파일을 생성해줘. 이 파일을 수정하고 내용을 채운 뒤, `devtools::build_readme()`를 실행하면 `README.Rmd` 파일이 일반 마크다운 파일인 `README.md`로 변환(knit)돼. GitHub는 `README.md` 파일을 자동으로 인식해서 예쁘게 보여주거든.

좋은 README에 포함되어야 할 내용들 📝
  • 패키지 이름과 짧은 설명: 이 패키지가 무엇을 위한 것인지 한두 문장으로 요약.
  • (선택) 상태 배지(Badges): CRAN 버전, 테스트 통과 여부(CI/CD), 코드 커버리지 등을 보여주는 작은 이미지. 패키지의 신뢰도를 높여줘. `usethis::use_cran_badge()`, `usethis::use_github_action_check_standard()` 등으로 쉽게 추가할 수 있어.
  • 설치 방법(Installation): CRAN이나 GitHub에서 어떻게 설치하는지 명확한 코드와 함께 안내.
    # CRAN에서 설치 (아직 제출 전이라면 주석 처리)
    # install.packages("myFirstPackage")
    
    # GitHub 개발 버전 설치
    # devtools::install_github("your-github-username/myFirstPackage")
  • 기본 사용 예제(Example): 가장 핵심적인 기능을 보여주는 간단하고 명확한 예제 코드. "이 패키지를 쓰면 5분 안에 이런 걸 할 수 있어요!"를 보여주는 게 목표야.
  • (선택) 도움받는 방법, 기여하는 방법, 행동 강령(Code of Conduct) 등.

`README.Rmd`를 수정한 뒤에는 잊지 말고 `devtools::build_readme()`를 실행해서 `README.md`를 업데이트해줘야 해. 이 과정을 자동화하고 싶다면, Git에 커밋하기 전에 자동으로 README를 빌드해주는 'pre-commit hook'을 설정할 수도 있어 (`usethis::use_precommit()` 참고).

친절한 비네트와 일목요연한 README는 당신의 패키지를 그냥 '쓸만한 코드 모음'에서 '사용자 친화적인 훌륭한 소프트웨어'로 격상시켜주는 중요한 마지막 터치야. 코드 작성만큼이나 문서화에도 애정을 쏟는다면, 사용자들은 당신의 패키지를 사랑하게 될 거야. ❤️

Part 8: 세상에 너의 코드를 알려라! 📢 GitHub와 CRAN 배포

자, 드디어 대망의 마지막 단계야. 우리는 열심히 패키지를 만들고, 문서화하고, 테스트까지 마쳤어. 이제 이 보석 같은 패키지를 나만 알고 있기엔 너무 아깝지 않아? 이제 당신의 코드를 세상에 공개하고 다른 사람들도 사용할 수 있게 만들어 줄 시간이야.

R 패키지를 배포하는 방법은 크게 두 가지야. 하나는 빠르고 쉬운 GitHub를 이용하는 방법, 다른 하나는 R의 공식 인증을 받는 것과 같은 CRAN에 제출하는 방법이야.

방법 1: 빠르고 자유로운 GitHub 배포 🚀

GitHub는 우리 패키지의 집이자, 쇼케이스이자, 배포 채널이 될 수 있는 가장 강력하고 쉬운 방법이야. Part 1에서 Git/GitHub 설정을 마쳤다면, 배포는 정말 간단해.

Step 1: GitHub 저장소(Repository) 생성 및 연결

아직 GitHub에 이 패키지를 위한 저장소를 만들지 않았다면, `usethis`에게 부탁하자.

usethis::use_github()

이 마법 같은 함수는:

  1. 당신의 GitHub 계정에 패키지 이름과 동일한 이름의 새로운 public 저장소를 만들어줘.
  2. 로컬 Git 저장소와 방금 만든 원격 GitHub 저장소를 연결해줘.
  3. 지금까지 작업한 모든 내용을 GitHub에 푸시(push)해줘.

이제 GitHub의 당신 계정에 가보면 `myFirstPackage` 저장소가 짠! 하고 만들어져 있고, 우리가 작성한 `README.md` 파일이 멋지게 첫 페이지를 장식하고 있을 거야.

Step 2: 설치 방법 안내하기

이제 전 세계 누구나 `devtools` 패키지만 있으면 당신의 패키지를 설치할 수 있어. `README.md` 파일에 아래와 같이 설치 방법을 안내해주자.

# 먼저 devtools 패키지를 설치해야 합니다.
# install.packages("devtools")

# GitHub에서 myFirstPackage를 설치합니다.
devtools::install_github("YOUR_GITHUB_USERNAME/myFirstPackage")

`YOUR_GITHUB_USERNAME` 부분만 당신의 GitHub 아이디로 바꿔주면 돼. 정말 간단하지?

GitHub를 통한 배포는 수정 사항을 즉시 반영할 수 있고, CRAN의 엄격한 정책에 얽매이지 않아도 된다는 큰 장점이 있어. 개인 프로젝트나 빠르게 발전하는 개발 단계의 패키지에 아주 적합한 방법이야.

방법 2: R 공식 인증, CRAN 배포 🏆

CRAN(The Comprehensive R Archive Network)은 R의 공식 패키지 저장소야. `install.packages("dplyr")` 처럼 패키지 이름만으로 간단하게 설치할 수 있는 모든 패키지는 바로 이 CRAN에 등록된 것들이지. CRAN에 패키지를 등록한다는 것은 당신의 패키지가 R 생태계의 공식적인 일원이 된다는 의미이며, 상당한 수준의 품질과 안정성을 인정받았다는 뜻이야. 그야말로 R 패키지 개발자의 '명예의 전당'이라고 할 수 있지.

하지만 그만큼 과정이 까다롭고 엄격해. CRAN은 자원봉사자들로 이루어진 팀이 관리하는데, 전 세계에서 쏟아지는 패키지들을 일관된 기준으로 관리해야 하기 때문이야.

CRAN 제출 전 최종 점검 리스트 ✅

CRAN에 도전하기로 마음먹었다면, 아래 항목들을 반드시 통과해야 해.

  1. `devtools::check()` 통과: `0 errors, 0 warnings, 0 notes`를 목표로! 만약 NOTE가 있다면, 왜 그 NOTE가 발생했고 문제가 되지 않는지 CRAN 리뷰어에게 설명할 준비를 해야 해.
  2. 다양한 환경에서 테스트: 내 컴퓨터에서만 `check()`를 돌려보는 건 부족해. `devtools`는 다른 운영체제(Windows, macOS, Linux)와 다른 R 버전(개발 버전 등)에서 원격으로 `check()`를 실행해볼 수 있는 기능을 제공해.
    # Windows 개발 버전에서 체크
    devtools::check_win_devel()
    # R-hub 빌더를 이용한 다양한 환경 체크
    rhub::check_for_cran()
    이 과정에서 예상치 못한 에러를 발견할 수 있어.
  3. CRAN 정책 숙지: CRAN은 'CRAN Repository Policy'라는 자체 정책 문서를 가지고 있어. 패키지 이름 규칙, `DESCRIPTION` 파일 작성법, 코드 작성 시 유의사항 등 꽤 상세한 내용이 담겨있어. 제출 전에 한 번쯤은 꼭 읽어보는 게 좋아.
  4. 완벽한 문서화: 모든 함수와 데이터는 문서화되어야 하고, 예제 코드는 모두 에러 없이 실행되어야 해. 패키지의 목적과 사용법을 설명하는 비네트가 있다면 CRAN 팀이 아주 좋아해.

제출 과정: `devtools::release()`

이 모든 준비를 마쳤다면, `devtools`의 `release()` 함수가 제출 과정을 안내해줄 거야.

devtools::release()

이 함수를 실행하면, 마치 로켓 발사 전 체크리스트처럼 여러 가지 질문을 던지며 최종 점검을 도와줘. `DESCRIPTION` 파일의 버전은 올바른지, `NEWS.md` 파일(버전별 변경사항을 기록하는 파일, `usethis::use_news_md()`로 생성)은 업데이트했는지 등을 확인하고, 최종적으로 패키지를 압축 파일(`.tar.gz`)로 만들어 CRAN에 제출할 준비를 마쳐줘. 모든 과정에 동의하면, 웹 브라우저가 열리면서 CRAN 제출 양식 페이지로 이동하고, 필요한 정보를 입력한 뒤 압축 파일을 업로드하면 제출이 완료돼.

제출 후에는 CRAN 팀의 리뷰를 기다려야 해. 며칠에서 몇 주가 걸릴 수 있어. 수정 요청이 올 수도 있고, 운이 좋으면 바로 통과될 수도 있어. 첫 제출에 거절당하더라도 너무 실망하지 마. 피드백을 반영해서 다시 도전하면 돼. 이 과정을 통해 당신의 패키지는 더욱 단단해질 거야.

이러한 패키지 개발 및 배포 기술은 매우 전문적인 능력이기 때문에, 익숙해진다면 재능넷과 같은 플랫폼에서 당신의 전문 지식을 필요로 하는 사람들에게 도움을 주며 새로운 기회를 만들 수도 있을 거야. 🌟

마치며: 이제 당신도 R 패키지 개발자! 🎉 다음 스텝은?

와, 정말 긴 여정이었어! 축하해! 👏 이 가이드를 끝까지 따라왔다면, 당신은 이제 더 이상 `source()` 함수에 의존하던 과거의 내가 아니야. 당신은 이제 체계적인 구조 위에서 코드를 작성하고, 문서화하고, 테스트하고, 세상과 공유할 줄 아는 진정한 R 패키지 개발자야.

우리는 함께 R 패키지 개발 환경을 세팅하는 것부터 시작해서, `usethis`로 패키지의 뼈대를 만들고, `R/` 폴더에 함수를 채워 넣었어. `roxygen2`로 전문가처럼 문서화를 하고, `testthat`으로 코드의 안정성을 확보했지. `devtools::check()`라는 최종 관문을 통과하는 법도 배웠고, 마침내 GitHub와 CRAN을 통해 우리의 작품을 세상에 선보이는 방법까지 모두 경험했어.

이 모든 과정이 처음에는 낯설고 복잡하게 느껴질 수 있어. 하지만 기억해. 가장 중요한 것은 '완벽함'이 아니라 '시작하는 것'과 '꾸준히 개선해 나가는 것'이야.

앞으로의 여정을 위한 몇 가지 팁
  • 작게 시작하기: 처음부터 세상을 바꿀 거대한 패키지를 만들려고 하지 마. 평소에 자주 사용하던 3~4개의 함수를 묶어서 작은 패키지로 만드는 것부터 시작해봐.
  • 다른 사람의 코드 읽기: `tidyverse` 팀의 패키지(dplyr, ggplot2 등)나 당신이 좋아하는 다른 패키지들의 GitHub 저장소에 가서 코드를 읽어봐. 다른 고수들은 패키지를 어떻게 구성하고, 어떤 방식으로 문제를 해결하는지 배우는 것만큼 좋은 공부는 없어.
  • 지속적 통합(CI) 도입하기: GitHub Actions 같은 CI/CD 도구를 사용하면, 코드를 GitHub에 푸시할 때마다 자동으로 `devtools::check()`를 실행하고 테스트를 돌릴 수 있어. 패키지의 품질을 항상 최상으로 유지하는 데 큰 도움이 돼. `usethis`에는 `usethis::use_github_action()` 같은 함수들이 준비되어 있어.
  • 커뮤니티와 함께하기: 막히는 부분이 있다면 주저하지 말고 질문해. RStudio 커뮤니티, Stack Overflow, 트위터의 #rstats 해시태그 등 도움을 받을 수 있는 곳은 정말 많아. 당신의 경험을 공유하는 것도 잊지 마!

R 패키지 개발은 단순히 코드를 정리하는 기술이 아니야. 이건 더 나은 프로그래머가 되기 위한 훈련 과정이고, 재현 가능한 과학(reproducible research)을 실천하는 방법이며, R 커뮤니티에 기여하는 가장 멋진 방법 중 하나야.

이제 당신의 손에는 스크립트 파일들을 멋진 작품으로 바꿀 수 있는 강력한 도구들이 쥐어져 있어. 당신의 아이디어와 코드를 패키지라는 그릇에 담아 세상과 나눠봐. 당신의 작은 패키지가 누군가의 반복적인 작업을 자동화해주고, 복잡한 분석을 가능하게 만들어 줄지도 몰라. 그 과정에서 느끼는 뿌듯함과 즐거움은 코딩의 또 다른 차원의 재미를 선사해 줄 거야.

이 가이드가 당신의 첫 패키지를 만드는 데 든든한 친구가 되었기를 바라. 이제 진짜 시작이야. Happy packaging! 😊

댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0
댓글을 불러오는 중입니다.

아직 댓글이 없습니다.