포스트

순환 참조 문제 해결: @Lazy는 임시방편일 뿐

순환 참조 문제 해결: @Lazy는 임시방편일 뿐

문제 상황

카카오테크캠퍼스에서 선물하기 API를 구현하다가 순환 참조 문제를 겪었다.

1
2
ProductService → OptionService
OptionService → ProductService

옵션을 생성할 때 상품이 있는지 확인해야 해서 OptionService에서 ProductService를 참조했다. 그런데 ProductService에서도 옵션 관련 로직 때문에 OptionService를 참조하고 있었다.

애플리케이션을 실행하니까 순환 참조 에러가 떴다.


임시 해결: @Lazy

일단 @Lazy 어노테이션을 붙여서 해결했다.

1
2
3
4
public OptionService(OptionRepository optionRepository, @Lazy ProductService productService) {
    this.optionRepository = optionRepository;
    this.productService = productService;
}

@Lazy를 붙이면 빈 생성 시점을 실제로 사용할 때까지 지연시켜서 순환 참조 에러를 피할 수 있다.


멘토님 피드백

그런데 멘토님한테 이런 피드백을 받았다.

“순환 참조가 발생했다는 건 두 클래스가 서로 너무 깊게 엮여 있다는 증거예요. @Lazy로 순환 참조 에러를 임시적으로 회피할 수는 있지만, 설계를 개선해야 합니다.”


근본적인 해결책

멘토님이 제안한 방법들:

1. 정말로 서로 의존해야 하는지 점검

  • 양쪽에서 쓰는 로직을 다시 살펴보니, 일부는 굳이 서비스를 통하지 않아도 됐다
  • Repository를 직접 주입받아서 해결할 수 있는 부분이 있었다

2. 단방향으로 바꾸기

  • 양방향 의존을 단방향으로 바꿀 수 있는지 검토
  • 한쪽 서비스에서 다른 쪽 서비스를 참조하지 않도록 로직을 재배치

3. 파사드 서비스 도입

  • 두 서비스를 조합해서 쓰는 상위 레이어 서비스를 만든다
  • ProductOptionFacade 같은 걸 만들어서 두 서비스를 조합

[이미지 필요] 순환 참조 의존성 다이어그램 (변경 전: 양방향 화살표 / 변경 후: 단방향 또는 파사드 패턴)


배운 점

  • @Lazy는 순환 참조를 “숨기는” 것이지 “해결하는” 게 아니다
  • 순환 참조가 생기면 설계가 잘못됐다는 신호다
  • 객체지향 설계에서 의존성 방향은 정말 중요하다
  • 당장 돌아가게 만드는 것보다 구조를 고치는 게 나중에 훨씬 편하다

카카오테크캠퍼스 3기 선물하기 API 클론 코딩 중 멘토님 피드백 정리.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.