티스토리 뷰
순환참조는 뭐가 문제일까?
개인 프로젝트는 혼자서 진행하기 때문에 내가 만든 설계가 제대로 된 설계인지 확인해보기 어렵다. 이를 확인하기 위해서 한 가지 기준을 두었는데 패키지간의 의존 방향을 단방향으로 하여 순환되지 않도록 하자는 것이었다. 다이어그램을 그려보고 의존성이 단방향을 나타낼 때는 제대로 된 설계를 했다는 성취감도 들었다. 그러다 문득 이런 생각이 들었다. '그래서 순환참조가 뭐가 문제일까?'
의존
먼저 의존에 대해서 다시 생각해보았다. A객체가 B객체에게 의존한다는 것은 A객체가 B객체를 사용한다는 것이다. 다이어그램으로 화살표를 나타내면 A→B라는 형태로 나타난다. 만약 '변경에 의한 영향' 이라는 기준에서 생각해보면 화살표의 방향은 반대로 나타내야 될 것이다. B가 변경될 때 A에게 영향을 주기 때문이다. 이러한 관점에서 볼 때 '의존'한다는 것은 단순하게 생각하는 것 이상으로 많은 책임이 따른다. 무언가를 의존하기 전에 해당 컴포넌트에 대한 변경에 영향을 받을 수 있다는 사실을 명심해야 한다.
조영호 님의 '우아한 객체지향' 세미나를 보면 앞부분에 아주 짧게 언급되지만 해당 세미나를 관통하는 말을 지나가듯이 하신다. '설계란 코드를 어디에 위치시킬 것인가에 대한 의사 결정이다. 이에 대한 결정은 변경에 초점을 맞추는 것이며 변경되는 코드들을 함께 넣어야 한다. 변경에 핵심은 의존성이다.'
순환참조의 문제점
개발할 당시에는 문제가 없었는데 통합 테스트를 진행하거나 배포 이후에 문제가 생긴다면 의존하는 컴포넌트에 영향일 가능성이 높다. 의존되는 컴포넌트들이 무엇이고 이것들이 어떻게 달라질지 예상한다면 이런 상황을 방지하는 것이 가능하겠지만, 컴포넌트가 순환참조를 일으킨다면 예상하기 어렵다.
순환참조가 발생되면 컴포넌트 간의 명확한 경계가 사라지고 연쇄적으로 변경에 의한 영향이 발생할 수 있다. 이로 인하여 개발과 유지보수 속도에 영향을 끼치고 예상치 못한 문제점을 만들어 낼 가능성도 높다. 이 후에 컴포넌트들을 분리해내도 어려워진다. 컴포넌트를 분리해내기 어렵다면 단기적으로 테스트하기가 어려워질 것이고, 장기적으로 협업하기 어려워지고 DDD나 MSA와 같은 개발 아키텍처를 구성할 수 없게 된다.
엉클밥 아저씨는 컴포넌트 간에 순환참조가 있어서는 안 된다고 말하며 ADP (Acyclic Dependencies Principle)라는 한 가지 설계 원칙도 만들었다. 의존성 구조에 순환이 발생하는지 항상 관찰하며 순환이 발생한다면 어떤 식으로든 끊어야 한다고 강조한다.
순환참조(의존) 끊어내는 방법
의존이 정말로 필요하다고 느껴진다면, 그리고 해당 의존이 순환참조를 발생시킨다면 인터페이스를 통해서 의존 방향을 변경시켜야 한다. 익숙한 예제로는 의존관계를 역전시키는 DIP가 있다.
Entities가 Authorizer에게 의존하게 되어 순환참조가 발생하게 된다면 해당 의존관계를 역전시켜야 한다. 직접적으로 의존하지 않고 User가 필요로 하는 기능을 인터페이스로 만들고 이를 Authorizer에서 구현한다면 의존 방향이 역전된다. (참고로 연관, 상속, 구현 관계 또한 추상적인 키워드로 의존이라 말할 수 있다.)
의존을 끊어내는 방법에 DIP처럼 의존을 역전시키는 방법도 있지만 인터페이스를 활용하여 의존의 방향을 우회시킬 수도 있다. 쉽게 말해 A ↔ B 간에 상호 참조가 발생하였을 때 A → C ← B와 같은 구조를 만들어 낼 수도 있고 생성 패턴을 사용하여 C → A, C → B → A 와 같은 방향을 갖게 할 수 도 있다. 핵심은 인터페이스를 사용하여 컴포넌트간의 순환참조를 끊을 수 있다는 점이다. 상황에 맞는 방법을 고려해보자.
참고
- 우아한 객체지향 (조영호) - 우아한 테크 세미나
- UML, 실전에서는 이것만 쓴다! - 로버트 C. 마틴
- 클린 아키텍쳐 - 로버트 C. 마틴
- https://softwareengineering.stackexchange.com/questions/306483/how-to-solve-circular-dependency
'Design Pattern' 카테고리의 다른 글
어댑터 패턴 (Adapter Pattern)은 언제 사용해야 할까? (0) | 2020.08.31 |
---|---|
적절한 메서드 위치에 대한 고찰 (0) | 2020.03.26 |
다형성을 이용한 클린코드 지향하기 (0) | 2020.02.16 |
LSP(리스코프 치환 원칙) - 오리와 오리장난감은 진짜 LSP 위반일까? (0) | 2019.11.17 |
템플릿/콜백 패턴이란? (1) | 2019.04.01 |