본문 바로가기
  • 구름빵의 개발 블로그
프로그래밍

[Architecture Design] Facade 패턴

by 은빛구름빵 2025. 12. 26.

개요

웹 개발을 할 때 Facade 계층이라는 것이 있다. 일반적인 경우 웹 서버 개발을 하면 3 Tier 구조를 떠올릴 것이다. Controller를 통해 API 엔드포인트를 결정하고 Service 계층에서 비즈니스 로직을 구현한 다음 Repository를 통해 데이터베이스와 통신하는 것이 3 Tier 구조이다. 하지만 이 사이에 Facade라는 계층이 하나 더 들어가 조금 더 체계적이고 구체적인 책임 분리를 할 수 있다.

 

Facade 패턴

Facade 계층을 Controller와 Service 계층 사이에 들어간다. 그래서 Controller - Facade - Service - Repository로 향하는 4 Tier 구조가 이루어진다. Controller와 Service 사이에 위치한 이 계층은 확실한 역할을 갖고 있다. Controller는 기존과 동일하게 API의 엔드포인트를 결정하고 클라이언트에서 들어오는 초입 구간을 맡는다. 그리고 Service는 Repository와 통신해 단일 도메인에 대한 기본적인 데이터베이스 작업을 담당한다. 그리고 Facade는 Controller와 Service 사이에서 비즈니스 로직을 담당하게 된다.

이러면 Facade 계층이 Service 계층과 다를게 무엇이냐, 왜 굳이 나누는 것이냐 물어볼 수도 있다. 이는 3 Tier 구조와 4 Tier 구조를 비교하면 확실하게 알 수 있다.

3 Tier 구조의 Service 계층을 보면 n개의 Repository를 사용하고 수많은 비즈니스 로직이 하나의 클래스에 정의된 것을 볼 수 있다. 분명 이름을 "UserService"라고 만들었음에도 이를 사용하기 위해 AuthRepository, TeamRepository 등 User와 관련된 수많은 Repository를 가져와 사용해야 한다.

이렇게 되면 하나의 Repository에 대해 n개의 서비스에 의존성이 생긴다. 하나의 도메인에 대한 작업을 수행했는데 다른 도메인의 서비스에도 영향을 줄 수 있다는 뜻. 규모가 작은 서비스라면 쉽게 오류를 잡을 수 있겟지만 규모가 큰 서비스의 경우 연관된 부분을 모두 수정하는게 꽤 많은 리소스가 소모된다.

이를 해결하기 위해 Facade라는 새로운 계층을 추가한다.

 

┌───────────────┐
│   Controller  │
│ (API Layer)   │
└───────┬───────┘
        │
        ▼
┌───────────────────┐
│      Facade       │
│ (Use Case / Flow) │
└───────┬───────┬───┘
        │       │
        ▼       ▼
┌──────────┐ ┌──────────┐
│ Service A│ │ Service B│
└────┬─────┘ └────┬─────┘
     │            │
     ▼            ▼
┌──────────┐ ┌──────────┐
│Repository│ │Repository│
└──────────┘ └──────────┘

이처럼 API의 엔드 포인트를 정의하는 Controller를 출발해 Service가 아닌 Facade로 향한다. 

기존에는 Service로 향해 이 Service에서 비즈니스 로직을 구현했으면 Facade 패턴에서는 Facade 계층에서 비즈니스 로직을 구현하게 된다. 그럼 Service는 무슨 역할을 하는가?

Service는 단일 Repository에 접근할 수 있으며 해당하는 도메인에 대한 DB 작업을 담당하게 된다. 즉, 비즈니스 로직에서 필요한 데이터에 대한 작업을 실질적으로 Service에서 구현하는 것이다.

어떤 유저에 대한 마이페이지 정보를 조회하는 API를 만들 때, 이 응답 안에 해당 유저의 개인 정보와 해당 유저가 작성한 게시글 목록을 함께 넘겨야 한다고 할 때, UserFacade라는 계층에서는 User Service와 Post Service라는 두 개의 서비스에 각각 접근해서 데이터를 가져오게 된다. User Service를 통해 User 엔티티에 대한 정보를 가져오며 Post Service를 통해 해당 User가 작성한 Post 목록을 가져온다. 그리고 이 정보를 하나의 DTO에 담고 ResponseEntity 형태로 변환하는 로직을 Facade에서 구현하게 된다.

 

코드

@Service
@RequiredArgsConstructor
public class UserFacade {
    private final UserService userService;
    private final PostService postService;
    
    public UserMyPageResponse getUserMyPageInformation( long userId ){
    	UserMyPageResponse.UserMyPageResponseBuilder builder = UserMyPageResponse.builder();
        User user = userService.findById( userId );
        List<Post> userPost = postService.findAllByWriterId( userId );
        return builder
        			.id( user.getId() )
        			.name( user.getName() )
                    .email( user.getEmail() )
                    .nickname( user.getNickname() )
                    .posts( userPost.stream().map( Post::getName ).toList() )
                    .build();
    }
}

Facade를 보면 두 개의 서비스를 가져와서 사용한다. 

실제로 데이터를 가져오는 작업은 Service에서 이루어지고 그 데이터를 가져와 가공하고 정제하는 역할을 맡게 된다.

@Service
@RequiredArgsConstructor
public class UserService {
	private final UserRepository repository;
    
    public User findById( long userId ){
    	return repositroy.findById( userId ).orElseThrow( () -> new CommonException( ErrorCode.USER_NOT_FOUND ) );
    }
}

----------------------------------------------------
@Service
@RequiredArgsConstructor
public class PostService {
	private final PostRepository repository;
    
    public List<Post> findAllByWriterId( long writerId ){
    	return repository.findAllByWriterId( writerId );
    }
}

서비스에는 Repository를 사용해 데이터를 조회하는 코드 뿐이 없다. 실제로 Service에서는 주로 CRUD를 담당하는 로직이 존재한다. 이러면 Facade에서 바로 Repository를 연결해서 사용하면 되는 것이 아닌가? 라고 생각할 수 있다.

하지만 DB에 의존하는 객체들이 줄어들기 때문에 이 Facade 도입이 유리하게 작용할 수 있다.

'프로그래밍' 카테고리의 다른 글

[MSA] Kubernetes vs. Spring Cloud + Netflix Eureka  (0) 2026.02.03
Framework vs. Library  (0) 2025.06.30