백엔드 개발하다 보면 Controller, Service, Repository 계층 구조에 익숙해짐.
근데 비즈니스 로직이 복잡해질수록 Service가 비대해지거나, Controller가 너무 많은 Service를 호출하는 문제가 발생함.
이럴 경우 사용해야 하는 것이 파사드(Facade) 레이어.
실무에서 파사드 패턴을 도입해야 하는 확실한 타이밍 3가지를 정리해 봄.
건물의 정면(출입구)을 의미하는 단어처럼, 복잡한 내부 로직을 감추고 외부(Controller)에는 깔끔한 인터페이스만 보여주는 역할을 함.
핵심 역할: Controller와 여러 Service 사이의 중간 조율자 (Orchestrator)
하나의 API 요청을 처리하기 위해 3~4개의 Service를 호출해야 한다면, Controller가 과도한 책임을 지고 있다는 신호임.
OrderService, PaymentService, DeliveryService를 다 주입받아서 순서대로 호출함. 로직이 Controller에 노출됨.OrderFacade 하나만 알고 있음. "주문해줘"라고 요청하면 끝.개발하다 보면 UserService가 PointService를 참조하고, 반대로 PointService가 UserService를 참조해야 하는 상황이 옴. 이때 서로 import 하면 순환 참조 에러가 발생함.
이때 파사드가 두 서비스를 위에서 내려다보며 조율하면, 서비스끼리는 서로 몰라도 되므로 순환 참조가 깔끔하게 해결됨.
여러 서비스의 로직이 '전부 성공하거나, 전부 실패해야 하는(Atomic)' 경우임.
개별 Service에 트랜잭션을 거는 것만으로는 부족할 때, 파사드 메서드에 @Transactional을 걸어 전체 흐름을 하나의 트랜잭션으로 묶어주기 좋음.
사용자가 '상품 구매'를 요청했을 때의 흐름 비교.
Controller가 비즈니스 흐름(재고 확인 -> 결제 -> 알림)을 다 알고 있음. 코드가 지저분하고 재사용이 어려움.
# controller.py
class OrderController:
def __init__(self, inventory_svc, payment_svc, noti_svc):
self.inventory_svc = inventory_svc
self.payment_svc = payment_svc
self.noti_svc = noti_svc
def order(self, request):
# 1. 재고 감소
self.inventory_svc.decrease(request.product_id)
# 2. 결제 시도
self.payment_svc.pay(request.user_id, request.amount)
# 3. 알림 발송
self.noti_svc.send(request.user_id, "주문 완료")
return "Success"
Controller는 단순해지고, 비즈니스 흐름의 조합은 Facade가 전담함.
# facades/order_facade.py
class OrderFacade:
def __init__(self, inventory_svc, payment_svc, noti_svc):
self.inventory_svc = inventory_svc
self.payment_svc = payment_svc
self.noti_svc = noti_svc
# 여러 서비스의 흐름을 하나의 트랜잭션으로 관리하기 용이함
def process_order(self, user_id, product_id, amount):
self.inventory_svc.decrease(product_id)
self.payment_svc.pay(user_id, amount)
self.noti_svc.send(user_id, "주문 완료")
# controller.py
class OrderController:
def __init__(self, order_facade):
self.order_facade = order_facade
def order(self, request):
# 깔끔해진 컨트롤러
self.order_facade.process_order(
request.user_id,
request.product_id,
request.amount
)
return "Success"