우리팀에서 사용되는 일부 서비스 로직에서는 평일/휴일 구분에 따라서 상이하게 동작하는 로직이 존재한다.

 

평일/휴일 구분에 따라 이벤트가 다르게 발생하는데, 기존 서비스 로직은 workalendar 라는 패키지를 통해 평일/휴일을 구분하게끔 설계되었었다.

 

여기서 해당 패키지의 문제점은 "사전에 정해진 규칙과 패턴으로 휴일을 계산하는 방법"을 사용한다

 

즉 아래와 같은 고정 규칙에 대해서만 구분할 수 있다.

 

  • 매년 반복되는 공휴일 (설날, 추석 등)
  • 기본 대체공휴일 규칙 (주말과 겹칠 때)

 

 

=> 아니 고정된 규칙이 변하지 않는 이상 패키지에서 구분해주는 휴일이 잘못된게 아닌데 뭐가 문제인거냐?!

 

패키지에서 구분해주는 휴일이 잘못된 것이라는 말이 아닌 갑작스럽게 발생하는 대체 공휴일에 대한 정보를 제공해주지 않는 것이 문제

 

  • 정부가 임시로 선언하는 특별 대체공휴일
  • 갑작스러운 정책 변경
  • 특별한 상황 (코로나19, 특별기념일 등)

 

즉 갑작스럽게 발생하는 대체 공휴일은 휴일이 아닌 평일로 구분되기 때문에 서비스 로직에서 한번씩 대체 공휴일임에도 불구하고 평일처럼 동작한다는 오류 리포트를 보고 받은 케이스가 한번씩 있었다.

 

이 문제가 서비스에서 제공하는 비즈니스에서 얼마나 치명적인 부분으로 작용하는지에 따라서 그대로 쓰는 방법을 선택하거나 or 내가 하는 방법처럼 보완하는 방법을 사용하면 된다.

 

우리 서비스에서는 현장에 방문하는 인원들의 출동 여부가 결정되기 때문에 1에 1~2번만 발생하더라도 치명적으로 작용한다.

 

그래서 나는 아래와 같은 방법으로 대체 공휴일 문제를 해결했다.

  • 기존 workalendar 의존성 제거, 캘린더 데이터 DB화 + 공공 API 데이터를 활용한 추가적인 대체 공휴일 정보 업데이트

=> 오 그러면 이제 근본적인 원인이 해결된것 아닌가요? 

 

내가 제시한 방법으로 근본적인 원인을 해결한것이 맞다.

 

하지만 새로운 서비스를 개발하는 과정에서 캘린더 데이터가 필요한 경우 캘린더 데이터를 DB화 + 공공 API를 통한 주기적인 업데이트 구조를 모두 똑같이 적용해야했다.

  • 기존 서비스에서 API를 통해서 받는 방법도 있었으나, 서비스 간의 의존성을 만드는 방법은 최악의 방법이기 때문에 고려하지 않았다.

 

A, B, C 서비스가 있다고 가정할때 서비스마다 각자 캘린더 데이터가 필요한 상황이 오게 된다면 캘린더 데이터 DB화 작업을 총 3번 진행하게 된다.

 

캘린더 데이터에 대한 DB를 매번 구성하고 최신화 하는 로직을 적용하는 부분을 서비스마다 해야한다면 오히려 리소스 낭비라고 생각한다.

 

=> 아니 그러면 공통 기능을 담당하는 서비스를 따로 두면 되는것 아닙니까?!

 

공통 기능을 담당하는 서비스를 따로 두는것은 가장 현명한 방법이 맞지만, 우리팀의 한정적인 리소스를 고려하면 어려운 상황이다.

  • 공통 기능 서비스 개발 인력 및 시간 + 관리 포인트 증가
  • 캘린더 기능이 공통 기능 부분으로 들어갈만한 부분인가? ( 평일/휴일만 구분 하는 용도로 사용되므로)

그래서 공통 기능 서비스를 개발할 수 없는 상황 +  관리 포인트까지 늘리고 싶지 않은 상황이라면 어떤 방법이 있을지 고민했다.

 

그렇게 고민하다가 내가 생각해낸 해답은 "workalender 같은 패키지를 직접 만들어보자" 였다.

 

나에게는 PyPI를 통한 오픈소스 프로젝트 출시 경험은 없었지만, 과정을 확인해보니 만들기가 어렵지 않다고 판단했다.

 

다음과 같은 과정으로 패키지를 만들고 출시하게 되었다.

 

1. GitHub 레포지토리 생성 및 Public 세팅

2. 패키지 네이밍 선정

3. 포맷터, 린트, pyproject, 디렉토리 구성 등 프로젝트의 전반적인 설정

4. 편의성 기능 개발 및 캘린더 데이터 내재화 작업

5. 테스트 코드 작성 및 자동 테스트를 위한 Codecov 연동 및 Actions Workflow 작성

6. 패키지 설명 및 관련 내용 작성 (README.md)

7. Test PyPI 선 출시 진행

8. Test PyPI 확인 및 PyPI 최초 릴리스 버전 출시 (1.0.0)


과정에 대한 내용들을 대부분 생략하였기에 별거 없다고 느껴질 수 있다. (정말 별거 없다고 느낄수도 있지만, 생각보다 손이 많이 가는 작업들이 많았다.)

 

패키지에 대한 정보가 궁금하시다면 아래 링크를 확인하시면 됩니다.

이제 "pip install your-package" 명령어만으로 전 세계 누구나 당신의 코드를 사용할 수 있습니다. 멋지지 않나요?

 

여러분의 첫 패키지 출시를 응원합니다! 🚀

 

 

저의 부족한 글에 관심을 가지고 읽어주셔서 정말 감사합니다. 

마침

Docker 컨테이너에서 Python 언어를 기반으로 프로젝트를 진행하다 보면 항상 모든 Python 개발자가 똑같이 겪는 문제가 있다.

 

그것은 바로 requirements.txt로 패키지를 새롭게 설치할 때마다 기다려야 하는 그 지루한 시간이다.

 

도커 컨테이너 기반의 환경에서 requirements.txt 내의 패키지가 추가/삭제 등이 되는 과정에서 컨테이너를 리빌드 하는 과정에 항상 패키지를 인스톨하는 과정이 싫어서 직접 커맨드로 설치하고 추가하는 일이 잦았다. -> 좋지 않은 습관이다.

 

반복되는 시간이 답답해서 Poetry 같은 패키지 도구를 써볼까도 고민했었지만 컨테이너 환경에서 쓰기 썩 좋지는 않다고 생각되었기에 도입을 망설이고 있었다.

 

그러다가 최근에 Rust 언어로 개발된 파이썬 패키지 및 프로젝트 관리 도구가 있다는 이야기를 들었다!

해당 도구의 이름은 바로 uv 이다.

  • uv는 기존의 pip, venv, pyenv, poetry 등과 유사한 기능을 제공하지만, rust로 작성되어서 속도가 매우 빠르다고 설명 되어있다.
  • Link : https://docs.astral.sh/uv/pip/

패키지 관리 도구 없이 requirements.txt에 명시된 패키지를 설치하는 경우 : 약 30초

uv 도구를 활용해 requirements.txt에 명시된 패키지를 설치하는 경우 : 6초

=> 어? 제목에는 10배 이상 시간을 단축한다면서 5배밖에 단축이 안되는데요?! 라고 보는 분들이 이야기 할 수 있다.

그래서 현재 팀에서 서비스 개발 시 사용된 requirements.txt로 비교해보려고 한다.

requirements.txt만 직접 설치하는 경우

uv 도구를 통해 requirements.txt 파일에 동봉된 패키지를 설치하는 경우

직접 설치한 시간을 70초로 반올림 , uv 도구를 통해 설치한 시간을 12초로 반올림 했을때 약 5.8배 가량 시간이 단축된것을 알 수 있다.

=> 여전히 10배 이상 시간 차이가 안나잖아요!!

저는 거짓말을 하지 않았습니다. (해당 도구의 소개 페이지에 적힌 내용대로 전달했을 뿐이에요)

 

5배가 빠르더라도 충분히 여러분들의 시간을 단축시켜줄 수 있을거라고 생각합니다.

 

대신 제가 dockerfile에서 uv를 사용하기 위해 사용된 코드를 공유드립니다.


COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

RUN uv pip install --system -r requirements.txt

 

저의 부족한 글이 도움이 되셨다면 감사합니다.

 

마침

+ Recent posts