클린 아키텍쳐 파이썬- django
Clean- Architecture란 무엇일까?
clean- architecture가 2021년 유럽 장고콘에서 다뤼졌다.
기존의 django 구조에는 어떤 문제가 있었길래 이런 clean architecture가 소개 된걸까?
기존 Django Architecture의 문제점은?
※ 비즈니스 로직을 어디에 두어야 할까?
- Views → 읽기 힘들다, 다시쓰기 힘들다
- Models → 모델의 dependency를 너무 복잡하게 생성한다. (즉, 수정하기 힘들다 능동적 db대응 힘듬)
- Forms → 이건 UI에 묶여있는 로직이라 불가하다
- 위의 모든 파트는 unit test하기 힘들고 share하기도 힘들다.
해결책은 무엇일까?
- 특정한 layer에 고립된 비즈니스 로직을 만들자
- 이런 layer들을 use cases layer에서 접근하게 하자
- adapter layer를 만들어 외부에서 접근하게 하자(ex: model)
- interface layer(ex:view)를 통해 adapter안에 있는 use case에 접근하자
이 해결책을 바탕으로 다시금 만든 architecture구조가 바로 소개할 clean architecture다
Clean Architecture
Clean architecture란 무엇인가?
- 프레임워크에 독립적
- 유닛테스트에 용이 → ui, DB, web server 그 외 모든 외부요소와 관련없이 비즈니스 로직만 테스트가능
- UI에 독립적 → UI는 언제나 쉽게 변한다 특히 front는 back보다 기술변화가 빠른데 여기에 독립적인것은
큰 이득이다. - DB에 독립적 → django프로젝트를 하면서 db를 스키마를 orm을 통해 잘못 구축했을 때 변경해본 고역을 겪어본사람이라면 이게 얼마나 큰 것인지 잘 알것이다. 언제든 DB를 바꿀 수 있다.
- 모든 외부적 요소 3rd party든 혹은 다른것이든 이 모든것에 독립적이다.
글보단 코드가 익숙할것이다.
다음은 clean architecture와 기존 구조와의 비교다.
1. 기본 구조
책들의 값의 평균을 구하는 로직으로 간단한 비즈니스 로직이다.
def books_average_price(request):
price_data = Book.objects.all().aggregate(Avg('price')))
return JsonResponse({"price":float(price_data["price__avg"])})
작동도 잘 되는 django의 기본 구조다. view를 통해 orm에 접근한다.
2. 비즈니스 로직을 통해 orm에 접근한 구조
class PriceEngine:
def get_average_price(self):
price_data = Book.objects.all().aggregate(Avg('price'))
return float(price_data["price__avg"])
def books_average_price(request):
price_engine = PriceEngine()
price = price_engine.get_average_price()
return JsonResponse({"price":price})
비즈니스 로직 모듈을 불러 orm에 접근한다.
view 함수가 직접적으로 orm에 접근하지 않는다.
3. Clean Architecture
def is_summer():
return datatime.datatime.now().month in (6,7,8)
class PriceEngine(ABC):
@abstractmethod
def get_average_price(self):
pass
class PriceEngineGeneral(PriceEngine):
def get_average_price(self):
price_data = Book.objects.all().aggregate(Avg('price'))
return float(price_data["price__avg"])
class PriceEngineDiscount(PriceEngine):
def __init__(self,discount):
self.discount = discount or 08
def get_average_price(self):
price_data = Book.objects.all().aggregate(Avg('price'))
return float(price_data["price__avg"]) * self.discount
def price_engine_factory(discount=None)->PriceEngine:
if is_summer():
return PriceEngineDiscount(discount)
return PriceEngineGeneral()
def books_average_price(request):
price_engine = price_engine_factory()
price = price_engine.get_average_price()
return JsonResponse({"price":price})
이제 clean architecture를 이용해서 로직을 나누었다.
view는 factory를 통해 비즈니스 로직에 접근한다. 그 후 비즈니스 로직은 orm에 접근한다.
이를 통해 외부 interface가 변하여도 비즈니스 로직은 어떠한 영향을 받지 않게 되었다.