Overview
MTV Pattern
Django는 애플리케이션을 모델(Model), 뷰(View), 그리고 템플릿(Template)으로 구성요소를 나누어 개발하는 MTV 패턴을 따르도록 권장합니다. 이는 흔히 알려진 MVC(Model-View-Controller) 패턴과 유사하지만, 용어 사용에 약간의 차이가 있습니다. Django에서 뷰는 사용자에게 '어떤' 데이터를 보여줄지 결정하는 역할을 하며, 템플릿은 그 데이터가 사용자에게 '어떻게' 표시될지를 담당합니다. MTV 패턴을 따르는 애플리케이션의 일반적인 요청 처리 흐름은 다음과 같습니다.
Serializer
우리는 Django를 주로 백엔드 HTTP API 서버 개발에만 활용하고 있기 때문에, 이 사용 사례에 최적화된 Django REST framework를 적극적으로 사용합니다. DRF는 JSON 기반의 RESTful API 개발에 유용한 여러 기능을 제공합니다. 그중에서도 가장 주목할 만한 점은, 기존 Django의 Template이 text/html 형식의 응답을 처리하는 반면, DRF의 Serializer는 application/json 형식의 응답을 주로 처리한다는 것입니다.
Serializer는 Django의 QuerySet이나 Model 인스턴스 같은 복잡한 데이터를 네이티브 파이썬 데이터 타입으로 변환하고, 이렇게 변환된 데이터를 다시 JSON이나 XML 같은 특정 포맷으로 직렬화(serialization)하는 과정을 쉽게 만들어 줍니다. 그리고 이 과정에서 각 필드 값의 유효성을 검증할 수도 있습니다.
Business Logic
이외에도 Django에는 QuerySet, ModelManager 등 다양한 기능들이 있습니다. 그러나 Django에는 비즈니스 로직 작성에 관한 특별한 규칙은 없기 때문에, 로직은 종종 애플리케이션의 여러 계층과 모듈에 분산되기도 합니다. 여러 곳에 일관성 없이 작성된 비즈니스 로직은 시스템의 복잡도를 높여 시간이 지남에 따라 유지보수를 점점 더 어렵게 만듭니다.
따라서 우리가 제시하는 Django 모범 사례의 핵심은 비즈니스 로직을 효과적으로 격리하고 관리하는 데 있습니다. 이를 위해, 우리는 의도적으로 모델을 빈약하게 만듭니다. 즉, 모델이 데이터베이스 테이블과 매핑되는 필드 정의와, 이 필드들을 기반으로 계산되는 단순 속성(property)만을 포함하도록 제한합니다.
데이터 변경이나 복잡한 로직을 포함하는 모든 주요 동작은 Use Case 계층에서 별도로 구현합니다. 결과적으로, 데이터베이스에 대한 모든 CRUD 작업은 유즈케이스 호출을 통해서만 수행되어야 하며, 이를 통해 비즈니스 로직의 응집도와 코드의 예측 가능성을 높입니다.
A Bird's-eye view
우리 애플리케이션의 전체적인 요청 처리 흐름은 다음과 같습니다.
- View: HTTP 요청을 받아 Input Serializer를 통해 입력값의 유효성을 검증합니다. 그 후, 하나 이상의 UseCase를 호출(조합)하여 비즈니스 로직을 실행하고 필요한 데이터를 처리합니다. 최종적으로 Output Serializer를 통해 클라이언트에 전달할 응답을 구성합니다.
- Input Serializer: 클라이언트로부터 전달된 데이터의 형식, 타입 등의 유효성을 검증하고, UseCase가 처리하기 용이한 파이썬 데이터 형태로 변환합니다.
- Use Case: 애플리케이션의 핵심 비즈니스 로직을 실행합니다. 데이터 생성, 수정, 삭제 등 모델(Model)과의 모든 상호작용을 담당하며, 트랜잭션 관리 등 서비스의 주요 기능을 실행합니다.
- Model: Object-Relation Mapping을 통해 데이터베이스 테이블과 애플리케이션 코드를 연결합니다. 데이터의 구조를 정의하고, 데이터베이스와의 실제 통신(조회, 저장 등)을 담당합니다.
- Output Serializer: UseCase로부터 전달받은 결과 데이터(주로 Model 인스턴스나 Python 객체)를 JSON 등 클라이언트가 이해할 수 있는 형식으로 직렬화하여 최종 응답 데이터를 생성합니다.
Directory Structure
애플리케이션의 디렉토리 구조는 다음과 같이 구성됩니다.
connectingServer/
└── services/
└── account/
├── migrations/
├── models/
│ ├── user.py
│ ├── profile.py
│ └── profile_image.py
├── usecases/
| ├── sign_up.py
| ├── sign_in.py
| ├── change_representative_image.py
| └── transfer_user_dia.py
└── v1/
├── apis/
| └── user_api.py
└── serializers/
├── user_api_input.py
└── user_api_output.py