- 특정 방법론이 항상 효율적인 것은 아니므로 상황에 맞는 선택이 중요하다.
- 같은 이유로 특정 방법론을 신봉하는 것은 좋지는 않다.
- 그러나 복수/단수 네이밍은 꼭 지켜주자.
- 하나의 프로젝트에 하나의 app으로 모든 기능을 담았다.
- config에 모든 세팅이 들어갔는데, settings.py를 하나로 하는 경우도 많지는 않다.
- 서버만 해도 test 서버, dev 서버, production 서버 세개를 두는 게 일반적이다.
- test를 위해 DB를 건드렸는데 실제 production DB에 영향이 가면 안되기 때문에 같은 DBMS는 일관성을 위해 같이 쓰지만 DB는 서로 달라야 한다.
- config 안에 settings 폴더를 넣고 구분하여 관리할 수 있다.
- app이 로그인, 회원가입, class 정보, student 정보, 댓글, 팔로우 등 모든 기능을 담당해서 views가 길어졌다.
- 만약 class를 추가하거나 수정하는 등 또다른 기능을 넣는다면 앱이 너무 커지므로 쪼개줄 필요가 있다.
- app은 하나의 역할, 하나의 기능을 담당한다고 생각하고 디자인하자.
- 그러나 여전히 개인의 선택이다. 하나의 앱 속에서 파일만 다르게 해줄 수도 있다.
- url 단위를 기준으로 나누는 RESTful 한 방식을 실습해보자.
- 우리가 만든 community라는 프로젝트는 예컨대 blog(글 관련), social(팔로우), account(로그인, 마이페이지 등) 등으로 나눌 수 있다.
- 리소스의 상태에 대한 표현
- 리소스(자원)는 곧 DB 테이블와 같은 말이라고 볼 수 있다.
- URI를 통해 어떤 자원인지 명시한 후, HTTP Method를 통해 해당 자원에 대해 어떤 동작을 수행할지 명시하는 것
- client & server: 자원을 가지고 있는 서버(api 제공, 비즈니스 로직 처리)와 이를 요청하는 클라이언트(사용자 세션을 직접 관리)
- stateless: 사용자의 상태(쿠키, 세션)를 서버에 저장하지 않고, 각각의 요청은 독립적으로 존재하므로 DB 상태 변경 외에는 요청의 순서가 상관없다.
- cacheable: 캐시 처리가 가능하다. (응답 시간이 빨라지고 자원 이용 효율이 증가)
- layered system: 아키텍쳐를 계층화하여 구성. 서버의 다양한 layer에서 각각의 역할을 나누어 처리하므로 api 서버에서는 비즈니스 로직만 처리하고 다른 layer에서 SSL 등의 보안이나 로드밸런싱 등을 처리한다.
- 유지보수/운영 효율 증가, 확장성 & 재사용성 증가
- 항상 절대적으로 효율적인 건 아니다. 예컨대 작은 서비스인 경우 RESTful API를 구축하고 이에 숙달시키기 위한 시간과 노력이 더 들 수가 있다.
- toss같은 곳에서도 의도적으로 지키지 않는 경우도 있으므로 상황에 맞게 선택하는 것이 중요하다.
- URI는 동사보다는 명사를, 소문자로, 상황에 맞는 복수와 단수를 사용, '/'로 계층을 구분하며 마지막에는 '/'를 포함하지 않는다(장고에서는 포함함).
- URI에는 언더스코어(
_
)보다는 하이픈(-
)으로 표현하고, 파일확장자는 포함하지 않는다. - CRUD와 관련된 요청행위는 적절한 HTTP 메서드를 사용한다.
- 늘 하던대로 프로젝트를 시작해주자. 까먹었을 수도 있으니 다시 한 번 해보자면...
$ mkdir {디렉토리명}'(디렉토리 생성), '$ cd {디렉토리명}'(디렉토리 진입),
$ virtualenv venv(가상환경 구축),
$ source venv/bin/activate(가상환경 진입),
$ pip install django(장고 설치),
$ django-admin startproject config .`(현재 디렉토리에 config라는 이름의 프로젝트 시작)
$ python manage.py startapp {앱 이름}
을 앱 개수만큼 해주고, config 폴더의 settings.py에 INSTALLED_APP에 앱 이름을 추가해준다.
- config의 urls.py 안에 각 앱의 urls.py를 import한다.
path('blog/', include('blog.urls'))
,path('social/', include('social.urls'))
등- 이렇게 하면
blog/
로 들어오는 요청은 자연스레 blog 앱으로 가는 등 요청이 들어왔을 때 자동으로 각 앱의 이름에 따른 urls.py로 찾아간다.
- 각 앱 폴더에 urls.py를 만들고, 처음 부분의
from django.urls import path
는 복붙한다.- 각 앱에서 views를 사용하여 경로에 맞는 함수처리를 할테니까
from {app name} import views
urlpatterns = []
로 path를 정해주는데, 이미 앞에 blog라는 경로가 붙어 온다는 것을 염두에 두고 중복되지 않도록 정해준다.- 여러 개의 아이템 중 하나를 pk값 등으로 받아 처리할 경우 경로 이름을 복수로 해준다.
- 각 앱에서 views를 사용하여 경로에 맞는 함수처리를 할테니까
- 앱의 urls.py에
app_name
이라는 변수에 문자열을 할당하면 네임스페이스를 사용할 수 있다.urlpatterns
에서 name으로 지정한 내용 앞에 붙을 이름을app_name
에 할당하면, 굳이 name을 blog-index라고 구체화하지 않아도 템플릿이나 redirect의 인자에서blog:index
로 해당 경로를 지칭할 수 있다.
- 지금까지는 views에서 error handling이나 validation을 모두 처리했는데, 그러다보니 너무 길어진다는 문제가 생겼다.
- 다양한 로직을 어떻게 처리할 것인지에 대한 의견이 여러 개 있는데 그 중에 Fat Models, Service Layers, Model Managers가 있다.
- models.py에서 모델이 비즈니스 로직까지 모두 수행하게 한다.
- class 안의 메서드로 로직을 정의한다.
- 장점: view가 얇아지고, 객체지향의 의미를 살릴 수 있다.
- 단점: 모델이 가진 변수나 필드를 한 번에 직관적으로 이해하기 힘들다.
- 3-layer-architecture로 더 알려져있으며, MTV를 지향하는 장고의 철학과는 썩 맞지 않을 수도 있다. (다른 웹 프레임워크에서 시작된 이론이기 때문에)
- control과 service를 완전히 분리하여 처리한다. 이 때 controller, service, data(model)의 세 개 계층으로 나뉘기 때문에 3-layer-architecture라고 불리며, 이 위에 template이 존재한다.
- controller: urls.py로 요청을 받고, views.py로 응답을 내보내는 역할만 한다. DB에 직접적으로 접촉하지 않는다.
- service: service.py라는 파일에서 DB에 관련된 모든 로직을 처리한다.
- data(model): service와만 접촉한다.
- views.py에서는 model을 import할 필요도 없게끔 전혀 모델(DB)을 직접 작업하지 않는다. (대신 service.py의 함수들을 import한다.)
- 장점: 서로 완전히 분리되어 어디에서 오류가 났는지 알고 대응하기 편하다. (response error는 views, DB connection error는 service 등)
- 단점: views.py에서 filter 한 번만 하면 되는데 이걸 굳이 하나의 레이어를 더 거쳐야 하는 경우 등 비효율적일 수 있다.
- MVC 기반 프레임워크에서 볼 수 있는 양상으로, 스프링이 이를 활용한다고 한다.
- 원래 장고가 활용하는 objects managers를 바꾼다.
- 모델이 너무 방대해지고, 기존 모델 매니저를 쓰지 않는 게 확고하게 유리하다고 판단될 경우 사용하는 방법이다.
- is_deleted가 True인 data를 exclude하는 경우 등 특정 모델메서드를 일반적인 상황에서 모두가 써야 하는 경우에 적합하다.
- app 폴더 안에 service.py 파일을 만든다. 함수보다는 class로 만들고 해당 class 안의 메서드로 정의하여 사용하는 것이 편하다. (
ArticleService.method
처럼) - 하지만 먼저 함수로 작업하고 불편함을 느껴보고 클래스로 전환하자.
- service는 DB에 직접 접근하여 작업하는 것을 목적으로 한다. 중복 제거나 함수 처리가 목적이 아니므로 DB에 닿는 모든 처리만 service에 넣을 것
- validation이나 helper 함수 역할을 하는 것은 service가 아닌 utils로 뺀다.
- 방법론이 참 많기도 한 걸 보니 사람들은 정말 똑똑하다.
- REST에 대해 공부하던 중에 수업에서도 마침 타이밍 좋게 배울 수 있어서 좋았다.