클린 아키텍쳐

GisangLee·2023년 8월 23일
1

django

목록 보기
35/35

1. 개요

개념

  • 클린 아키텍처는 이러한 요건을 만족하는, '추상화 개념'으로
    관심사를 분리시키고 의존도를 낮추는 것에 목적을 둔 아키텍처

    의존도를 낮추고 서로에게 주는 영향을 감소함으로써 유지보수의 용이성 향상.
    덕에 낮은 비용으로 새로운 기능 추가 용이.

    출처 : http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html


2. 구성 요소

Entity

  • 도메인 계층으로도 불리며, 엔티티 계층은 하나 이상의 프로그램 간에 공유될 수 있다는 가정하에 만드는 수명이 긴 객체.
    (즉, 재사용의 가능성이 높다는 것을 인지하고
    외부에 의해 변경될 가능성을 낮추어야 한다.)

  • 이곳에는 Enterprise 규모의 비즈니스 데이터를 포함하거나
    핵심이 되는 비즈니스 규칙을 캡슐화합니다.

Use Cases

  • 애플리케이션 계층으로도 불리며, 어플리케이션 규모의 비즈니스 규칙을 포함합니다. 이 레이어의 변경사항은 엔티티에 영향을 미쳐서는 안되며,

  • 인프라 단의 DB나 UI, 라이브러리와 같은 외부요소에 의해
    영향을 받지 않는다는 것을 원칙.

  • 이는 즉, 해당 계층의 수정은 응용 프로그램의 동작에 영향을 미친다는 의미.

Interface Adapter

  • 어뎁터 계층은 DB나 Web, UI와 같은 바깥 계층에서 사용하기 편리하도록,
    유즈케이스 또는 엔티티 계층에서 데이터를 변환하는 어뎁터의 집합.

  • 흔히 MVC, MVVM과 같은 아키텍처를 포함하는 것이 이 영역으로
    컨트롤러, 프레젠터, 게이트웨이 등이 속합니다.

Frameworks & Drivers

  • 인프라 계층이라고도 불리며, 가장 외부에 있는 레이어로 DB, 웹 프레임워크와 같은 세부 정보(Details)를 나타내는 계층.

  • 이곳은 보통 글루 코드(Glue code)만 작성하며, 시간이 지남에 따라 구성이 변경될 수 있으므로 엔티티 계층(또는 도메인 계층)에 추상화(abstracted)하여 도메인 계층에 영향을 주지 않고 인터페이스를 수정하고 업데이트할 수 있음.


3. Django에 적용하기 (feat. Generic Viewset)

폴더 구조

users/
|-- domain/
|   |-- entities.py
|   |-- use_cases.py
|-- repositories/
|   |-- user_repository.py
|-- views/
|   |-- user_views.py
|-- models.py
|-- serializers.py

model

from django.db import models

class User(models.Model):
    username = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

entity

class UserEntity(object):
    def __init__(self, id=None, username=None, email=None):
        self.id = id
        self.username = username
        self.email = email

Use Cases

class CreateUserUseCase(object):
    def __init__(self, user_repository, serializer_class):
        self.user_repository = user_repository
        self.serializer_class = serializer_class

    def execute(self, user_entity):
        user = self.user_repository.save(user_entity)
        return self.serializer_class(user)


class ListUsersUseCase(object):
    def __init__(self, user_repository, serializer_class):
        self.user_repository = user_repository
        self.serializer_class = serializer_class

    def execute(self):
        users = self.user_repository.get_all()
        return self.serializer_class(users, many=True)

repository

from .models import User

class UserRepository:
    def save(self, user_entity):
        user = User.objects.create(username=user_entity.username, email=user_entity.email)
        return user

    def get_all(self):
        return User.objects.all()

serializer

from rest_framework import serializers
from .domain import entities

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    username = serializers.CharField()
    email = serializers.EmailField()

    def create(self, validated_data):
        return entities.UserEntity(**validated_data)

view

from rest_framework import viewsets, mixins, status
from rest_framework.response import Response
from .domain import use_cases, entities
from .repositories import UserRepository
from .serializers import UserSerializer

class UserViewSet(viewsets.GenericViewSet,
                 mixins.CreateModelMixin,
                 mixins.ListModelMixin):
                 
    queryset = User.objects.filter()
    serializer_class = UserSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        use_case = use_cases.CreateUserUseCase(UserRepository(), self.get_serializer)
        result_serializer = use_case.execute(serializer.save())
        
        return Response(result_serializer.data, status=status.HTTP_201_CREATED)

    def list(self, request, *args, **kwargs):
        use_case = use_cases.ListUsersUseCase(UserRepository(), self.get_serializer)
        result_serializer = use_case.execute()
        return Response(result_serializer.data)
profile
포폴 및 이력서 : https://gisanglee.github.io/web-porfolio/

0개의 댓글