Skip to content

Latest commit

 

History

History
583 lines (411 loc) · 35.1 KB

script.md

File metadata and controls

583 lines (411 loc) · 35.1 KB

발표 대본

안녕하세요, [파이썬 대패키지 시대, 텍스트파일 하나만 믿어도 정말 괜찮은걸까] 발표를 맡게 된 강민철이라고 합니다. 이번에 저는 기존 pip를 이용한 파이썬 패키지 관리 컨벤션이 갖고 있는 문제점과 그를 대체할 수 있는 다양한 패키지 의존성 관리자에 대한 소개 및 비교분석 결과를 발표로 준비하게 되었습니다.

본격적인 발표를 진행하기에 앞서 간략하게 저의 소개를 하자면, 저는 오픈소스컨설팅이라는 회사에서 근무하는 시스템 엔지니어이자, 온오프라인 프로그래밍 교육을 하고 있는 강사입니다. 또한 제가 배울 수 있는 것들은 모두 다 배우고 싶어하는 욕심많은 학생이기도 하고, 취미로 오픈소스에 컨트리뷰션을 하기도 합니다.

자, 그럼 원할하게 발표 주제에 접근하기 위해 꼭 필요한 배경지식들을 빠르게 설명해드리도록 하겠습니다. 우선 모듈/패키지/라이브러리가 무엇인지, 그리고 기존 패키지 인스톨러인 pip에 대해 설명해드릴 예정이구요, 그리고 의존성 관리란 무엇이며 왜 필요한지 말씀드린 뒤에, 파이썬과 옆동네 자바스크립트의 의존성 관리를 비교해보도록 하겠습니다.

우선 모듈은 그냥 파이썬으로 정의된 파일입니다. 실행가능한 파이썬 파일을 모듈이라고 보시면 됩니다.

그리고 패키지는 모듈의 집합이라고 보시면 되는데, 조금 더 자세하게는 파이썬 코드 내에서 “쩜 모듈이름“ 으로서 그 모듈 속 내용에 접근할 수 있게 하는 namespace를 패키지라고 부릅니다.

이번 발표에서는 프로젝트를 이루는 단위, 즉, 프로젝트를 완성하기 위해 사용하는 코드 뭉치 및 모듈의 집합을 통틀어 편의상 “패키지”라고 지칭할 예정입니다.

그리고 마지막으로 라이브러리는 쓸 만한 기능들을 미리 모듈/패키지로 만들어 놓은 것, 즉, 미리 준비된 모듈 및 패키지를 라이브러리라고 합니다.

파이썬이 준비해둔 라이브러리에는 Python Standard Library, 즉 표준 라이브러리와 , 지금 이 순간에도 수많은 파이써니스타들이 배포하고, 또 다운로드 받을 수 있는 패키지 저장소인 Python Package Index (PyPI) 가 제공하는 라이브러리가 있습니다. 이 Pypi에는 방대한 양의 패키지가 존재하고, 또 실시간으로 업데이트되고 있는 만큼, 이 패키지들을 설치하고, 삭제하고, 또 현재 설치된 패키지 목록을 조회하는 등 패키지를 관리해주는 툴도 있어야될겁니다. 그쵸?

파이썬에서는 바로 이 pip라는 툴이 파이썬의 패키지/라이브러리를 관리해준다고 보시면 됩니다.

예컨데 $pip install 패키지 이름 명령어를 이용한다면 Pip는 PyPl에서 해당하는 패키지를 자동으로 찾아주고, 다룬로드해주고, 설치도 진행해줍니다.

뭐 원하는 특정 버전을 지정해서 설치할 수도 있구요, 반대로 설치된 패키지를 제거할 수도 있구요, 이미 설치된 패키지를 최신 버전으로 업그레이드도 할 수 있습니다. 이렇게, pip는 패키지들을 관리하는 다양한 명령어들을 제공하는데요,

그 중에서 이 명령어가 이번 발표를 이해하시는 데에 있어서 좀 중요한 역할을 합니다, 이 Pip freeze 명령어는 현재 프로젝트 환경에서 설치된 모든 패키지의 이름 및 버전 정보를 출력해주는 명령어입니다. 예를 들면, 이렇게 말이죠.

자, 그럼 의존성 관리는 뭘까요? (이미 아시는 분들은 조금만 더 기다려주시길 바라겠습니다…^^) 의존성 관리는,

지금 이 프로젝트 환경에서 어떤 버전의, 어떤 패키지가 쓰였니? 어떤 버전의, 어떤 패키지가 쓰일 수 있니? 를 관리하는 것을 말합니다.

다시말해, 프로젝트가 어떤 외부 라이브러리를 쓰고 있는지를 따로 관리하는 것을 의존성 관리라 합니다.

이 의존성관리는 프로젝트의 흥망에 직접적으로 영향을 줄 수 있을 만큼, 개발을 하는데에 있어서 매우 중요한 요소인데요, 이게 정확하게 왜 중요할까요?

예를 들어서, 제가 프로젝트를 막 만들고 있는데, 제 프로젝트에 꼭 필요한 패키지인 <파이콘 코리아>라는 패키지 하나를 설치했다고 가정해보죠;

그리고 이 <파이콘 코리아>패키지는 A, B, C라는 외부 모듈/혹은 패키지로 이루어져 있고,

A 라는 모듈(혹은 패키지)에는 A’ 이라는 다른 외부 모듈 혹은 패키지가 쓰인다고 가정해봅시다

자 이런 상황에서, 내 프로젝트에는 파이콘 코리아 패키지가 꼭 필요한데, 그럼 당연히 제 프로젝트를 사용할 미래의 사용자들은 그때그때 제 프로젝트에서 꼭 사용하는 파이콘 코리아 패키지를 그 때 그 때 설치해줘야겠죠?

근데 이때, A’ 모듈 혹은 패키지가 갑자기 버전이 바뀌었다고 가정해봅시다. 이는 A’을 이루는 코드가 바뀌었음을 의미하겠죠?

근데 이 A’의 새 버전이, A에까지 영향을 끼친다면 어떡할까요? 좀 안좋은 사례이긴하지만, A’의 패치로 인해 A도 기존 버전으로는 동작이 안되는 경우도 있을 겁니다. A도 덩달아 패치가 필요해지는 거죠.

그렇게 되면 당연히 제 프로젝트는 영향을 받겠죠? 옛날 버전의 A를 상정하고 만든 프로젝트인데, A’ 때문에 A가 변해버렸으니 만약 버전을 고려하지 않는다면, 버전 때문에 설치가 제대로 안되는 이용자들도 분명 있을 겁니다. 그쵸?

음 그럼 아예 이런 방법은 어떨까요? 내 프로젝트에 쓰이는 특정 버전의 의존성 모듈 A B C A’ 모두 다 내 프로젝트 안에 소스코드로 박제해버리는 거에요. 어떨거 같으세요?

코드가 돌아가기야 돌아가겠지만 당연히 문제가 생기겠죠? 애초에 프로젝트에 실을 수 없는 코드도 있을 뿐더러,

실을 수 있다고 해도 꼬리에 꼬리를 무는 패키지들의 코드 때문에 프로젝트 자체도 굉장히 무거워질겁니다.

또 만일에 A’ 이나 A의 업데이트의 이유가 보안상의 취약점 때문이었다면 내 프로젝트는 보안에 취약한 구버전을 사용하는 꼴이 되기도 쉽구요.

이렇듯, 의존성 관리가 제대로 안된다면 실컷 다 만들어 놓은 프로젝트인데, 이 광활한 우주에서 내 컴퓨터에서만 동작하는 프로그램을 만드는 대참사를 일으킬 수도 있습니다.

그럼 지금까지 파이썬에서는 의존성관리를 어떻게 해오고 있었는지 한 번 알아볼까요? 가장 유명하고 대중적인 방법은 이 명령어를 이용하는 방법입니다.

Pip freeze는 아까 말씀드렸듯이 현재 내 프로젝트 환경에 설치된 모든 패키지의 이름과 버전을 출력해줘! 하는 명령어구요,

이 명령어의 결과를 어디에 기록하길 바라냐면 Requirements.txt 라는 텍스트 파일에 기록하길 바란다! 라는 명령어라고 보시면 됩니다.

즉, 이 명령어를 수행하면 pip freeze 명령어의 결과가 requriemrets.txt 파일 안에 자동으로 담기게 될거에요

그리고 이렇게 만들어진 패키지와 버전에 대한 정보를 담은 requirements 파일은 프로젝트 환경이 아닌 다른 환경, 예컨데 다른 유저가 사용하는 환경에서 이런 명령어로 설치할 수 있습니다.

“저 패키지를 설치할건데요, 이 파일에 내용에 맞게 설치할거에요“ 라는 뜻이에요. 그럼 이 파일에 담긴 이름, 그리고 버전에 맞는 패키지들이 자동으로 깔리겠죠?

즉, 지금까지 파이썬에서의 의존성 관리는 프로젝트 수행 환경에서 사용된 패키지와 버전들을 모조리 기록한 requirements.txt 파일을 만들고. 또다른 환경에서 그 requirements 파일을 가지고 있는 그대로 설치하는, 이러한 방식으로 진행되곤 했습니다.

이는 꽤나 간편하고 대중적인 방법입니다.
심심해서 파이콘 코리아 공식 홈페이지는 어떻게 의존성을 관리하는지 찾아봤는데

여기도 requirements를 사용하더라구요.. 명령어 한 번으로 패키지 이름과 버전 정보가 싹다 담기니까 꽤나 간편한 방법이기도 합니다.

하지만 제 발표 제목을 보시면 아시겠지만 저는 이번에 이렇게 pip를 이용해 패키지 관리에 하는 방식에 대한 문제점을 짚고, 또 대안을 제시할 예정입니다.

근데 그 전에, 문제의식에 대해 다루기 전에 , 옆동네 자바스크립트에서는 어떻게 패키지의존성을 관리하는지 잠깐 보고올까요?

왜 갑자기 파이콘에서 뜬금없이 자바스크립트 얘기세요? 하실 수도 있겠지만 이 자바스크립트가 패키지 관리를 기가 막히게 하거든요.. 참고로 npm 과 yarn은 파이썬의 pip 와 같은, 대표적인 JS의 패키지 관리자/관리툴입니다..

우선 자바스크립트, 대표적으로 npm에서는 이 세 녀석들로 패키지의 의존성을 관리합니다. Pacskage.json package-lock.json, node_modeules 디렉터리

우선 이 node_modules는 Npm으로 다운로드한 외부 라이브러리들이 담기는 폴더입니다. Npm으로 외부에서부터 패키지들을 다운로드하시면 여기에 담긴다고 보시면 되요.

다음은 이 package.json 파일입니다. 이 파일은 프로젝트 시작할 때 쓰는 npm init을 치면 자동으로 생성되는, 프로젝트 정보와 의존성을 관리해주는 문서입니다 잘 보시면 이 패키지의 이름, 버전, 섥명, 저장소, 키워드, 라이선스 등등을 담고 있는 걸 알 수 있죠.

주목하실 점은 npm은 개발용 패키지와 배포용 패키지를 따로 관리할 수 있다는 점입니다.

왜 으레 프로젝트를 진행할 떄, 프로젝트 자체 개발을 위해 꼭 설치해야 하는 배포용 패키지, 그리고 디버깅, 테스트 처럼 개발 과정의 편의를 위해 설치하는 개발용 패키지는 다를 수 있지 않겠어요?

Npm은 이렇듯 배포용 패키지를 설치 및 관리하는 명령어와 개발용 패키지를 설치 및 관리하는 명령어가 구분되어 있습니다.

다음은 package-lock 파일입니다. 음 언뜻 보면 낯설 수도 있는 이 package-lock 파일도 굉장히 유용하고 필수적인 역할을 맡고 있는데요.

이 package-lock은 node_modeule 디렉터리나 Package.json 파일이 변경될 때마다 자동으로 생성되고, 업데이트되는 파일입니다.

다시말해서, node_modeules 디렉터리나 Package.json 파일이 변경될 때마다 그 순간의 snapshot을 저장하는 역할을 합니다.

즉, node_modeules 나 package.json의 순간을 저장해서 항상 동일한 모듈 트리의 생성을 보장해주는 녀석이라고 보시면 됩니다.

이렇게 package 파일에서는 해당 프로젝트 대한 정보와 설치된 패키지들의 의존성 정보들이 종류별로 담기고,

Package-lock 파일은 package와 node_module이 변경사항이 생길 때마다 Node_modules 디렉터리의 그 순간 순간의 스냅샷을 저장하기 때문에

Package 파일과 package-lock 파일만 git에 올리게 되면 항상 동일한 패키지 트리인 node_modules를 만들 수 있게 되는 겁니다.

자, 근데 개인적으로는 이런 자바스크립트의 패키지 의존성 관리를 보고 나니까 개인적으로 Pip 를 이용한 기존의 requirements.txt 방식에 문제의식이 느껴지더라구요.

구체적으로 어떤 문제들이 있을까요? 저는 다음과 같이 꼽았습니다. 이원화되지 않은 개발용 패키지, 배포용 패키지 의존관계 파악의 어려움 특정 패키지 버전 지정의 어려움 그리고 설치시 발생할 수 있는 문제

우선 개발용 패키지, 배포용 패키지가 이원화되어있질 않아서 생기는 문제점이 있습니다 아까 npm의 package.json에서 보여드렸듯이, 개발을 할 떄에 있어서 사용하는 패키지는 으레 개발용 패키지와 배포용 패키지가 구분되기 마련이잖아요?

만약 개발용 패키지가 배포용 패키지의 일부라고 가정한다면, 배포용 패키지를 이 명령어를 이용해서 한 번에 만든다고 쳐도, 나머지 개발용 패키지들은 직접 손으로 써가며 기록해야 한다는 불편함이 있습니다.

또 만일 개발용 패키지들의 종류 및 버전이 배포용 패키지들을 완전히 포함하고 있지 않을 때, 즉, 배포용 패키지로는 사용하지 않을 패키지가 개발용 패키지에 포함되어 있다면 더 관리가 귀찮아집니다.

이 때는 다음과 같이, 특정 디렉터리 하에 파일을 구분해놓으면 배포용, 개발용 패키지가 한 방에 설치야 되겠지만,

이 때는 개발용 패키지 의존성 관리 문서와 배포용 패키지 의존성 관리 문서를 모두 손으로 써가며 관리해야 하는 번거로움이 있을 겁니다.

Pip를 이용한 패키지 의존성 관리의 두 번째 문제는 의존관계 파악이 어렵다는 데에 있습니다. 일례로 만일 keras를 pip로 설치한 뒤에 pip freeze를 하면 다음과 같이 보이구요,

djangorestframework 을 설치하고 pip freeze를 하면 다음과 같이 보입니다.

어떤 패키지가 어떤 패키지에 의존적인지, 각자의 패키지는 무슨 관계이며 무슨 역할을 하는지, 딱 보면 전혀 감이 안오시죠?

더군다나 pip uninstall을 통해 특정 패키지를 삭제해도 이런 의존성 패키지까지는 삭제되지 않기 때문에 프로젝트가 진행되면 진행될 수록 패키지 의존관계 파악이 어려워질겁니다.

마지막으로, 설치시 발생하는 문제도 있을 수 있습니다. 즉 pip install –r requirements 명령어가 문제를 일으킬 수도 있습니다.

가상환경을 이용하지 않고 쌩으로 설치하게 될 경우, 만일 설치 환경에서 이미 설치한 패키지와 상충하는 경우에는 기존 환경에 영향을 끼칠 것이고,

애초에 특정 패키지 설치가 안되는 환경일 경우, 프로젝트 전체가 설치되지 않겠죠?

그래서 대부분 가상환경을 켜 둔 채 pip install을 진행할겁니다.

근데, 이럴 경우 통일되지 않은 패키지 관리자와 가상환경 때문에 바로바로 설치가 안되는 경우도 있더라구요,

예컨데 아나콘다 에서 지원하는 conda 패키지 관리자와 condaenv(conda 가상환경)은 Requirements.txt를 내보내고 설치하고 할 수는 있지만, 설치 과정에서 pip와 혼용이 안되거나 번거로운 작업을 거쳐야만 혼용이 가능했습니다.

즉, 항상 편리하고 안정적으로 동일한 패키지 설치를 보장하기 위해서는 패키지 관리자와 가상환경이 통일되어야 한다고 생각했습니다.

이러한 문제의식을 안은채, 더 나은 의존성 관리자를 찾기 위한 저의 여정이 시작되었습니다. 이제부터 하나씩 분석하고 살펴볼 대상은, pip-tools pipenv poetry 이 세 개입니다

이 pip-tools는 pip-compile과 pip-sync로 구성된 툴입니다,

이 Pip compile은 setup.py, requirements.in 등의 재료를 가지고 requirements.txt를 만들어내는 역할이구요, 그리고 pip-sync는 이렇게 만들어진 requirements.txt를 프로젝트에 직접 설치하고 반영하는 역할을 합니다.

이 그림을 보시면 좀 더 명확하게 이해가 되실텐데요, Requirements.in 혹은 개발용 dev-requirements.in을 pip-compile로 이런 파일들(Requirements.txt 혹은 개발용 dev-requirement.txt)을 만들어내면 이를 토대로 pip-sync를 통해 프로젝트에 반영하는 과정으로 의존성 관리가 이루어진다고 보시면 됩니다.

즉, 여기서는 Requirements.txt 혹은 개발용 dev-requirement.txt 가 Npm의 package-lock.json처럼 lock file의 역할을 수행한다고 볼 수 있겠죠?

그리고 npm을 쓸 때 그랬듯이 이 두개를 git과 같은 version control system에 올려두면 될겁니다.

실제 use case를 좀 보여드리자면 다음과 같이 requirements.in 안에 djangorestframework를 적어둔 다음 Pip-compile 명령어를 치게 되면 Requirements.txt. 파일이 자동으로 뿅 하고 생길 것이고

이 안에 Pip-compile 명령어를 친 순간의 djangorestframework 패키지와 버전, 그리고 의존성 패키지들의 정보들이 담기게 될 겁니다.

그리고 자세히 보면 주석으로 이 패키지가 어디 패키지에 의존된 패키지인지 자동으로 써지는다는 걸 알 수 있습니다.

참고로 pip-compile 명령어를 칠 때 특정 옵션을 주게 되면 Requirements.txt 안에 Npm의 package-lock.json이 그러하듯 해시값을 생성해주기도 합니다

그리고 pip-tools를 이용한다면 특정 패키지의 버전을 업그레이드 할 때 버전을 지정하기가 매우 쉬워집니다

전체 패키지를 업그레이드를 하고 싶을 때는 이렇게 Django는 최신으로, requirest는 2.0.0으로 업그레이드하고 싶을 때는 이렇게 그리고 django는 2 이하버전으로 업그레이드 한 값의 lock file을 requirements-django1.txt라는 이름의 파일에 담고 싶으면 이렇게 써 주기만 하면 됩니다.

Pip을 이용했더라면 이런 상황에서 명령어를 여러번 치거나 requirements.txt를 직접 수동으로 건드려줬어야 했을 겁니다.

그리고 이건 생성된 requirements.txt는 이렇게 pip-sync를 통해 실제 프로젝트에 반영할 수 있습니다.

특정 lock file을 프로젝트에 반영하고 싶을 때, 즉 이 경우에는 requirements-django1x.txt를 프로젝트에 반영하고 싶으시면 이렇게 파일 명만 적어주시면 보시는 것처럼 잘 반영이 됩니다.

이 pip-tools가 기존 pip 문제 해결에서 가지는 큰 의의는 lock file을 담당하는 requirements.txt를 자동으로 얻을 수 있다는 겁니다. 그렇기 때문에 당연히 개발환경의 재생산성이 어느정도 보장이 될거구요.

그리고 아까 말씀드렸던 것 처럼 설치/업그레이드할 때 특정 패키지의 버전 지정 편리해졌구요, requirements.txt에서 자동으로 생성되는 주석에 의존성 정보가 쓰이기 때문에 Package tracking이 어느정도는 가능해졌습니다.

자 근데, 사실 여기서 만족했어도 됐었는데,

그리고 저는 아직까지도 만약에 누군가 “최대한 가볍고 단순하게 파이썬 패키지 의존성 관리하는 방법이 뭐에요?” 라고 물어보신다면

Pip-tools라고 답할 의사도 있는데, 개인적으로 조금 제 개인적인 니즈와는 안맞는 지점들은 있더라구요

일단 이 pip-tools는 패키지 설치 기능은 없습니다.

그리고 여전히 패키지 관리자와 가상환경은 따로 놀기 때문에 패키지 관리자와 더불어 가상환경도 하나 껴야 되구요 만약 파이썬 버전별 management가 필요하시다면 pyvenv도 있으셔야겠죠?

그리고 무엇보다도, 이게 의존관계가 한 눈에 안들어옵니다. 주석으로 써 준다고는 하는데, 프로젝트가 커지고 패키지가 많아지니까 가독성이 영 좋지는 않더라구요

pip-tools 도 이걸 의식하고 있는지 공식 저장소 가 보면 의존성 그래프 가독성 높이려면 pipdeptree라는 패키지를 또 깔라고 안내하고 있기도 하구요

그러니까, pip-tools 너무 좋기는 한데, 의존성 관리 외에는 아무것도 안해준다는 느낌?이 들더라구요. 저는 패키지와 관련된 모든 것들을 알아서 해주는 툴, 즉, 올인원을 해줄 수 있는 패키지 관리자를 원했습니다.

그래서 다음으로 알아봤던 대안은 pipenv였습니다

이 pipenv의 동작 과정은 pipenv를 처음 사용했을 때 콘솔화면에서 찍히는 정보들을 읽어보면 이해가 잘 갑니다. (Pipenv가 워낙 친절하게 프린트를 찍어줘서요..)

예를 들어 pipenv라는 폴더를 만들고 그 안에서 pipenv 를 이용한 패키지 관리를 진행해본다고 가정해보죠

제가 지금 빨간색으로 친 pipenv install명령어는 “의존성 파일들에 적힌 내용대로 패키지를 설치해라!” 라는 명령어인데,

만약 프로젝트에서 처음으로 이 명령어를 치게되면 (지금 제가 빨간 하이라이트를 친 걸 보시면 알 수 있듯이) 가상환경이 특정 경로에 생성됩니다. 가상환경.

프로젝트마다 각기 다른 가상환경이 만들어지는데, 맨 아랫줄을 보시면 아시다시피 Pipenv shell 명령어를 통해 이 만들어진 가상환경을 실행할 수 있습니다.

그리고 만약 프로젝트 초기에 처음으로 pipenv install 명령어를 치게 되면 보시는 것처럼 가상환경뿐 아니라 이 Pipfile, 그리고 Pipfile.lock, 즉 lock file이 생성되게 됩니다.

Pipenv는 이 Pipfile과 Pipfile.lock으로 자체적으로 생성한 가상환경 하에서 패키지 의존성 관리를 진행한다고 보시면 됩니다.

짐작하시겠지만, 이 pipfile과 pipfile.lock은 npm에서 package.json, package-lock.json 역할을 수행합니다.

Pipenv은 패키지 설치 기능도 갖고 있는데요, Pipenv로 django를 이렇게 설치할 수 있습니다 django를 설치하게 되면 npm이 그러하듯 lock file이 업데이트 될 겁니다.

그리고 개발용 패키지도 쉽게 설치할 수 있습니다. Pipenv install에 dev 옵션을 주게 되면 개발용 패키지도 덩달아 설치가 되는데 이 경우 lock file에는 [dev-packages]라는 독립된 패키지 리스트들을 locking하게 됩니다.

배포용 패키지와 개발용 패키지를 각각 설치했을 때 Pipfile에도 이렇게 dev-packages Packages가 나뉘어서 명시된다는 걸 알 수 있구요

그리고 개인적으로 정말 좋았던 점은 드디어 패키지의 의존관계를 한 눈에 알 수 있는 그래프가 제공되었다는 점입니다. 보시면 아시겠지만 Django 라는 패키지에는 이런 패키지들이 종속되어 있고, 몇 버전이 필요하며, 현재 설치된 버전은 몇 버전인지까지 한 눈에 알 수 있죠.

이런 기본적인 기능들 이외에도, Pipenv run python 명령어를 이용해서 파이썬 모듈을 직접 실행시켜 볼 수도 있습니다. 예컨데 django로 웹 서버를 구동하려면 pipenv run python manage.py runserver로 실행시킬 수 있겠죠?

그리고 lock file을 업데이트 할 수 있는 lock 명령어도 있고 여러 파이썬이 이미 설치되어있거나, 혹은 pyenv를 사용중이라면 프로젝트 환경에서 사용할 특정 버전의 파이썬을 이렇게 지정할 수도 있습니다

지금까지의 말씀을 들어보셨다면 분명 공감하시겠지만, Pipenv는 분명 기존 pip가 가지고 있는, 제가 문제제기했던 문제점들을 해결해주었습니다.

Lockfile이 생겼기 떄문에 Pipfile과 pipfile.lock 두 파일을 버전관리시스템에 올리기만 하면 누가 어디서 clone을 받든 패키지 의존성이 어느정도 보장된 상태에서 사용할 수 있을 겁니다.

그리고 pip-tools와는 다르게 패키지의 설치와 관리, 가상환경 생성까지 모두 한 번에 수행해준다는 점에서 기존의 문제를 해결했다고 볼 수 있었습니다.

그리고 아까 보여드렸듯이 프로젝트마다 파이썬 버전을 지정하기가 쉬워졌고 개발용 배포용 패키지를 나누어 사용하기 편해졌습니다.

근데 이 pipenv도 여느 SW가 그렇듯 완벽하지는 않아서, 이런저런 논란, 비판점으로 인해 완벽하게 신뢰하기는 어렵지 않나? 하는 목소리도 있었습니다.

대표적인 예로 너무 늦은 릴리즈 주기가 있죠. 올해 릴리즈가 나오기는 했는데, Dependency resolution issue는 꾸준히 있어왔음에도 불구하고 2018년부터 올해까지 새 릴리즈가 없었으니 이용자들 입장에서는 “제대로 maintain 되는거 맞냐” 하는 의구심이 생겼던 거죠.

그리고 이건 조금 이따가 성능 분석 때 한번 더 다룰 예정인데요, 운영체제별로도 퍼포먼스가 조금씩 차이가 있습니다. 아예 pipenv 공식 저장소에 windows 가 우리한테는 first calss citizen이다! 라고 명확히 적어두었더라구요.

이런 시원섭섭한 상황에서, 최근에 pipenv의 경쟁자가 등장했습니다.

바로 poetry라는, 만들어진지 얼마 되지 않은 패키지 관리자인데요. 기능성으로만 놓고 봤을 때는 아까 언급해드렸던 pipenv의 기능성 + 알파 을 제공하는 패키지 관리자라고 보시면 됩니다.

이 poetry의 기본적인 use case도 빠르게 소개해 드리도록 할게요. 사용하는 주요 기능 자체는 pipenv와 비슷해서 빠르게 톺아보고 넘어가자면,

처음 프로젝트 환경에서 poetry init을 입력하게 되면 Pipenv에서 pipfile이라는 의존성 관리 문서가 생성되었듯 Poetry는 pyproject.toml이라는 의존성 관리 문서가 생성됩니다. 이 pyproject에 담기는 내용은 제가 하이라이트친 부분에 해당하구요

그리고 Pipenv와 비슷하게 poetry install 명령어를 치게 되면

가상환경가 더불어 poetry.lock 파일이 만들어지게 됩니다. Pipenv와 상당히 유사하죠?

그리고 그렇게 만들어진 가상환경을 실행시키는 명령어, 즉 activate 시키는 명령어는 Poetry shell입니다

개인적으로는 pipenv의 가상환경의 프롬프트는 가상환경을 켰을 때, 껐을 때 서로 큰 차이가 없어서 좀 헷갈리는 경우가 많았는데, Poetry는 가상환경을 activate하면 프롬프트가 달라져서 좀 더 편하더라구요. 뭔가 딱 새로운 환경에 들어갔다는 느낌도 들구요.

Poetry도 pipenv 와 마찬가지로 패키지를 설치할 수 있는 패키지 관리자 기능을 수행하는데요, 예를 들어 배포용으로 django를 설치하는 명령어는 다음과 같습니다. 이렇게 django를 add를 하게 되면 당연히 Lock file도 같이 업데이트가 될 겁니다.

그리고 이제는 어쩌면 당연하게도, 개발용 패키지를 구분해서 설치할 수도 있습니다 보시는 것처럼 --dev 옵션으로 패키지를 추가하면 배포와는 무관한 개발용 패키지가 잘 설치될거에요.

그리고 여기서부터 poetry의 쁠러스 알파에 해당하는 기능들인데요, 물론 다양한 기능들을 제공하지만 개인적으로 개발을 할 때 있어서 가장 고맙고 유용했던 기능들을 꼽아봤습니다. 일단 처음으로 package search 기능인데요,

이건 흥미롭게도 pip는 제공되지만 pipenv나 pip-tools는 제공되지 않은 기능입니다. 예를 들어 poetry search keras로 패키지를 검색하게 되면 거기에 매칭되는 패키지와 버전 그리고 간략한 설명까지 프린트되는 걸 확인할 수 있습니다.

이런 기능이 실제 프로젝트에서 특별히 더 유용하게 쓰이는 이유는 제가 발표 제목에도 적어두었듯이 바야흐로 파이썬 대패키지시대이기 때문입니다.

우리들이 필요한 패키지들을 모두 이름을 외우고 다닐 수 없을 거에요. 그리고 극히 일부의 패키지들을 쓰고 싶을 때 굳이 그걸 포함하는 패키지까지 받을 필요도 없을 거구요. 결국 이렇게 패키지를 search하고 조회하는 기능이 있어야 우리는 적재적소에 또 가볍게 원하는 패키지들을 받을 수 있을 겁니다.

그리고 개인적으로 꼽았을 때 가장 좋았던 건, Poetry의 친절한 인터페이스였습니다

예를 들어 poetry show, 혹은 show – tree 옵션으로 패키지들을 조회하면, 현재 프로젝트에 어떤 패키지가 어떤 버전으로 있고, 심지어 이 패키지가 어떤 기능을 하는지 종속관계별로 색깔로 표시해서 보여주더라구요

개인적으로 이런 유저 친화적인 인터페이스가 제가 딱 원했던 이상적인 패키지 매니저의 덕목 중 하나여서 정말 사막에서 오아시스를 찾았던 기분을 느꼈었습니다..

이 밖에도 poetry는 pipenv보다 훨씬 더 많은 기능들을 제공하는데요, 프로젝트의 필수적인 파일, 디렉터리 구조까지 다 세팅해주는 kickstart기능이나 빌드기능, 그리고 가장 큰 차별점으로 인정받고 있는 배포기능 등등 많은 기능들을 제공합니다.

때문에 poetry는 이런 다채로운 기능을 바탕으로, 기존에 제가 제기했던 문제, 즉 pip가 가지고 있는 문제를 해결합니다.

Lock file을 이용한 의존성 관리는 당연하구요, 패키지 설치/ 가상환경 / 의존성 관리 올인원 역할을 하는 것도 굉장히 고마운 부분이었죠.

그리고 pipenv처럼 python 버전 호환이 자유롭고 아까 말씀드린 것 처럼 배포, 검색, 의존성 그래프를 비롯한 친절한 인터페이스 등등

Poetry는 기존에 제가 문제제기했던 모든 문제를 해결해주는 강력한 패키지 매니저였습니다.

근데, 사실 이 발표의 결론은 원래 “여러분, 그래서 앞으로 poetry 쓰세요!” 가 결론이었습니다.

왜냐면 이 발표를 처음으로 준비했을 때가 3월달 4월달이었는데 저 때도 pipenv는 새 버전이 릴리즈가 없어서 저도 암묵적으로 maintain이 안되는 줄 알았거든요.

근데, 올해 갑자기 pipenv에서 두 개나 버전을 뿅뿅 내더라구요, 그리고 심지어 이번 릴리즈는 반응도 정말 좋았습니다.

그래서 결론을 조금 바꾸게 됐죠.

그래서, 어떤 방면에서는 뭐가 더 나은지, 그래서 어떤 니즈를 가질 경우 무엇을 써야 하는지 에 대한 답변을 드리는 걸로 결론이 바꾸었습니다.

그 결론을 도출하기 위해서, 지금까지 제가 제기했던 문제를 해결했던 앞선 두 가지 도구 Poetry와 pipenv를 기능 면, 관리 면, 그리고 성능 면에서 비교를 해보도록 하겠습니다.

일단 다채로운 기능은 poetry를 따라올 수 없습니다.

그리고 개인적으로 poetry의 기능성이 뛰어나다고 생각한 이유는, “뭐 하나만 걸려라”는 식으로 산발적인 기능들을 병렬적으로 추가한 게 아니라,

딱 패키지 혹은 프로젝트의 처음 탄생부터 배포까지 겪을 법한 일들을 돕기 위한 기능들이 주를 이루기 때문이에요. 아까 예시로 보여드린 kickstart, 검색, 배포 같은 기능도 이런 맥락이구요.

근데, 그래서 프로젝트의 발전상황은 어떠냐, 버그는 얼마나 있고 얼마나 빨리 고쳐지고 있느냐를 여쭤보신다면 또 상황이 다릅니다.

왜냐하면 poetry의 버그가 압도적으로 많아요. 워낙 신생이라서 그런 것도 있는 것 같구요, 역으로 기능이 워낙 많아서 그런 것도 있는 것 같습니다.

다음으로 성능 테스트입니다. 이 성능테스트와 관련해서는 드릴 말씀이 많은데, 이번 발표에서는 시간관계상 중요한 핵심 결론만 말씀드리겠습니다. 자세한 결과나 추가적인 설명 혹은 더 많은 실험들은 우측 하단 링크에 담겨드리겠습니다.

일단 pipenv와 poetry의 상황별 성능을 time을 이용해서 측정했는데, 기본적으로 Django djangorestframework 을 설치하고 개발용 패키지로 flake 어무해-debug-toolbar, pytest 를 설치하는 과정을 측정했습니다

그리고 이 패키지들을 Install 하고, dependency를 추가하고, lockin하고, uninstall하는 과정을 측정했습니다.

일단 여러 번의 실험을 다양한 환경에서 반복실행한 결과 공통적으로 install 을 할 때는 pipenv가 더 높은 속도를 보였구요 그 이외의 상황에서, 즉 Dependency를 추가하거나 특정 패키지를 uninstall하거나, locking할 때는 큰 폭으로 poetry가 우세했습니다.

근데 이 실험을 진행할 때 제가 리눅스 환경에서 두 번 실험을 했었거든요? Centos 7.7이랑 ubuntu 18.04에서 진행했었는데, 나중에 이 테스트를 윈도우에서 진행했을 때에는 이 차이의 폭이 그렇게 크지 않았습니다.

여러번 노트북을 달리해서 실험해봐도 같은 결과가 나오는 걸 보면, 확실히 pipenv는 windows에서 사용하기 적합한 툴인 것 같습니다.

운영체제에 따라 성능이 얼마나 차이가 나는지에 대해서도 테스트를 해보고 싶었는데, 동일하거나 비슷한 성능을 가진 맥북, 리눅스, 윈도우 컴퓨터를 각각 구하는게 아무래도 좀 어렵더라구요.

아마 컨퍼런스가 시작되고 이 발표를 여러분들이 보실 때 쯤에는 해당 테스트까지 완료한 내용을 하단 링크에 남겨두었을 겁니다. (약속할게요 :) )

아, 그리고 마지막으로 pipenv가 올해 릴리즈가 있었다라고 말씀드렸잖아요? Pipenv의 최신 버전으로 테스트를 해보면 , 이전 버전에 비해 성능이 눈에 띄게 좋아졌더라구요. 당연한 얘기일 순 있겠지만 버전에 따라서도 성능 개선이 있었습니다.

자, 그래서 길었던 저의 이야기의 결론은 다음과 같습니다. 만일 pip를 이용한 패키지 관리의 문제점에 공감하고 있는 어떤 사람이 와서,

저는 배포나 package tracking 아직은 큰 관심 없고, 딱히 가상환경을 따로 쓰거나 python 버전별로 개발할 필요 없어요. 동일한 프로젝트 환경 생성만 보장되면 돼요

라고 물어보신다면

저는 가볍게 pip-tools 쓰시고, requirements.in 혹은 setup.py를 requirements.txt랑 같이 commit하세요 라고 답변할 거구요

또 만약에 누군가가

저는 Package dependency tracking이 중요해요. 동일한 프로젝트 환경 생성은 당연히 중요하구요, 가상환경 필요하고 dependeny resolving issue는 만나고 싶지 않네요 무난하고 할거 다 해주는 패키지 관리자를 원해요

라는 니즈를 갖고 계시다면 저는 그래도 아직까지는 안정적이고 버그가 비교적 적은 pipenv를 쓰세요 좋은게 좋은, 무난한 pipenv도 좋아요~ 라고 말씀드릴겁니다.

그리고 마지막으로 누군가 프로젝트의 처음부터 끝까지 편리하게 케어받을 수 있는 패키지 의존성 매니저가 있나요? 라고 물어본다면 전 poetry 쓰시라고 말씀드릴 것 같습니다.

끝으로 제 사견을 마지막으로 본 발표를 마치자면 저는 진심으로 pipenv 올해 릴리즈에 대한 감사한 마음을 가지고 있습니다.. 만 poetry에 대한 지속적인 관심과 contribution을 저와 함께 이어나가고 싶은 파이써니스타들이 정말 많아진다면 다채로운 기능을 갖춘, 또 한편으로는 안정적인 패키지 관리자가 하나 만들어지지 않을까? 하는 행복한 상상을 해보기도 했습니다.

이상으로 발표 마치겠습니다 들어주셔서 감사합니다.