Skip to content

✍️ 필사 모드: 패키지 매니저 완전 가이드 — npm, uv, RPM, Homebrew 원리와 소프트웨어 등록법

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며

소프트웨어 개발에서 패키지 매니저는 인프라의 근간이다. 우리가 매일 사용하는 npm install, pip install, brew install, yum install 같은 명령어 뒤에는 의존성 해결, 버전 관리, 바이너리 배포라는 복잡한 메커니즘이 숨어 있다.

이 글에서는 네 가지 주요 패키지 매니저의 내부 원리를 파헤치고, 각 생태계에 자신의 소프트웨어를 등록하는 방법까지 다룬다.


Part 1: npm 원리 (JavaScript / Node.js)

1-1. npm이란

npm(Node Package Manager)은 JavaScript 생태계의 표준 패키지 매니저다. 세 가지 핵심 구성 요소가 있다.

레지스트리(Registry): 모든 패키지가 저장되는 중앙 저장소다. registry.npmjs.org에 호스팅되며 전 세계에 CDN으로 배포된다. 2026년 기준 300만 개 이상의 패키지가 등록되어 있다.

package.json: 프로젝트의 메타데이터와 의존성을 선언하는 파일이다.

{
  "name": "my-project",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.18.0",
    "lodash": "~4.17.21"
  },
  "devDependencies": {
    "jest": "^29.0.0"
  }
}

node_modules: 의존성이 실제로 설치되는 디렉토리다. npm은 기본적으로 중첩(nested) 구조를 사용하지만, 가능한 한 끌어올림(hoisting)을 통해 디렉토리를 평탄화한다.

1-2. 의존성 해결 메커니즘

npm의 의존성 해결은 크게 네 가지 개념으로 설명된다.

Semver(Semantic Versioning):

npm은 semver 규칙을 따른다. 버전은 MAJOR.MINOR.PATCH 형식이며, 각 범위 지정자의 의미는 다음과 같다.

지정자의미예시
^4.18.0MAJOR 고정, MINOR와 PATCH 허용4.18.0 이상 5.0.0 미만
~4.17.21MAJOR와 MINOR 고정, PATCH만 허용4.17.21 이상 4.18.0 미만
4.18.0정확히 해당 버전만4.18.0만
>=4.0.0해당 버전 이상 모두4.0.0 이상

Lock 파일:

package-lock.json은 설치된 모든 패키지의 정확한 버전, 무결성 해시, 해결된 URL을 기록한다. 이를 통해 팀 전체가 동일한 의존성 트리를 재현할 수 있다.

{
  "name": "my-project",
  "lockfileVersion": 3,
  "packages": {
    "node_modules/express": {
      "version": "4.18.2",
      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
      "integrity": "sha512-abc123..."
    }
  }
}

Hoisting(끌어올림):

패키지 A가 lodash 4.17.21에 의존하고, 패키지 B도 lodash 4.17.21에 의존한다면, npm은 lodash를 최상위 node_modules에 한 번만 설치한다. 하지만 서로 다른 버전이 필요하면 하위 node_modules에 중복 설치된다.

팬텀 의존성(Phantom Dependencies):

hoisting으로 인해 직접 의존하지 않은 패키지를 코드에서 import할 수 있게 되는 문제다. package.json에 선언하지 않았는데도 우연히 사용 가능한 상태가 되는 것이다. 이는 나중에 의존성 트리가 바뀌면 갑자기 깨지는 원인이 된다.

1-3. npm vs yarn vs pnpm

세 패키지 매니저의 핵심 차이를 비교해보자.

항목npmyarn (Berry)pnpm
저장 방식node_modules (hoisted)Plug'n'Play (PnP)content-addressable store + symlinks
Lock 파일package-lock.jsonyarn.lockpnpm-lock.yaml
팬텀 의존성 방지XO (strict PnP)O (격리된 node_modules)
디스크 사용량높음낮음매우 낮음 (하드링크)
워크스페이스npm workspacesyarn workspacespnpm workspaces
성능보통좋음매우 좋음

pnpm의 핵심 아이디어:

pnpm은 글로벌 content-addressable store에 패키지를 한 번만 저장하고, 프로젝트의 node_modules에는 하드링크(hard link)를 만든다. 동일한 버전의 lodash를 10개 프로젝트에서 사용해도 디스크에는 한 번만 저장된다.

~/.pnpm-store/
  v3/
    files/
      ab/cdef1234...   # lodash 4.17.21의 실제 파일

project-a/node_modules/.pnpm/
  lodash@4.17.21/
    node_modules/
      lodash/
        index.js  -->  ~/.pnpm-store/v3/files/ab/cdef1234... (하드링크)

1-4. npm에 패키지 등록하기

자신의 패키지를 npm 레지스트리에 배포하는 단계별 과정이다.

1단계: 계정 생성 및 로그인

npm adduser
# 또는 이미 계정이 있다면
npm login

2단계: 패키지 초기화

mkdir my-awesome-lib
cd my-awesome-lib
npm init

3단계: package.json 완성

{
  "name": "my-awesome-lib",
  "version": "1.0.0",
  "description": "A library that does awesome things",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "build": "tsc",
    "prepublishOnly": "npm run build"
  },
  "keywords": ["awesome", "utility"],
  "author": "Your Name",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourname/my-awesome-lib"
  }
}

4단계: 배포

# 빌드 확인
npm run build

# 배포 전 미리보기 (어떤 파일이 포함되는지 확인)
npm pack --dry-run

# 실제 배포
npm publish

# 스코프가 있는 패키지 (공개)
npm publish --access public

5단계: 버전 관리

# 패치 버전 올리기 (1.0.0 -> 1.0.1)
npm version patch

# 마이너 버전 올리기 (1.0.1 -> 1.1.0)
npm version minor

# 메이저 버전 올리기 (1.1.0 -> 2.0.0)
npm version major

# 배포
npm publish

Part 2: uv 원리 (Python)

2-1. uv란

uv는 Astral에서 Rust로 개발한 초고속 Python 패키지 매니저이자 프로젝트 관리 도구다. pip를 대체하면서도 pip의 10~100배 빠른 속도를 보여준다.

uv가 빠른 이유는 여러 가지다.

  • Rust로 작성: 네이티브 바이너리로 컴파일되어 Python 인터프리터의 오버헤드가 없다
  • 병렬 다운로드: 의존성 해결과 다운로드를 동시에 수행한다
  • 글로벌 캐시: 한 번 다운로드한 패키지는 모든 프로젝트에서 재사용한다
  • 최적화된 SAT 솔버: 의존성 그래프를 효율적으로 해결한다
# uv 설치
curl -LsSf https://astral.sh/uv/install.sh | sh

# 프로젝트 생성
uv init my-project
cd my-project

# 의존성 추가
uv add requests flask

# 의존성 동기화 (lock 파일 기반)
uv sync

2-2. pip vs uv vs poetry vs conda

항목pipuvpoetryconda
언어PythonRustPythonPython/C
의존성 해결백트래킹SAT 솔버SAT 솔버SAT 솔버
Lock 파일X (수동 freeze)uv.lockpoetry.lockenvironment.yml
가상환경 관리X (별도 venv)O (내장)O (내장)O (내장)
속도 (cold install)느림 (기준)10~100x 빠름2~5x 빠름느림
빌드 시스템setuptools자체 해결자체 빌드자체 빌드
비-Python 패키지XXXO (numpy C 라이브러리 등)

속도 비교 (실제 벤치마크):

# requests + flask + sqlalchemy 설치 (cold cache)
pip install:    12.4s
poetry install:  8.1s
uv sync:         0.8s   # 15x 빠름

2-3. uv의 의존성 해결 알고리즘

uv는 PubGrub 알고리즘을 기반으로 한 SAT 솔버를 사용한다. 이 알고리즘이 하는 일을 단계별로 살펴보자.

1. 의존성 그래프 구축:

프로젝트의 직접 의존성에서 시작하여, 각 패키지의 메타데이터를 읽어 전이적(transitive) 의존성 그래프를 구축한다.

2. 제약 조건 전파(Constraint Propagation):

각 패키지의 버전 요구사항을 제약 조건으로 변환하고, 이를 전파하여 가능한 버전 공간을 줄여나간다.

3. 단위 전파(Unit Propagation):

하나의 가능한 값만 남은 변수가 있으면, 그 값을 확정하고 관련 제약을 업데이트한다.

4. 충돌 기반 학습(Conflict-Driven Clause Learning):

충돌이 발생하면 그 원인을 분석하여 "학습된 절(learned clause)"을 추가한다. 이를 통해 같은 실패를 반복하지 않는다.

예시: A>=1.0 requires B>=2.0, but C<1.5 requires B<2.0
  -> 충돌 발생
  -> 학습: A>=1.0 AND C<1.5 는 동시에 성립 불가
  -> 백트래킹 후 다른 버전 시도

2-4. PyPI에 패키지 등록하기

Python 패키지를 PyPI(Python Package Index)에 등록하는 현대적인 방법이다.

1단계: pyproject.toml 작성

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my-python-lib"
version = "1.0.0"
description = "A useful Python library"
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
authors = [
    { name = "Your Name", email = "you@example.com" }
]
dependencies = [
    "requests>=2.28.0",
    "pydantic>=2.0",
]

[project.urls]
Homepage = "https://github.com/yourname/my-python-lib"
Documentation = "https://my-python-lib.readthedocs.io"

[project.optional-dependencies]
dev = ["pytest", "ruff", "mypy"]

2단계: 빌드

# 빌드 도구 설치
uv add --dev build

# 빌드 실행
python -m build

# dist/ 디렉토리에 .whl과 .tar.gz 파일이 생성됨
ls dist/
# my_python_lib-1.0.0-py3-none-any.whl
# my_python_lib-1.0.0.tar.gz

3단계: TestPyPI에서 테스트

# twine 설치
uv add --dev twine

# TestPyPI에 업로드
python -m twine upload --repository testpypi dist/*

# 테스트 설치
pip install --index-url https://test.pypi.org/simple/ my-python-lib

4단계: 실제 PyPI에 배포

# PyPI에 업로드
python -m twine upload dist/*

# 이제 누구나 설치 가능
pip install my-python-lib
# 또는
uv add my-python-lib

Trusted Publisher 설정 (GitHub Actions):

name: Publish to PyPI
on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install build
      - run: python -m build
      - uses: pypa/gh-action-pypi-publish@release/v1

이 방식을 사용하면 API 토큰 없이도 PyPI에 배포할 수 있다. GitHub의 OIDC 토큰을 통해 인증이 이루어진다.


Part 3: RPM (Red Hat / CentOS / Rocky Linux)

3-1. RPM이란

RPM(Red Hat Package Manager)은 Red Hat 계열 리눅스 배포판의 패키지 관리 시스템이다. 핵심 구성 요소는 다음과 같다.

RPM 파일: .rpm 확장자를 가진 바이너리 패키지 파일이다. 컴파일된 프로그램, 설정 파일, 문서, 설치/제거 스크립트를 포함한다.

RPM 데이터베이스: /var/lib/rpm에 위치하며, 설치된 모든 패키지의 정보를 추적한다.

yum / dnf: RPM의 의존성 해결 문제를 해결하는 상위 레벨 도구다. RPM은 단일 패키지만 설치할 수 있지만, dnf는 의존성을 자동으로 해결하고 원격 저장소에서 패키지를 다운로드한다.

# RPM 직접 사용 (의존성 자동 해결 안 됨)
rpm -ivh package-1.0.0-1.el9.x86_64.rpm

# dnf 사용 (의존성 자동 해결)
dnf install nginx

# 패키지 정보 조회
rpm -qi nginx

# 패키지에 포함된 파일 목록
rpm -ql nginx

Spec 파일: RPM 패키지를 빌드하기 위한 레시피 파일이다. 소스 코드를 어떻게 컴파일하고, 어떤 파일을 어디에 설치하며, 어떤 의존성이 필요한지를 정의한다.

3-2. RPM 패키지 만들기

1단계: 빌드 환경 준비

# 빌드 도구 설치
dnf install rpm-build rpmdevtools

# 빌드 디렉토리 구조 생성
rpmdev-setuptree

# 생성되는 구조:
# ~/rpmbuild/
#   BUILD/      - 빌드가 수행되는 디렉토리
#   RPMS/       - 빌드된 RPM 파일
#   SOURCES/    - 소스 타르볼
#   SPECS/      - spec 파일
#   SRPMS/      - 소스 RPM 파일

2단계: Spec 파일 작성

Name:           myapp
Version:        1.0.0
Release:        1%{?dist}
Summary:        My awesome application

License:        MIT
URL:            https://github.com/yourname/myapp
Source0:        %{name}-%{version}.tar.gz

BuildRequires:  gcc
BuildRequires:  make
Requires:       openssl-libs

%description
MyApp is an awesome application that does useful things.
It supports multiple platforms and is easy to configure.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files
%license LICENSE
%doc README.md
%{_bindir}/myapp
%{_mandir}/man1/myapp.1*
%config(noreplace) %{_sysconfdir}/myapp.conf

%changelog
* Sat Apr 12 2026 Your Name <you@example.com> - 1.0.0-1
- Initial package

3단계: 빌드

# 소스 타르볼을 SOURCES에 복사
cp myapp-1.0.0.tar.gz ~/rpmbuild/SOURCES/

# RPM 빌드 (-ba: 바이너리와 소스 RPM 모두)
rpmbuild -ba ~/rpmbuild/SPECS/myapp.spec

# 빌드된 RPM 확인
ls ~/rpmbuild/RPMS/x86_64/
# myapp-1.0.0-1.el9.x86_64.rpm

4단계: 로컬 레포지토리 만들기

# createrepo 설치
dnf install createrepo_c

# 레포 디렉토리 생성
mkdir -p /var/www/html/myrepo/

# RPM 복사
cp ~/rpmbuild/RPMS/x86_64/myapp-*.rpm /var/www/html/myrepo/

# 레포 메타데이터 생성
createrepo /var/www/html/myrepo/
# /etc/yum.repos.d/myrepo.repo
[myrepo]
name=My Custom Repository
baseurl=http://myserver.example.com/myrepo/
enabled=1
gpgcheck=0

3-3. DEB vs RPM 비교

항목RPM (Red Hat 계열)DEB (Debian 계열)
배포판RHEL, CentOS, Rocky, FedoraDebian, Ubuntu, Mint
패키지 형식.rpm.deb
저수준 도구rpmdpkg
고수준 도구yum / dnfapt / apt-get
패키지 정의spec 파일debian/ 디렉토리 (control, rules 등)
빌드 도구rpmbuilddpkg-buildpackage
레포 생성createrepoapt-ftparchive / reprepro
스크립트 단계pre/post install/uninstallpreinst/postinst/prerm/postrm
서명GPGGPG (apt-key)

핵심 차이는 설계 철학에 있다. RPM의 spec 파일은 모든 것을 하나의 파일에 담는 반면, DEB의 debian/ 디렉토리는 역할별로 파일을 분리한다.


Part 4: Homebrew (macOS / Linux)

4-1. Homebrew 원리

Homebrew는 macOS(그리고 Linux)의 비공식 패키지 매니저다. 핵심 개념들을 살펴보자.

Formula: 패키지 설치 방법을 정의하는 Ruby 스크립트다. 소스 URL, 빌드 옵션, 의존성, 설치 과정을 포함한다.

Tap: Formula를 모아놓은 Git 저장소다. 기본 Tap은 homebrew-core이며, 누구나 자신만의 Tap을 만들 수 있다.

Cellar: 패키지가 실제로 설치되는 위치다. macOS에서는 /opt/homebrew/Cellar/ (Apple Silicon) 또는 /usr/local/Cellar/ (Intel)에 위치한다.

Keg-only: Cellar에 설치되지만 PATH에 심볼릭 링크가 생성되지 않는 패키지다. 시스템에 이미 같은 프로그램이 있을 때 충돌을 방지한다. 대표적인 예가 openssl이다.

# 패키지 설치
brew install wget

# 설치 경로 확인
brew --prefix wget
# /opt/homebrew/opt/wget

# Cellar 내부 구조
ls /opt/homebrew/Cellar/wget/1.21.4/
# bin/  etc/  share/

# keg-only 패키지 강제 링크
brew link --force openssl@3

Bottle: 미리 컴파일된 바이너리 패키지다. 소스에서 빌드하는 대신 Bottle을 다운로드하면 설치 속도가 크게 빨라진다. 대부분의 공식 Formula에는 macOS와 Linux용 Bottle이 제공된다.

4-2. Homebrew에 소프트웨어 등록하기

Homebrew에 소프트웨어를 등록하는 세 가지 방법이 있다.

방법 1: 개인 Tap 만들기

가장 간단하고 제약이 적은 방법이다.

1단계: GitHub 리포지토리 생성

homebrew-mytap이라는 이름으로 GitHub 리포지토리를 만든다. Homebrew는 homebrew- 접두사를 Tap 이름으로 인식한다.

2단계: Formula 작성

# Formula/myapp.rb
class Myapp < Formula
  desc "My awesome command-line application"
  homepage "https://github.com/yourname/myapp"
  url "https://github.com/yourname/myapp/archive/refs/tags/v1.0.0.tar.gz"
  sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  license "MIT"

  depends_on "go" => :build

  def install
    system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
  end

  test do
    assert_match "myapp version #{version}", shell_output("#{bin}/myapp --version")
  end
end

3단계: 사용

# Tap 추가
brew tap yourname/mytap

# 설치
brew install yourname/mytap/myapp

# 또는 Tap 추가 후 직접 설치
brew install myapp

방법 2: homebrew-core에 PR 제출

공식 Homebrew에 포함되려면 엄격한 기준을 충족해야 한다.

필수 조건:

  • GitHub에서 30개 이상의 star (또는 충분한 사용자 기반)
  • 안정적인 릴리스 태그
  • 오픈소스 라이선스
  • CI/CD를 통한 자동 빌드
  • macOS와 Linux 모두에서 빌드 가능
# homebrew-core 클론 및 Formula 추가
brew tap --force homebrew/core
cd $(brew --repository homebrew/core)

# Formula 생성 헬퍼
brew create https://github.com/yourname/myapp/archive/refs/tags/v1.0.0.tar.gz

# Formula 검증
brew audit --new myapp
brew test myapp

# PR 제출 (GitHub CLI)
gh pr create --title "myapp 1.0.0 (new formula)" --body "Description of the tool..."

방법 3: Cask (GUI 앱) 등록

.app, .dmg, .pkg 형태의 macOS GUI 애플리케이션을 배포할 때 사용한다.

# Casks/myguiapp.rb
cask "myguiapp" do
  version "2.1.0"
  sha256 "abc123def456..."

  url "https://github.com/yourname/myguiapp/releases/download/v#{version}/MyGuiApp-#{version}.dmg"
  name "MyGuiApp"
  desc "A beautiful GUI application"
  homepage "https://myguiapp.example.com"

  app "MyGuiApp.app"

  zap trash: [
    "~/Library/Application Support/MyGuiApp",
    "~/Library/Preferences/com.yourname.myguiapp.plist",
  ]
end
# Cask 설치
brew install --cask myguiapp

4-3. Formula 작성법 상세

Homebrew Formula는 Ruby DSL로 작성된다. 주요 구성 요소를 살펴보자.

class ComplexApp < Formula
  desc "A complex application with many build options"
  homepage "https://complexapp.dev"

  # 안정 버전 소스
  url "https://github.com/yourname/complexapp/archive/refs/tags/v2.0.0.tar.gz"
  sha256 "deadbeef..."

  # HEAD 버전 (개발 중)
  head "https://github.com/yourname/complexapp.git", branch: "main"

  license "Apache-2.0"

  # 빌드 의존성
  depends_on "cmake" => :build
  depends_on "pkg-config" => :build

  # 런타임 의존성
  depends_on "openssl@3"
  depends_on "sqlite"

  # 플랫폼 제한
  depends_on :macos

  # Python 바인딩 (선택)
  option "with-python", "Build Python bindings"
  depends_on "python@3.12" if build.with?("python")

  def install
    args = %W[
      --prefix=#{prefix}
      --with-openssl=#{Formula["openssl@3"].opt_prefix}
      --with-sqlite=#{Formula["sqlite"].opt_prefix}
    ]

    args << "--with-python" if build.with?("python")

    system "./configure", *args
    system "make", "install"

    # 쉘 완성 스크립트 설치
    bash_completion.install "completions/complexapp.bash"
    zsh_completion.install "completions/_complexapp"
    fish_completion.install "completions/complexapp.fish"
  end

  # 설치 후 안내 메시지
  def caveats
    <<~EOS
      To start complexapp as a service:
        brew services start complexapp
    EOS
  end

  # 설치 검증 테스트
  test do
    assert_match version.to_s, shell_output("#{bin}/complexapp --version")
    system "#{bin}/complexapp", "check"
  end
end

Formula의 주요 DSL 메서드:

메서드용도예시
url소스 다운로드 URLurl "https://..."
sha256무결성 검증 해시sha256 "abc..."
depends_on의존성 선언depends_on "openssl@3"
install빌드 및 설치 과정system "make", "install"
test설치 검증assert_match ...
prefix설치 기본 경로/opt/homebrew/Cellar/app/1.0
bin실행파일 경로prefix/"bin"
etc설정파일 경로prefix/"etc"
share공유 데이터 경로prefix/"share"

Part 5: 패키지 매니저 대비교

5-1. 종합 비교 매트릭스

항목npmPyPI(uv/pip)RPM(dnf)HomebrewAPT(deb)snapflatpak
대상Node.js 라이브러리Python 라이브러리시스템 패키지CLI/GUI 앱시스템 패키지데스크톱 앱데스크톱 앱
플랫폼크로스 플랫폼크로스 플랫폼RHEL 계열macOS/LinuxDebian 계열리눅스리눅스
레지스트리npmjs.compypi.org벤더 레포homebrew-core벤더 레포snapcraft.ioflathub.org
격리 방식node_modulesvirtualenv없음 (시스템 전역)Cellar+symlinks없음 (시스템 전역)샌드박스샌드박스
의존성 해결semver 범위SAT 솔버libsolv (SAT)자체APT solversnap 자체 관리런타임 공유
자동 업데이트XXdnf-automaticbrew upgradeunattended-upgradessnapd (자동)X
보안 서명npm 서명GPG/SigstoreGPG코드서명 (Cask)GPGSnap Store 서명Flathub 서명
크기 제한없음없음없음없음없음큼 (번들)큼 (런타임)

5-2. 어떤 패키지 매니저를 사용해야 할까?

JavaScript/TypeScript 라이브러리를 배포하고 싶다면: npm 또는 GitHub Packages를 사용한다.

Python 라이브러리를 배포하고 싶다면: PyPI에 등록하고 uv/pip으로 설치하게 한다.

리눅스 서버에 시스템 레벨 패키지를 배포하고 싶다면: RPM(RHEL 계열) 또는 DEB(Debian 계열) 패키지를 만든다.

macOS용 CLI 도구를 배포하고 싶다면: Homebrew Formula를 작성하여 개인 Tap에 올리거나 homebrew-core에 PR을 제출한다.

크로스 플랫폼 데스크톱 앱을 배포하고 싶다면: snap 또는 flatpak을 고려한다. snap은 자동 업데이트가 내장되어 있고, flatpak은 더 개방적인 생태계를 가진다.


마치며

패키지 매니저는 단순한 설치 도구가 아니다. 의존성 해결이라는 NP-완전 문제를 실용적으로 풀어내고, 수백만 개의 패키지를 안전하게 배포하며, 개발자 생태계의 혈관 역할을 한다.

각 패키지 매니저의 내부 원리를 이해하면 의존성 충돌을 더 빠르게 해결하고, 캐시를 효율적으로 관리하며, 자신의 소프트웨어를 세상에 배포하는 과정이 훨씬 수월해진다.

자신의 프로젝트를 npm, PyPI, Homebrew, RPM 어디에든 등록해보자. 패키지 매니저의 작동 원리를 체감하는 가장 좋은 방법은 직접 패키지를 만들어보는 것이다.


참고 자료

현재 단락 (1/398)

소프트웨어 개발에서 패키지 매니저는 인프라의 근간이다. 우리가 매일 사용하는 `npm install`, `pip install`, `brew install`, `yum instal...

작성 글자: 0원문 글자: 13,748작성 단락: 0/398