NOW 프로젝트를 진행하면서 기록한 글입니다.
파사드 패턴(Facade Pattern)을 적용하게 된 이유
컨트롤러(Controller)에서 다음과 같은 문제점을 발견했는데요.
- 다수의 서비스 주입: 다수의 서비스 객체를 의존하고 있어서, 서비스 객체들과의 결합도가 높은 상태
- 컨트롤러의 복잡한 역할: 단순히 HTTP 요청과 응답 처리를 넘어서서 서비스 로직까지 직접 처리
제가 왜 그렇게 생각했는지 실제 구현된 코드를 살펴보겠습니다.
deletePhoto
핸들러 메서드는 다음과 같이 실행됩니다.
- 게시글 삭제 권한 확인(비즈니스 로직)
- 모든 댓글 삭제
- 모든 첨부파일 삭제
- 게시글 삭제
해당 코드를 볼때마다 나쁜 냄새(Bad Smell) 가 난다는 것을 계속 느꼈으며, 리팩토링이 필요하다고 생각했습니다.
처음으로 생각했던 방법은 주 서비스 객체인 PhotoService
객체에서 모든 책임을 갖도록 하는 것이였는데요.
클래스 다이어그램으로 표현하자면, 아래와 같습니다.
그렇다면, 개선된 컨트롤러의 코드도 살펴보겠습니다.
그전보다는 코드가 굉장히 깔끔해졌는데요.
하지만, 이러한 방식은 추후 문제가 발생할 수 있습니다.
순환참조 발생
현재 PhotoService
에 추가적인 NewsService
객체도 주입되어야 한다고 가정해보겠습니다.
public class PhotoService {
...
private final NewsService newsService;
}
그렇다면, 기존 필드에 NewsService
객체만 추가하면 되는데요.
만약 NewsService
객체에서도 PhotoService
를 주입해야 하는 상황이 발생한다면?
이렇게 되면 서로다른 객체가 서로를 주입해야하는 상황이 발생합니다.
이를 순환참조라고 합니다.
순환참조는 스프링 프레임워크에서 최대한 피하도록 권장합니다.
이러한 상황에서는 아래와 같이 Controller
와 Service
중간에 레이어를 추가하는 것으로 해결했습니다.
파사드 패턴(Facade Pattern) 적용
모든 서비스 객체를 하나의 객체(파사드 패턴이 적용된 객체)가 주입받아서 사용하도록 합니다.
컨트롤러는 파사드 패턴이 적용된 객체를 사용하면 됩니다.
따라서, 기존 Service
객체에서는 필요한 Repository
객체만 주입받아서 사용하도록 했습니다.
추가적으로, 파사드 패턴을 적용함으로써 트랜잭션 설정 관점에서도 편리함이 있었는데요.
그 이유는, 여러 개의 비즈니스 로직이 있는 서비스 메서드를 하나의 논리적 단위로 묶어서 트랜잭션으로 관리할 수 있었습니다.
아래 프로젝트에 적용했던 코드를 살펴보겠습니다.
트랜잭션 설정
이렇게 묶인 메서드 내에서 트랜잭션을 시작하고, 모든 작업이 성공적으로 완료되면 트랜잭션을 커밋하고, 만약 하나의 작업이라도 실패하면 트랜잭션을 롤백할 수 있습니다.
이로써 여러 서비스 메서드 간의 트랜잭션 관리가 훨씬 간단하고 일관된 방식으로 이루어질 수 있습니다.
마무리
현재 프로젝트에서 파사드 패턴을 적용하게 된 이유와 적용방법 그리고 트랜잭션 설정까지 간략하게나마 설명드렸습니다.
부족하거나, 개선할 부분은 앞으로 프로젝트를 진행하면서 차근차근 진행하고자 합니다.
긴 글 읽어주셔서 감사합니다.
'Spring' 카테고리의 다른 글
Spring Cache(스프링 캐시) 적용 (0) | 2023.08.26 |
---|---|
격리된 테스트 환경 구성 후 Repository 객체에 대한 테스트 코드 (0) | 2023.08.22 |
Spring의 Argument Resolver를 활용한 principal 주입 (0) | 2023.08.14 |
Spring AOP로 Slack 알람 구현 (0) | 2023.08.13 |
Spring AOP로 모든 요청과 응답 로그 기록 (0) | 2023.08.10 |
댓글