Web 일반
[Web 일반] 의존성 관리: Dependency 파일과 Lock 파일
comgu
2025. 4. 11. 21:13
반응형
의존성 관리는 프로젝트의 안정성과 재현성을 위해 매우 중요하다. 특히 팀 프로젝트나 배포 환경에서는 더욱 그렇다.
이 글에서는 의존성 관리의 핵심인 dependency 파일과 lock 파일에 대해 살펴본다.
목차
Dependency 파일과 Lock 파일의 차이점
Dependency 파일
- 개념: 프로젝트에 필요한 패키지와 대략적인 버전 범위를 정의
- 파이썬 예시: requirements.txt, setup.py, pyproject.toml
- 형식: 일반적으로 패키지 이름과 버전 제약 조건 포함 (예: Django>=3.2,<4.0)
- 목적: 개발자가 프로젝트에 필요한 의존성을 명시적으로 선언
Lock 파일
- 개념: 의존성 트리 전체의 정확한 버전을 고정(lock)
- 파이썬 예시: poetry.lock, Pipfile.lock, pdm.lock
- 형식: 모든 패키지와 그 하위 의존성의 정확한 버전, 해시값 등을 포함
- 목적: 모든 환경에서 정확히 동일한 패키지 세트가 설치되도록 보장
Git에 포함해야 하나?
Dependency 파일
- 결론: 반드시 포함해야 한다.
- 이유: 프로젝트의 필수 요구사항을 정의하며, 다른 개발자가 프로젝트를 이해하고 설정하는 데 필수적이다.
Lock 파일
- 결론: 대부분의 경우 포함해야 한다.
- 이유:
- 모든 개발자와 배포 환경에서 동일한 의존성을 보장
- "내 컴퓨터에서는 잘 돌아가는데?" 문제 방지
- 빌드 재현성 보장
- 예외: 라이브러리를 개발할 때는 lock 파일을 제외하는 경우도 있다(사용자의 환경에 따라 유연하게 대응해야 하므로).
주요 의존성 관리 도구
파이썬
- pip + requirements.txt
- 가장 기본적인 방식
- Lock 파일 개념이 없음 (pip freeze로 생성한 파일은 유사하지만 완전한 lock 파일은 아님)
- Poetry
- 현대적인 의존성 관리 도구
- pyproject.toml과 poetry.lock 사용
- 의존성 해결 알고리즘이 뛰어남
- Pipenv
- Pipfile과 Pipfile.lock 사용
- 가상환경 관리 통합
- PDM
- PEP 621 표준 준수
- pyproject.toml과 pdm.lock 사용
- 의존성 관리와 빌드 시스템 통합
- uv
- Rust로 작성된 최신 파이썬 패키지 설치 도구
- pip보다 훨씬 빠른 설치 속도 제공
- requirements.txt와 호환되며 lock 파일도 지원 (requirements.lock)
- 가상환경 생성 및 관리 기능 통합
- 의존성 해결 알고리즘이 개선되어 더 안정적인 의존성 트리 생성
다른 언어의 도구들
- JavaScript: npm/yarn (package.json, package-lock.json/yarn.lock)
- Ruby: Bundler (Gemfile, Gemfile.lock)
- Go: Go Modules (go.mod, go.sum)
- Java: Maven, Gradle (pom.xml, build.gradle)
하위 패키지 버전 결정 방식
패키지를 설치할 때 그 패키지가 필요로 하는 하위 패키지의 버전은 어떻게 결정될까?
의존성 해결 과정
- 의존성 트리 구성: 각 패키지가 필요로 하는 모든 하위 패키지를 재귀적으로 탐색
- 버전 제약 조건 수집: 모든 패키지의 버전 요구사항 수집
- 최적 버전 계산: 모든 제약 조건을 만족하는 각 패키지의 버전 조합 찾기
패키지 매니저별 동작 차이
- pip: 설치 순서에 따라 결과가 달라질 수 있음 (최신 버전의 pip는 개선됨)
- Poetry/Pipenv/PDM: 의존성 해결 알고리즘을 사용해 모든 제약조건을 만족하는 최적의 세트 계산
- uv: 백트래킹 알고리즘을 사용하여 효율적이고 결정론적인 의존성 해결 제공, pip보다 훨씬 빠르게 의존성 계산 및 설치 수행, 동일한 입력에 대해 항상 동일한 결과 보장
예시
프로젝트에서 패키지 A와 B를 직접 사용
- 패키지 A는 C>=1.0,<2.0 필요
- 패키지 B는 C>=1.5,<3.0 필요
→ 이 경우 C의 1.5~1.9 버전이 설치됨 (보통은 범위 내 최신 버전)
의존성 충돌 해결하기
의존성 충돌은 패키지 간 호환되지 않는 버전 요구사항이 있을 때 발생한다.
일반적인 충돌 유형
패키지 A는 C==1.0 필요
패키지 B는 C==2.0 필요
→ 두 요구사항을 동시에 만족시킬 수 없음
해결 방법
- 패키지 업데이트
- 충돌하는 패키지의 최신 버전으로 업데이트
- 최신 버전에서는 종종 호환성 문제가 해결됨
- 버전 제약 조건 완화
- 엄격한 버전 핀 대신 범위 지정 (예: ==1.0 → >=1.0,<2.0)
- 가상환경 분리
- 호환되지 않는 의존성이 있는 경우 별도의 가상환경 사용
- 의존성 오버라이드
- 일부 도구(Poetry, PDM)에서는 특정 패키지 버전을 명시적으로 오버라이드 가능
# poetry.toml 예시 [tool.poetry.dependencies] package-c = "1.5" # A와 B 모두 호환되는 버전으로 강제 # pyproject.toml (PDM) 예시 [tool.pdm.overrides] package-c = "1.5"
- 직접 패치 또는 포크
- 극단적인 경우, 문제가 있는 패키지를 직접 수정하거나 포크
실제 사용 예시: Django 프로젝트
Poetry 사용 시
1. 프로젝트 설정:
poetry init
poetry add django==4.2
poetry add --dev pytest pytest-django
2. 생성된 파일:
- pyproject.toml: 주 의존성 파일
- poetry.lock: 정확한 버전이 고정된 lock 파일
패키지 업데이트:
poetry update # 모든 패키지를 제약조건 내에서 최신 버전으로 업데이트
poetry update django # django만 업데이트
결론
Dependency 파일과 lock 파일을 적절히 활용하면 개발 과정이 더 원활해지고, "내 컴퓨터에서는 잘 돌아가는데?" 같은 문제를 피할 수 있다.
파이썬 백엔드 개발을 시작하는 분들께는 다음을 권장한다:
- 개인 프로젝트: 최소한 requirements.txt는 관리할 것.
- 팀 프로젝트: Poetry나 PDM 같은 현대적 도구로 lock 파일까지 관리할 것.
- 버전 관리: 의존성 파일과 lock 파일 모두 Git에 포함할 것.
반응형