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 파일을 제외하는 경우도 있다(사용자의 환경에 따라 유연하게 대응해야 하므로).

주요 의존성 관리 도구

파이썬

  1. pip + requirements.txt
    • 가장 기본적인 방식
    • Lock 파일 개념이 없음 (pip freeze로 생성한 파일은 유사하지만 완전한 lock 파일은 아님)
  2. Poetry
    • 현대적인 의존성 관리 도구
    • pyproject.toml과 poetry.lock 사용
    • 의존성 해결 알고리즘이 뛰어남
  3. Pipenv
    • Pipfile과 Pipfile.lock 사용
    • 가상환경 관리 통합
  4. PDM
    • PEP 621 표준 준수
    • pyproject.toml과 pdm.lock 사용
    • 의존성 관리와 빌드 시스템 통합
  5. 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)

 

하위 패키지 버전 결정 방식

패키지를 설치할 때 그 패키지가 필요로 하는 하위 패키지의 버전은 어떻게 결정될까?

의존성 해결 과정

  1. 의존성 트리 구성: 각 패키지가 필요로 하는 모든 하위 패키지를 재귀적으로 탐색
  2. 버전 제약 조건 수집: 모든 패키지의 버전 요구사항 수집
  3. 최적 버전 계산: 모든 제약 조건을 만족하는 각 패키지의 버전 조합 찾기

패키지 매니저별 동작 차이

  • 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. 패키지 업데이트
    • 충돌하는 패키지의 최신 버전으로 업데이트
    • 최신 버전에서는 종종 호환성 문제가 해결됨
  2. 버전 제약 조건 완화
    • 엄격한 버전 핀 대신 범위 지정 (예: ==1.0 → >=1.0,<2.0)
  3. 가상환경 분리
    • 호환되지 않는 의존성이 있는 경우 별도의 가상환경 사용
  4. 의존성 오버라이드
    • 일부 도구(Poetry, PDM)에서는 특정 패키지 버전을 명시적으로 오버라이드 가능
    # poetry.toml 예시
    [tool.poetry.dependencies]
    package-c = "1.5"  # A와 B 모두 호환되는 버전으로 강제
    
    # pyproject.toml (PDM) 예시
    [tool.pdm.overrides]
    package-c = "1.5"
    
  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 파일을 적절히 활용하면 개발 과정이 더 원활해지고, "내 컴퓨터에서는 잘 돌아가는데?" 같은 문제를 피할 수 있다.

파이썬 백엔드 개발을 시작하는 분들께는 다음을 권장한다:

  1. 개인 프로젝트: 최소한 requirements.txt는 관리할 것.
  2. 팀 프로젝트: Poetry나 PDM 같은 현대적 도구로 lock 파일까지 관리할 것.
  3. 버전 관리: 의존성 파일과 lock 파일 모두 Git에 포함할 것.
반응형