패키지 매니저 (Package Manager)

"Reuse code, share libraries, accelerate development"

— 이미 존재하는 바퀴를 다시 발명하지 말고 공유 생태계를 활용해 번개처럼 개발하자는 모토.

내가 짠 코드는 10줄인데, 정작 설치된 오픈소스 파일만 20만 줄이 넘어가 하드디스크를 강제로 혹사시키는 용량 도둑. 하지만 어느 날 하나의 서브 의존성 패키지가 개발자 변심이나 해킹으로 내려가는 순간, 전 세계의 수백만 배포 파이프라인이 동시에 폭사한다.(...)

1. 개요

패키지 매니저는 프로젝트에 필요한 외부 라이브러리(의존성, Dependency)의 설치, 업데이트, 버전 조율, 삭제 등을 자동화해 주는 도구이다. 현대 소프트웨어 개발은 무에서 유를 창조하는 것이 아니라 타인의 코드를 벽돌처럼 쌓아 집을 짓는 과정이기에, 이 친구들의 통제를 받지 않고서는 단 하루도 정상적인 코딩이 불가능하다. 언어별로 대표적인 패키지 매니저가 고유의 생태계를 지배하고 있으며, 개발자들의 디렉토리를 무겁게 채우는 노역을 담당한다.(...)

2. 언어별 생태계를 지배하는 패키지 매니저 삼국지

현대의 거의 모든 개발 언어는 자체적인 패키지 매니저를 기본 내장하거나 커뮤니티 표준으로 둔다.

2.1. 자바스크립트/타입스크립트 생태계

  • 대표 주자: npm, Yarn, pnpm
  • 전통의 강자 npmNode.js와 동봉되어 웹 생태계를 평정했다. 하지만 속도가 느리고 node_modules라는 좀비 폴더를 양산하는 단점이 있어, 병렬 다운로드와 캐싱을 무기로 삼은 Yarn과 하드 링크를 활용해 디스크 용량을 획기적으로 절약하는 pnpm이 등장해 사정없이 점유율을 뜯어먹고 있다.1

2.2. 파이썬 생태계

  • 대표 주자: pip, Poetry, Conda
  • 기본 도구인 pip가 오랫동안 사용되었으나, 의존성 충돌 해결 능력이 끔찍하게 부족하다는 비판을 받아왔다. 이 때문에 현대적 프로젝트 관리 및 칼 같은 락킹(Locking)을 지원하는 Poetry가 업계 표준으로 올라섰고, 데이터 과학 진영은 가상 환경과 C-라이브러리 빌드를 한 번에 해결해 주는 Conda를 선호한다.

2.3. 러스트 생태계

  • 대표 주자: Cargo
  • 러스트의 공식 빌드 시스템이자 패키지 매니저인 Cargo는 전 세계 개발자들이 침이 마르도록 찬양하는 축복이다. 패키지 설치는 물론 컴파일, 테스트 실행, 문서 생성까지 명령어 하나로 뚝딱 끝내는 경이로운 완성도를 자랑한다.

3. 잠금 파일 (Lock File)의 중요성과 의존성 지옥

패키지 매니저를 쓸 때 가장 흔히 저지르는 실수가 바로 package-lock.json, yarn.lock, Cargo.lock 같은 잠금 파일(Lock File).gitignore에 넣어 버리는 만행이다.

3.1. 락 파일이 필요한 이유

  • package.json"lodash": "^4.17.0"이라고 적혀 있으면, 패키지 매니저는 4.17.0 이상 5.0.0 미만의 버전 중 가장 최신 버전을 매번 동적으로 알아서 설치한다.
  • 만약 영희가 개발할 때는 4.17.21 버전이 설치되어 멀쩡히 동작했는데, 이틀 뒤 철수가 설치할 때 lodash에 버그가 있는 4.17.22 버전이 새로 릴리스되면 철수의 로컬 환경만 기괴하게 오작동한다.
  • 이 비극을 방지하기 위해, 최초 설치 시 빌드된 모든 패키지의 정확한 버전 정보와 체크섬(Checksum)을 락 파일에 박제해 두고, 다른 개발자나 CI/CD 러너가 설치할 때 이 락 파일을 똑같이 추적하게 함으로써 완전히 일관된 환경을 보장해야만 한다.2

4. 관련 밈 및 드립

4.1. node_modules 블랙홀

Node.js 기반 웹 프로젝트를 생성하고 패키지를 몇 개 설치한 뒤 폴더 용량을 보면, 소스코드는 1MB 남짓인데 node_modules 폴더는 500MB를 넘나드는 현상이다. 인터넷에서는 세상에서 가장 무거운 물체로 블랙홀, 중성자별과 함께 node_modules 폴더가 자주 소환되며, 하드디스크의 남은 용량을 야금야금 먹어 치우는 악마의 폴더로 묘사된다.

4.2. Left-pad 대참사

2016년, 단 11줄짜리 자바스크립트 문자열 정렬 라이브러리인 left-pad 의 개발자가 npm 진영과의 갈등으로 패키지를 삭제해 버린 사건이다. 어처구니없게도 전 세계 수십만 개의 대형 프로젝트(React 등)가 이 코드를 직간접적으로 의존하고 있었던 탓에, 전 세계 수많은 대기업의 빌드 서버가 동시에 빨간 불을 뿜으며 주저앉는 현대 소프트웨어 개발사의 최대 촌극이 연출되었다.(...)

5. 여담

  • SemVer (유의적 버전)의 환상: 버전 번호를 Major.Minor.Patch로 부여해 변경 파급력을 예측하게 하는 표준 규약이다. 이론상은 완벽하지만, 많은 오픈소스 개발자들이 무지성으로 API를 깨뜨려 먹거나 실수로 마이너 버전에 파괴적 변경(Breaking Change)을 쑤셔 넣어 전 세계 빌드를 터뜨리곤 한다.
  • 가짜 패키지 공격 (Typosquatting): 해커들이 인기 있는 패키지명과 오타가 나기 쉬운 유사한 이름(예: reqeusts 대신 requests)으로 악성코드가 담긴 패키지를 올려두고, 개발자들이 실수로 오타를 내어 설치하길 기다리는 영악한 해킹 기법이 기승을 부린다.
  • Monorepo와 pnpm: 하나의 리포지토리에 여러 하브 프로젝트를 두는 모노레포 환경에서 pnpm은 최고의 전성기를 맞이했다. 같은 라이브러리를 여러 프로젝트가 쓸 때, 디스크 공간에 한 번만 물리적으로 저장하고 링크로 연결하므로 빌드 속도와 저장 공간 모두 극단적인 효율성을 보장한다.

6. 관련 문서

각주

  1. yarn v2/v3(Yarn Berry)는 아예 node_modules를 안 쓰고 가상 zip 파일로 의존성을 인덱싱하는 PnP(Plug'n'Play) 방식을 고안하여 실행 속도를 미친 듯이 끌어올렸다.

  2. 따라서 락 파일은 무조건 Git 저장소에 커밋해야 하며, 빌드 배포 단계에서도 npm install 대신 락 파일을 강제로 고수하는 npm ci 명령어를 써야 한다.