이번엔 의존성 관리 도구를 결정하자. pip, npm, yarn, gem, maven, gradle 등과 같은 의존성 관리/빌드 도구를 써본 적 없다면 이해하기 어려울 수 있으니 의존성 관리 도구(Dependency Manager)라는 글을 읽어보자. 프로젝트 한두번 하면서 의존성 관리를 해 본 경험이 있다면 더욱 좋다.

도입 이유

의존성 관리 도구

소프트웨어 어플리케이션 개발에는 대부분 라이브러리가 필요하다. 언어 차원에서 지원되는(built-in) 것일 수도 있고, 우리가 사용하기로 한 Sanic처럼 외부 라이브러리 저장소에 의존하는 것일 수도 있다. 프로젝트가 어떤 외부 라이브러리를 사용하고 있는지를 별도로 관리하는 것의존성 관리라고 한다. 프로젝트가 사용하고 있는 외부 라이브러리들을 남들이 알도록 하는 것이 기본적인 목표인데, 이런 의존성 관리가 중요한 이유는 다음과 같다.

  • 먼저, 언어 차원에서 지원되는 라이브러리는 이미 다들 설치되어 있으니 따로 관리할 필요가 없다.
  • 백엔드 팀에서 함께하는 타 개발자의 입장에서 생각해 보자. 의존성이 제대로 설치되어 있지 않으면 어플리케이션을 실행해볼 수 없다. 혼자 개발하는 입장이라면 그냥 필요한 라이브러리들을 컴퓨터에 미리 설치해 두기만 하면 되겠지만, 협업이 힘들어지는 것이 문제다.
  • 오픈 소스로 관리되는 라이브러리의 소스 코드를 그냥 그대로 붙여넣거나, 따로 무슨무슨 라이브러리 쓴다고 문서화해둬도 되기야 하겠지만, 의존성의 의존성과 같은 재귀 의존 현상라이브러리 각각의 버전 업데이트 대응을 별도의 도구 없이 해결하기엔 너무 낭비다. 그 예로 Sanic은 httptools, websockets, multidict 등의 외부 의존성을 가지고 있다. 그리고 라이브러리 한 20개 쓰고 있는 상황에서, 버전 맞춰서 하나하나 설치하는 것도 귀찮은 일이다.
  • 배포 과정에서 필요하다. 예를 들어 테스트와 같은 배포 전처리를 위해 어플리케이션의 의존성들을 모두 다운로드해야 하고, 빌드/패키징 등과 같이 컴파일이 들어가는 과정에서 항상 필요하다.

이름은 거창하지만 의존성 관리 도구들이 자체적으로 많은 부분을 도와주기에, 우리에게 보여지는 겉모습 자체는 별 거 없다. 대부분 어떤 라이브러리의 무슨 버전을 쓸 지 목록화시킨 파일로서 의존성을 관리한다. 아래는 차례대로 Pythonrequirements.txt, JavaScriptpackage-lock.json, RubyGemfile 예제다.

aiohttp==3.4.4
async-timeout==3.0.1
beautifulsoup4==4.6.3
Flask==1.0.2
Flask-Cors==3.0.7
Flask-JWT-Extended==3.13.1
Flask-RESTful==0.3.6
influxdb==5.2.0
jsonschema==2.6.0
mongoengine==0.16.1
multidict==4.5.0
nose==1.3.7
openpyxl==2.5.10
pymongo==3.7.2
redis==3.0.1
Werkzeug==0.14.1
body-parser@1.18.2:
  version "1.18.2"
  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454"
  dependencies:
    bytes "3.0.0"
    content-type "~1.0.4"
    debug "2.6.9"

express@^4.15.3:
  version "4.16.2"
  resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"
  dependencies:
    accepts "~1.3.4"
    array-flatten "1.1.1"
    body-parser "1.18.2"
    content-disposition "0.5.2"
    content-type "~1.0.4"
    cookie "0.3.1"
    cookie-signature "1.0.6"

fresh@0.5.2:
  version "0.5.2"
  resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"

type-is@~1.6.15:
  version "1.6.15"
  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
  dependencies:
    media-typer "0.3.0"
    mime-types "~2.1.15"
source 'https://rubygems.org'

gem 'sinatra'
gem 'httparty'
gem 'shopify_api'
gem 'dotenv'

의사결정

의존성 관리 도구

선택지

  • pip와 requirements.txt
  • pipenv

의사결정

pipenv를 선택하겠다. 그 이유는,

  • Python은 일반적으로 가상 환경(virtual environment)을 통해 독립된 Python 실행 환경을 구성하게 되는데, pipenv는 가상 환경 구성의존성 관리한번에 해결해주기 때문이다. JavaScript를 해봤다면, npm을 떠올리면 된다.

준비

pipenv란 무엇인가Pipenv으로 Python 프로젝트 관리하기라는 글로 pipenv에 입문하자.

작업

의존성 관리 시작하기

pipenv를 통해 프로젝트 디렉토리에 pipenv를 초기화하고, 가상 환경에 들어가 Sanic을 설치한 후 lock하자.

$ pipenv install
$ pipenv shell
$ pipenv install sanic

lock 직후의 스냅샷