지금은 전직장이 되버린 마지막 회사의 개발팀에 있으면서 서비스 운영 및 고도화 업무를 수행하였는데, 이 팀의 개발 Spec이 Python 기반의 Django Framework + ORM이 Main이었다.
Javascript와 Java기반 Spring Framework Spec이 Main인 나로써는 어찌보면 가지말았어야 했는데, 그놈의 도!전!정!신 하나로 왜 할 수 있다고 생각 했는지.. 지금 생각해보면 선택하지 말아야할 선택을 한 것이 아닌가 싶다.
(물론 후회까지는 아니다. 그리고 언어를 모른다고 개발을 못한다는 것은 아니다. 다만, 나의 연차 대비 신규 언어 습득과 이에 따른 퍼포먼스는 회사에서 보았을 때 중요한 이슈이긴 하다.)
오늘 스OOO에서 글을 쓰는 이순간에도, 다양한 경험을 한 것중 가장 최근에 사용한(?) 기술을 까먹을 듯하여 짧지만 이것저것 해본 Python/Django에 대한 나의 지식을 구글링의 힘을 빌어 최대한 간결하게 정리해 보려한다.
(모든 개발자 분들은 아시겠지만 velog에는 나보다 훨~씬 대단하고 위대하신 능력자 분들이 계시다. 혹시 기술 도움을 받기 위해 우연히 이 글을 보고 계시는 분이 있다면, 필시 다른 개발자 기술 블로그를 찾아 가시기 바란다. ^^)
Python이란
Python 제단에서 만든 오픈소스 인터프린터 언어
pyenv
- 파이썬 버전별로 독립적인 개발을 하기 위해 제공하는 가상 개발 환경
- 사용 이유 : 파이썬버전에 따라 deperated 된 기능이 있는 경우 버전업 시 시스템에 영향을 줄 수 있어, 버전별로 관리가 필요
(우리는 이걸 버전을 탄다고 한다.)
MeCab
list vs dict
- 배열 기반 vs key:value 기반
- 검색 시 순서로 정의된 인덱싱을 통해 테이터 조회 vs hash table을 사용하여 key를 통해 데이터 조회
- 특정 key의 값 조회 시 모두 조회 vs 특정 key에 해당 되는 데이터만 조회
list vs tuple
- 순서 존재 vs 순서 존재
- indexing 존재 vs indexing 존재
- 값 변경 가능 vs 값 변경 불가
Django Framework 란
- python 으로 만들어진 웹 프레임워크, 웹페이지를 쉽게 만들기 위해 제공합니다.
Django 동작 사이클
- 웹페이지 요청 -> Django urlResolver에서 mapping 되어 있는 경로 찾기 -> view 함수에서 관련 기능 수행 -> Data Serializer 수행 -> 응답 값 리턴
Django DRF
- Djangp Rest Framework 약자로 Django REST API를 쉽게 구성할 수 있도록 제공함
- DRF의 중요한 포인트는 Model에 Mapping 되어 있는 Data를 Serializer 해주어
Data Serializer
- Object를 구체적이고 저장/전송이 가능한 byte 파일로 바꾸어 보내는 것
- Django 에서 Serializer는 데이터 응답에 필요한 필드를 원하는 것만 정의하기 때문에, DTO 및 보안 관리 측면에서도 중요한 개념임(vaildation 등)
- Data는 ORM 또는 Non-ORM을 통해 데이터가 Mapping되어짐
Decorator
- 코드의 가독성 및 재사용성을 높이기 위해서 사용하는 기능
- 커스터마이징 가능
ORM
- 객체와 관계형 데이터베이스를 자동으로 Mapping해주는 lib
(Java JPA와 비슷한 동작방식이라고 생각하면 좋을 듯, 그러나 명확하게 다릅니다.)
- 장점
- 객체지향적 코드 작성이 가능
- 코드 가독성 증가
- 재사용 및 유지보수 용이
- RDBMS의 종속성이 줄어듬
- 단점
- 프로젝트의 복잡성에 따라 개발 난이도가 올라감
(ex : prepatch_related/selected_related 사용, annotation/aggregate를 활용한 통계 등)
- 프로시저가 많은 RDBMS에서는 적합하지 않음
ORM vs JPA
- 이부분을 설명하기 전에 JAVA Spring Framework에서도 동일한 개념이 있다.
- ORM : Java에서 정의한 DAO 객체와 RDBMS Field와 매핑하여 데이터를 제공하는 개념
(여기서 DAO 개념이 나옵니다. 즉, DAO는 데이터 접근이 가능한 객체를 정의하고, 해당 데이터를 어플리케이션 상에서 주고 받을 수 있도록 제어해주는 개념입니다.)
- JPA : Java Persistance API 약자로 말그대로 ORM으로 정의된 영속적인 객체를 API를 통해 데이터를 주고받을 수 있도록 Spring에서 제공하는 lib. 그래서 JPA는 DAO로 말하지 않고 DTO 개념으로 설명한다. 즉 데이터 접근 가능한 객체 정의 + API를 통한 데이터 전송방식입니다.)
- 개인적으로 Django의 ORM은 JPA의 특성만을 뽑아 만든 lib라고 생각을 합니다. API 방식으로 데이터를 주고받진 않지만, 개발자 친화적인 코드 작성, 객체지향적인 코딩 방식은 JPA와 매우 유사하기 때문입니다.
lazy loading vs eager loading
- 지연 로딩 디자인 패턴 vs 즉시 로딩 디자인 패턴
- 쿼리를 조회하는 시점에서 한번에 할껀지 vs 요청 때 마다 바로 조회할 것인지 결정
(ex: Student 테이블과 Action 테이블이 1:N 관계라고 가정하고, 학생이 수행할 수 있는 활동들을 조회하고 싶을 경우)
# lazy loading
student = Student.obejcts.get(id=1)
actions = Acton.objects.filter(student=student.id)
for action in actions.iterator():
print(student.name, action.work)
- lazy loading을 사용하는 경우 DB 호출 시점은 Action 테이블을 조회할 때 시점이고, 이때 앞에 조회 쿼리를 정의했던 student는 바로 조회되지 않고 기다리고 있다가 Action 테이블 조회 시 student 테이블을 먼저 조회하고, 그 결과로 action 테이블을 조회하여 데이터를 가져온다.
- 반면, eager loading의 경우 DB 호출 시점이 아래와 같이 Action 테이블에서 select_related/prepatch_related를 사용하여 join이 발생될 때 Student 테이블을 즉시 조회하고, 그 결과와 mapping되어 있는 action 테이블의 데이터를 가져온다.
# eager loading
actions = Acton.select_related(‘Student’).objects.filter(student=1)
for action in actions.iterator():
print(student.name, action.work)
lazy loading 장점
- DB요청이 상대적으로 적기 때문에 DB의 부하를 줄일 수 있어 시스템 인프라를 효율적으로 사용할 수 있다.
- 통계 수집, 데이터 학습 등에서는 효율적일 듯
lazy loading 단점
- one to one 관계에서는 비효율적
eager loading 장점
- one to one 관계처럼 즉각적으로 표시가 필요한 실시간 시스템에서 적합
eager loading 단점
- DB요청이 많기 때문에 DB의 부하가 늘어나 서비스 지연/장애 등의 문제가 발생할 수 있음
- 대세적인 흐름은 기본적으로 lazy loading 방식으로 데이터를 처리하나, 즉각적으로 실행이 필요한 데이터에 대해서만 eager loading을 사용하여 처리하는 것이 효율적이다고함.
- one to one 관계 처럼 참조 테이블에 대하여 join을 사용하는 경우 (이걸 역참조라고 설명을 많이 하는 편) vs many to many, many to one 등 조회할 테이블을 각각 수행한 후 application에서 합쳐서 사용
annotate vs aggregate
- 어떤 특정 필드를 임의로 만들어 추출하고 싶을 경우 사용 vs sum, avg 등 통계적 데이터를 추출 시 사용
- annotate 필드를 정의 시 sum, avg 등 통계적 기능 사용 가능 vs 전체 필드의 단순 통계 추출만 사용 가능
ex) 과목별 가장 높은 점수를 받은 학생 vs 전체 학생 중 가장 높은 점수를 받은 학생
Mocking
- 특정 클래스나 함수를 사용자가 정의한 응답값으로 반환하기 위하여 사용하는 기능
- 주로 TDD에서 기능 확인 시 많이 사용
ex) try catch 예외 처리 테스트, 임의의 날짜로 변경 후 테스트
Django에서는 unittest.mock.patch 어노테이션을 이용하여 처리
ex) with patch(class_name.function) as test:
test.return_value = {‘result_code’: 400, ‘msg’ : ‘400 에러 테스트’}
result = class_name.function()
assert_that(result).is_equal_to({‘result_code’: 400, ‘msg’ : ‘400 에러 테스트’})
Celery
- 분산 메시지 전달 및 처리에 기반을 둔 비동기 테스크 큐
- 상황에 따라서 스케줄러 역활도 가능
Django를 정리하겠다고 글을 쓰기 시작했는데, 나도 모르게 Python과 ORM까지 정리해버렸다.(사실은 의식의 흐름대로 작성을 컥...)
다 아는 것도 아닌데 이게 뭐라고 이렇게 정리하는 것인지...
그리고 아직도 해소하지 못한 질문
그래서 Django가 뭔가요?
끗