Django 서비스 레이어

Hyuk·2023년 9월 4일

Django 리팩토링

목록 보기
1/2
post-thumbnail

티스토리에 있던 예전 글을 이사했습니다.

django로 프로젝트를 진행할 때, 항상 궁금했던 점이 있었다.

django와 springboot가 하는 일은 사실 같은 일인데, 스프링부트에서 볼 수 있었던 구조를 django에서는 볼 수 없었다는 점이다.

기본적으로 springboot에서는 repository 레이어에서 db에 접근하고, service 레이어에서 비즈니스 로직을 처리하고, web 레이어에서 클라이언트의 요청을 처리한다고 알려져있다.

따라서 가장 보편적인 ( 개발 서적에서 살펴볼 수 있는 ) 스프링부트 프로젝트 구조는 다음과 같다.

그러나 현재 진행중인 Django 프로젝트의 구조는 조금 다르다

위와 같이 urls.py가 클라이언트의 요청을 처리하는 레이어이고, view.py에서 이외의 모든 일들을 처리한다.

그렇다면 내가 언제부터 스프링부트에서 위에 서술한 구조로 나누어 프로젝트를 진행했을까?

사실 처음부터 저런 구조로 진행했다. 왜냐하면 대부분의 책과 인강에서 당연하다는 듯이 보여주기 때문에 저런 구조가 규칙이라고 생각했던 것 같다.

하지만 이제는 역할과 책임에 근거하여 나뉘어있는 구조라는것을 알기에 기술적으로 강요되는 구조는 아니라는 것을 알고 있다.

스프링부트에서도 물론 한 파일에 모든걸 때려박고 진행할 수 있다. 하지만 분명 그랬을 때의 단점이 분명히 존재하기 때문에 위와 같은 구조가 존재하고, 암묵적으로 모두가 규칙처럼 사용하고 있다.

그렇지만 대부분의 서적이나 인강에서 스프링부트 프로젝트를 위와 같은 레이어로 구분지었을 때와 그러지 않았을 때의 차이를 분명하게 알려주지 않기 때문에 생각없이 사용하고 있었고, 잘못 사용하고 있을지도 모른다는 생각이 들었다.

그렇다면 궁금한 점은,

스프링부트에서 권장하는 레이어 구조는 정확하게 무엇이고, 어떤 이유를 갖고있는 구조일까?
장고에서는 이런 구조를 권장하지 않는것 처럼 보이는데, 그 이유는 무엇일까?
해결하고 싶은 점

장고에서 스프링부트와 동일한 구조로 코드 재구성 해보기 (장고에서도 그 구조를 따라도 괜찮다면)

  1. 장고 컨벤션
    먼저 서비스레이어를 분리하는것은 standard한 장고 디자인패턴 컨벤션은 아니라고 한다.

공식문서에 존재하는 장고 설계 철학을 살펴보면 서비스 레이어에 대한 언급은 존재하지 않는다.

bookmark

그럼에도 불구하고 서비스 레이어를 따로 분리해보고자 한다. 그 이유는 다음과 같다.

이미 많은 사람,기업에서 분리를 하고 있다.
장고 공식문서에 서비스레이어를 만들으라는 말은 없지만 (아마도) view 함수를 최대한 단순하고, 가볍게 만들으라는 제안이 존재한다. 나는 이것의 해결법으로 서비스 레이어를 분리시키는것을 적용해보고자 한다.
내 프로젝트 코드는 매우 단순하지만, 후에 확장을 염두해둔 프로젝트이므로 레이어를 분리시켰을 때 유지보수가 용이할 것으로 예상된다.
해보고싶다. 만약 분리시켰을 때의 단점도 있다면, 직접 경험해봐야 더 잘 알 수 있고 다른곳에서 같은 아키텍쳐를 사용했을 때 더 잘 적용할 수 있을것이다.
pypi에서는 서비스 레이어를 분리하는 방법으로 몇가지 방법을 제안한다.

분리 없이 View에 담기 분리가 존재하지 않으면 로직을 이해하기 너무 힘들다. 코드의 반복도 빈번하게 일어나는 문제가 발생한다.또한 어떤 뷰를 상속받는 자식 view가 존재할 때, 부모간에 너무 강하게 연결되어 있다는 점이 문제가 된다. (느슨한 결합 중요)
model에 분리. 가장 많이 사용되는 방법중 하나이지만, 프로젝트가 커질수록, 너무나 많은 책임을 model이 가져아한다는 점이 단점이다. 또한 데이터베이스에 접근할 필요 없는 로직이거나, 두개 이상의 테이블에 접근해야하는 로직의 경우 역할이 모호해질 수 있다는 단점이 존재한다. 코드의 중복을 줄일 수 있다는 장점이 있다.
QuerySet에 분리 마찬가지로 여러 테이블이 필요한 로직이 존재할 때, 문제가 발생한다. 다만 가독성이 높아지고, 쿼리 최적화가 가능하다는 장점이 존재한다.
Serializers에 분리 원래의 역할이 분명히 존재하기 때문에 무조건적으로 피해야하는 옵션이라고 소개된다.
Service 레이어 만들어서 분리. 비즈니스 로직을 분리해서 함수에 담고, 그 함수를 view와는 다른 레이어에 담는다. 코드 관리가 쉬워진다는 장점이 있으며 많은 곳에서 이런 방법을 사용한다.
이렇든 많은 방법이 있고, 각 방법이 모두 장단점이 있기 때문에 정답이 존재하는것은 아니다. 하지만 한가지 방법을 선택해야 하고, 마지막 Service 레이어 만들어서 분리 를 선택했다 (이유)

기존 코드

@api_view(['GET']) def getBookById(request):
	bookId=request.GET["bookId"]     
    book=Book.object.get(pk=bookId)     
    comments = Comment.object.filter(book=book)     
    responseData = {"book": BookSerializer(book, many=False).data, "comments": CommentSerializer(comments, many=True).data}     
    return Response(responseData, status=status.HTTP_200_OK)

변경 코드

views.py

@api_view(['GET']) def getBookById(request):     
	bookId=request.GET["bookId"]     
    responseData=getById(bookId)     
    return Response(responseData, status=status.HTTP_200_OK)

service.py

def getById(bookId):     
	book=Book.object.get(pk=bookId)     
    comments = Comment.object.filter(book=book)     
    responseData = {"book": BookSerializer(book, many=False).data, "comments": CommentSerializer(comments, many=True).data}     
    return responseData

위의 리팩토링으로 서비스레이어를 분리하였다.

다음은 리포지토리 레이어도 분리해보겠다.

profile
🙂 🙃 🙂 🙃

0개의 댓글