현재 백엔드 소스에서 view단에서 모든 로직이 구현되어, 서비스 레이어 분리가 필요해 보임
django에서 사용되는 디자인 패턴에 대해서 조사
💡 비즈니스 로직(Business Logic)은 유저의 요청에 따른 결과물을 만들어내기 위한 일련의 작업들을 의미한다. 회원가입을 예로들면, 아이디 중복 체크를 할 때 유저에게는 단순하게 중복여부를 출력만 하지만, 내부적으로는 DB에 접근하여 유저가 입력한 아이디가 존재하는지 확인하는 절차가 진행된다. 다시 정리하자면, 사용자가 어떤 요청을 했을 때, 그 요청을 처리하기 위해 내부적으로 진행되는 절차를 비즈니스 로직이라고 한다.
View, Serializer
- 일반적으로 사용. view, serializer에 비지니스 로직 넣음
- serializer는 데이터 유효성 검증(validation)
- 로직이 커질수록 view가 지저분해지고 직관적으로 파악하기 어려움
- 복잡성이 높은 비즈니스 로직 추가를 피해야함
- 특정 API에 기능이 종속되는 경우, 다른 API나, 배치잡에서 해당 기능을 재사용하기 어려움
Fat Model, Thin Controller
- model에 기능을 모아두고, controller는 중계 역할로 구성
- 코드 중복이 줄어들고, 객체지향적으로 코드 설계가 편하다
- 서비스가 커지며 비즈니스 로직이 많아지고, 다양한 도메인이 섞이게 되면 복잡하고 관리가 어려움
- 다른 model에서 상속을 하는 경우가 있다면 모든 비지니스 로직을 상속. 이런 경우 사이드 이슈 발생 가능성
- 결국 프로젝트, 비즈니스 로직이 커지고 복잡해지게 되면 model을 분리해야 하는 레거시 코드가 될 수도 있음(한 app에서 많은 양의 코드가 있어서 복잡하기 때문에 유지보수 측면에서 좋지 않음)
Service layer
- model과 view 사이에 비즈니스 로직을 담당하는 개념을 추가
- service layer가 추가되면 모델에는 객체의 속성만 관리
- 방식
- Form / Serializer가 Service Layer를 대신
- utils 모듈에 비즈니스 로직을 추가해서 사용
- service 모듈에 비즈니스 로직을 추가해서 사용
++ 조회 / 응답 / 비즈니스로 분리하여 구성
- 기존 Service Layer에는 비즈니스 로직의 수행 및 데이터 정합성 검증의 두 가지 역할
Service Layer의 비즈니스 로직이 복잡해지면서 가독성을 떨어뜨리고, 개발자가 집중해야 할 비즈니스 로직을 파악하는 데 어려움
- 이를 해결하기 위해 데이터를 검증하고 설정들을 관리하는 Python 라이브러리인 Pydantic을 사용한 Validator Layer를 추가하여 데이터 정합성 검증의 역할을 분리
- Validator를 통해 데이터 검증을 완료한 후 Service 레이어를 호출하게 됨으로써 Service Layer는 비즈니스 로직의 수행에만 집중할 수 있게 되었습니다.
- selectors.py
- services.py
- validators.py
- veiws.py
- 조회/응답/비즈니스 분리 예시
- 쿼리 최적화가 필요하다면 Selector
- 비즈니스 로직 파악이 필요하다면 Service
- 응답 형태를 확인하고 싶다면 View를 확인하기만 하면 되는 구조
app_name
├── api
├── models.py
├── views.py
├── selectors
│ ├── all_posts.py
│ ├── user_posts.py
│ ├── search_posts.py
│ └── ...
├── services.py
├── validators.py
queryset / manager
- 모델에 쿼리를 호출하는 함수가 포함되어 있으면 대량 처리가 필요한 경우 최적화되지 않은 쿼리가 호출될 가능성이 높다.
- 예를 들어, 여러 개의 포스트의 상태를 변경해야하는 경우, 로직이 모델에 종속되어있으면 포스트의 개수만큼 변경 쿼리가 호출
- QuerySet을 사용하면, 한번의 update 쿼리로 여러개의 객체의 상태를 변경할 수 있다.
- 따라서 QuerySet에 비즈니스 로직을 모아두면 Batch, Service Object에서 기능을 재사용하기 편하다.
- 장점
- 유닛 테스트가 쉬워진다.
- 가독성이 높아진다.
- 코드가 간결해진다.
- 쿼리 최적화가 가능하다.
현재 구성
app_name(최근)
├── api
│ ├── views.py
│ ├── serializers.py
├── models.py
├── urls.py
app_name(이전, core)
├── 관련 tables(ex, courses)
│ ├── urls.py
│ ├── views.py
...
├── models.py
├── views.py
├── serializers.py
참고자료
비고
클린 아키텍처 / 헥사고날(이 부분은 아직 이해하지 못했으나, 추후 공부해보면 좋을 것 같아 추가했습니다.)
├── rentomatic
│ ├── app.py
│ ├── domain
│ │ ├── entities
│ │ │ └── room.py
│ │ ├── interfaces
│ │ │ └── repository.py
│ │ ├── request_objects
│ │ │ └── room_list_request_object.py
│ │ ├── response_objects
│ │ │ └── response_objects.py
│ │ └── use_cases
│ │ └── room_list_use_case.py
│ ├── repository
│ │ ├── memrepo.py
│ │ ├── mongorepo.py
│ │ ├── postgres_objects.py
│ │ └── postgresrepo.py
│ ├── rest
│ │ └── room.py
│ ├── serializers
│ │ └── room_json_serializer.py
│ └── settings.py
└── wsgi.py