팀원들과 프로젝트를 진행할 때 혹은 협업이 필요하여 작업을 할 때,
- 가상환경 셋팅하고 진행해주세요.
- xxx.py 파일로 실행 해주시면 됩니다.
등의 반복되는 말의 사용으로 피곤함을 느껴보신 적 많으실텐데요.
이번 시간에는 반복되고 복잡한 빌드과정을 쉽게 자동화 해줄 수 있는 방식에 대해 설명드리고자 합니다.
실제 저희 팀에서도 협업을 하며 테스트를 할 때, 신입분이 들어오시거나 갑자기 프로젝트에 새로 투입되신 분들에게 코드 설명을 할 때 등 반복적으로 설명하는 불필요한 작업에 대해 피로도를 느끼고 있었는데요.
특히, 사소한 빌드 실수로 인해 코드가 실행되지 않는다, 설치가 이상하다 등의 휴먼에러로 인해 발생하는 사건들이 종종 있으시더라구요.
반복되는 작업과 휴먼에러로 인해 협업에 불필요한 차질이 생기는 것을 개선하고자 이번 글을 작성하게 되었는데요.
비슷한 고민을 가지고 계셨던 분이 있으시다면 이번 기회에 도입해보시면 효과적이란 걸 몸소 느끼실 수 있습니다!!
그럼 시작하겠습니다 :)
다들 Makefile에 대해 들어보셨나요?
보통 C언어를 사용하시는 분들에게는 익숙하실 수 있는 용어일 텐데요.
이번 시간에는 Makefile이 무엇인지, 왜 필요한 것인지, 무엇에(?) 좋은지에 대해 알아보고자 합니다!
다만, 일반적으로 사용되는 C언어 에서의 Makefile 용도보다
실제 협업 및 python을 사용할 때 도움이 되는 방향으로 정리해 볼 예정입니다.
1. Make 란
: make는
소프트웨어 개발을 위해 유닉스 기반 운영체제에서 사용되는 프로그램 빌드 도구입니다.
2. Makefile 이란
: 유닉스 기반 운영체제와 함께 제공되는 make 시스템을 통해 make 문법에 맞춰 파일에 작성하는 문서입니다.
3. Makefile 사용하는 이유
: Makefile
은 매번 기억하기 어렵고 복잡한 빌드 단계를 관리하기 때문에 궁극적으로는 복잡성을 줄여줍니다.
Makefile
은 복잡한 빌드 의존관계를 작성해 두고 매번 빌드 스크립트를 다시 작성하는 일을 자동화하기 위해 만들어졌습니다.- c와 같은 컴파일 언어에서는 컴파일과 링크의 순서가 중요하지만, 파이썬은 스크립트 언어이기 때문에 복잡한 빌드과정이 필요 없습니다. 하지만 스크립트 단순화 목적으로 사용하기 좋으므로 사용해 보시길 추천드립니다!!
Makefile
을 사용하지 않고 수동으로 입력하다 보면 오류가 발생하기 쉬울 뿐 아니라 프로젝트 수명 내내 반복적으로 동일한 명령을 입력해야 하므로 상당히 번거로운 부분이 많아집니다.
4. Makefile 문법
<Target> : <Dependencies>
<Recipe>
Target
: 빌드 대상 이름을 의미.- 최종적으로 생성하는 파일명을 작성한다.
Dependencies
: 빌드 대상이 의존하는 Target이나 파일 목록.- 여기에 나열된 대상들을 먼저 만들고 Recipe의 명령어를 실행한다.
Recipe
: 빌드 대상을 생성하는 명령.- 여러 줄로 작성할 수 있고, 각 줄 시작에 반드시 Tab 문자로 Indent 가 삽입되어야 한다.
@
: shell 명령어를 실행하되, 실행하는 명령어를 출력하지 않을 때 사용.@
사용하지 않을 때@
사용할 때
5. 변수 선언
: Make에서 일반적으로 변수를 선언하는 방법은 2가지가 있습니다.
💡변수를 사용하면 Makefile을 보다 깔끔하고 확장성 있게 작성이 가능
💡변수 선언 및 사용법은 Bash Shell Script와 동일
5.1. 일반적인 변수 선언 방법
5.1.1. Recursively expanded variable
: =
기호를 사용해서 변수에 값을 할당하는 방법
- 변수에 다른 변수를 참조하고 있다면, 다른 변수가 참조하고 있는 값을 참조합니다.
ENV_NAME = venv
TEST = $(ENV_NAME)
VAR = $(TEST)
echo_test:
@echo $(VAR)
특징
- 장점
- 여러 변수를 사용해서 make를 작성할 수 있다.
ENV_ACTIVATE = . $(ENV_NAME)/bin/activate
- 여러 변수를 사용해서 make를 작성할 수 있다.
- 단점
- 재귀로 변수를 재정의 할 수 없다.
ENV_NAME = $(ENV_NAME)-test
- 위와 같이 선언할 경우 무한 반복에 빠지기 때문에 에러가 발생합니다.
- 재귀로 변수를 재정의 할 수 없다.
5.1.2. Simply expanded variable
: :=
기호를 이용해서 변수에 값을 할당하는 방법
- 재귀적 확장 변수의 단점을 보완하기 위한 변수
=
와는 달리 재귀적으로 작동하지 않으며, 변수에 대입된 값을 그대로 출력한다.
ENV_NAME = venv
ENV_NAME := $(ENV_NAME)-test
echo_test:
@echo $(ENV_NAME)
ENV_NAME
변수를 스스로 참조하는 무한 반복에 빠지지 않는다.- 변수 뒤에 다른 값을 추가할 수 있는 장점이 있다.
✅ 일반적으로 선언하는 2 가지 방식 외에 확장성을 용이하게 해 주는 자동변수라는 것도 있습니다.
5.2. 자동 변수
$@
: recipe가 작성되는 Target의 이름을 지칭$<
: 첫 번째 Dependency 이름을 지칭$^
: 현재 Target이 의존하는 Dependencies의 전체 목록 (공백으로 구분)$?
: 현재 Target이 의존하는 대상들 중 새롭게 변경된 Dependencies의 전체 목록
6. 비교
6.1 Makefile을 사용하지 않는 경우
- 가상환경 실행 후 파이썬 실행
# 1. 가상환경 활성화
. env/bin/activate
# 2. 파이썬 파일 실행
python main.py
💡매번 파이썬 파일을 실행하기 전 가상 환경을 활성화시켜주는 동일한 명령어가 사용된다.
💡매번 똑같은 파일에서 반복되는 패턴으로 명령어가 실행된다.
6.2. Makefile을 사용하는 경우
- 변수 선언
ENV_NAME = env
API_ENV_NAME = api-env
PATH = path
PIP_INSTALL := pip install --upgrade pip
ENV_ACTIVATE := . $(ENV_NAME)/bin/activate
API_ENV_ACTIVATE := . $(API_ENV_NAME)/bin/activate
RUN_ENCRYPT_FILE := python $(PATH)/utils/encrypt.py
ENCRYPT_KEY := --key_path=$(PATH)/key
USE_ENV_RUN_ENCRYPT_FILE := $(ENV_ACTIVATE) && $(RUN_ENCRYPT_FILE)
RUN := python main.py
TEST := python test.py
Makefile
에서 사용할 변수들을 미리 선언
- 가상환경 및 의존성 설치
install:
$(PIP_INSTALL) &&\
sudo apt-get install python3-virtualenv &&\
virtualenv $(ENV_NAME)
$(ENV_ACTIVATE) &&\
pip install -r requirements_linux.txt
make decrypt
make install_api
install_mac:
$(PIP\_INSTALL) &&\
virtualenv $(ENV_NAME)
$(ENV_ACTIVATE) &&\
pip install -r requirements_macos.txt
install_api:
$(PIP_INSTALL) &&\
virtualenv $(API_ENV_NAME)
$(API_ENV_ACTIVATE) &&\
pip install -r requirements_api.txt
install
: 가상환경 생성 및 의존성 설치를 위한 Targetinstall_mac
: mac에서 의존성 설치를 위한 Target ver.install_api
: api를 사용하기 위한 의존성 설치를 하는 Target
- 암호화 및 복호화를 위한 Target
encrypt:
@$(USE_ENV_RUN_ENCRYPT_FILE) --type=$@ --file_path=$(PATH)/.env $(ENCRYPT_KEY)
decrypt:
@$(USE_ENV_RUN_ENCRYPT_FILE) --type=$@ --file_path=$(PATH)/env $(ENCRYPT_KEY)
encrypt
: config, env, json 등 암호화에 필요한 파일들을 미리 정의하여 만든 Targetdecrypt
: 암호화된 파일들을 복호화하여 데이터 값을 업데이트할 수 있는 Target
- 서비스 성격에 따라 실행하는 Target
run: decrypt
@$(ENV_ACTIVATE) && $(RUN)
test: decrypt
@$(ENV_ACTIVATE) && cd $(PATH) && $(test)
run
: main.py를 실행하는 Targettest
: test를 실행하는 Target
📌 정리
Makefile
을 사용함으로써 우리는 다음의 장점을 얻을 수 있습니다.
- 워크플로를 간소화할 수 있다.
- 프로젝트를 지속적 통합 시스템으로 쉽게 통합할 수 있다.
- 입력해야 하는 코드의 양이 줄어들면 자동화 측면에서도 좋다.
서버 테스트를 위해 코드를 실행한다고 가정할 때, 다음과 같은 차이가 생깁니다.
적용 전
- 가상환경 생성
- 가상환경 실행
- requirements.txt 파일로 의존성 모듈들 설치
- config, constant 파일들 복호화해서 env 파일 생성
- 메인 파일 실행으로 서버 테스트 가능
적용 후
make install
로 가상환경 및 의존성 설치make run
으로 서버 테스트 가능
⚠️단, Makefile 은 프로젝트의 많은 부분을 자동화해 주지만 새로운 파일이 추가되는 경우처럼
추가 기능이나 새로운 요소의 자동화가 필요할 때 종종 Makefile을 업데이트해주어야 합니다.
이렇게 Makefile이 무엇인지 그리고 어떻게 사용하면 좋은지에 대해 간략하게 알아봤습니다.
실제 Makefile에 대해 공부하면서 C언어와 같은 컴파일 언어에서는 컴파일 순서가 중요하므로 사용에 이점이 있지만 파이썬과 같은 스크립트언어에서 이걸 쓰는 것이 효과적일까?라는 의문을 가졌던 적이 있습니다.
하지만 실제 프로젝트 및 협업에 도입해보니 빌드 복잡성이 확실히 줄어들어 정말 큰 도움이 되는 걸 느꼈습니다!
그리고 Makefile을 잘 작성해놓으면 유사 Readme.md 같은 효과(?)를 얻을 수도 있으니 정말 좋은 것 같습니다.
특히 저희 조직에서는 빠른 PoC 확인을 위해 테스트 프로그램을 빠르게 작성하여 테스트 하는 일이 많은데요,
팀 내에서 Makefile에 대해 간단하게 세션을 진행하고 도입해보니 협업의 효율성이 정말 많이 증가하였습니다!
혹시 아직까지 Makefile에 대해 잘 모르고 계셨거나 사용해보시지 않으신 분들은 이번 기회에
한번 도입해보시길 강추드립니다!!

Reference
'Dev' 카테고리의 다른 글
주니어 개발자의 이직 한 달 회고 (1) | 2024.11.10 |
---|