계층 역할
Repository DB 접근 담당
Service 비즈니스 로직 담당
UseCase 사용자 시나리오(행위) 담당

 

Repository

DB 접근 전담 계층

class UserRepository:

    async def get_by_id(self, user_id: int):
        ...

    async def save(self, user: User):
        ...

    async def delete(self, user: User):
        ...

특징

- SQLAlchemy 코드 존재

- session 사용

- ORM 처리

- CRUD 담당

 

if user.is_banned:
    raise Exception()

위 코드 처럼

Repository는 비지니스 판단을 하면 안 됨

이건 Service/UseCase 책임

 

Repository는 최대한 단순하게

데이터 가져오기/저장하기

Service

비즈니스 로직 처리

class OrderService:

    async def create_order(self, user_id, product_id):

        product = await repo.get_product(product_id)

        if product.stock <= 0:
            raise OutOfStock()

        product.stock -= 1

        await repo.save(...)

재고 검사와 같은 '업무 규칙' 처리

 

특징

- 여러 Repository 조합 가능

- 외부 API 호출도 여기서 많이 함

UseCase

사용자 행동(시나리오) 단위

class CreateOrderUseCase:

    async def execute(self, user_id, product_id):
        ...

회원가입, 로그인, 주문하기, 게시글 작성 같은 것 자체가 UseCase

 

굳이 Service랑 나누는 이유는?

 

service는 보통 재사용 가능한 업무 로직 중심

작은 업무 기능들

payment_service.pay()
inventory_service.decrease_stock()
coupon_service.apply()

usecase는 사용자 요청 흐름

전체 사용자 시나리오 orchestration

class PurchaseProductUseCase:

    async def execute(...):

        apply_coupon()

        pay()

        decrease_stock()

        create_order()

보통 구조는 아래와 같음

Controller(API)

    ↓

UseCase

    ↓

Service

    ↓

Repository

    ↓

DB

 

단순화도 많이 함

 

1. 작은 프로젝트

Controller > Repository

 

2. 일반적

Controller > Service > Repository

 

3. 큰 규모

Controller > UseCase > Service > Repository

 

사람마다 회사마다 용어를 다르게 쓰는 경우도 있음

특정 아키텍처가 정해져있기보다는 '책임을 어디까지 분리할 것인가'가 핵심