Circular Dependency 이슈
Circular Dependency(순환 의존성)란 두 개 이상의 모듈, 클래스, 또는 컴포넌트가 서로를 참조하여 의존 관계가 순환하는 상태를 말한다. (ex. 모듈 A가 모듈 B를 참조하고, 모듈 B가 다시 모듈 A를 참조하는 경우)
주로 DI(의존성 주입) 구현을 위해 생성자를 주입하다가 설계 오류로 발생할 수 있다.
이러한 순환 의존성은 다음과 같은 문제를 야기할 수 있으므로 소프트웨어 아키텍처 설계에 있어 주의가 필요하다.
- 코드 유지보수 어려움: 의존 관계가 복잡해지면, 변경 사항이 다른 모듈에 미치는 영향을 추적하기 힘들다. A 클래스를 변경하는 경우 참조하는 클래스를 모두 변경한 뒤 다시 돌아와 A클래스에 다시 영향을 미칠 수 있다.
- 테스트 어려움: 단위 테스트를 수행할 때 테스트를 위한 의존성을 주입하거나 모의 객체(mock)를 설정하는 것이 복잡해진다.
- 리소스 낭비: 순환 의존성은 메모리와 리소스를 비효율적으로 사용할 수 있으며, 특정 상황에서는 객체가 해제 되지 않고 메모리에 남아 있을 수 있다.
- 의존성 주입 문제: 의존성 주입 프레임워크를 사용할 경우 순환 의존성이 발생하면 충돌하여 런타임 오류가 발생할 수 있다.
예시
다음 코드는 순환 의존성이 발생한 코드의 예시이다.
- 모듈 A가 모듈 B를 참조하고, 모듈 B가 다시 모듈 A를 참조
// 모듈 A
class ModuleA(val moduleB: ModuleB) {
fun doSomething() {
moduleB.doSomething()
}
}
// 모듈 B
class ModuleB(val moduleA: ModuleA) {
fun doSomething() {
moduleA.doSomething()
}
}
순환 의존성 제거 방법
순환 의존성를 끊기 위해서는 아래와 같은 방법을 사용할 수 있다.
1. 인터페이스를 통해 의존성 리팩토링
인터페이스를 도입하거나 중간 모듈을 추가하여 의존성을 분리한다.
// 인터페이스
interface ModuleBInterface {
fun doSomething()
}
// 모듈 A
class ModuleA(val moduleB: ModuleBInterface) {
fun doSomething() {
moduleB.doSomething()
}
}
// 모듈 B
class ModuleB: ModuleBInterface {
override fun doSomething() {
// Logic for Module B
}
}
2. 느슨한 결합(Losely Coupled) 설계
의존성을 최소화하고 모듈 간의 결합도를 낮추는 설계를 통해 순환 의존성을 방지한다. 예를 들어 이벤트 기반 아키텍처를 사용하여 컴포넌트 간의 직접적인 의존성을 줄일 수 있다.
모듈 간의 상호 작용을 직접적으로 연결하는 대신, 이벤트나 콜백 메커니즘을 통해 서로의 의존성을 끊을 수 있다.
예를 들어 이벤트 기반 아키텍처는 컴포넌트 간의 통신을 이벤트를 통해 비동기적으로 처리하는 설계 방식으로, 시스템의 각 컴포넌트는 이벤트를 발행하거나 구독하는 형식으로 필요한 작업을 처리한다. 컴포넌트 간에 직접적으로 호출하거나 참조하지 않고 이벤트라는 간접적인 매개체를 통해 상호작용하게 되므로 결합도가 낮아지고 각 컴포넌트는 독립적으로 실행되게 된다.
3. 의존성 주입(DI) 사용
DI 프레임워크를 사용하여 생성자 주입 대신 메소드 주입이나 필드를 주입할 수 있다. 이러한 주입 방식을 통해 객체가 필요한 의존성을 나중에 주입받을 수 있으므로, 순환 의존 문제를 피할 수 있다.
또한 interface만 활용하여 개발할 경우 수동으로 의존성을 관리해야하는 어려움이 발생하지만, DI 프레임 워크를 사용하면 이런 관리를 자동으로 해주기 때문에 더욱 쉽게 코드를 관리할 수 있다.
- 자동화된 의존성 관리: 객체가 필요로 하는 의존성을 자동으로 주입합니다. 수동으로 생성하지 않아도 된다.
- 생명 주기 관리: 객체의 생명 주기(싱글톤, 프로토타입 등)를 자동으로 관리한다.
- 구성 및 설정: 복잡한 의존성 관계를 쉽게 구성하고 설정할 수 있다.
- 유지보수 용이: 의존성 주입이 자동화되므로 코드 유지보수가 쉬워진다.
'Programming > Architecture' 카테고리의 다른 글
DI(의존성 주입)이란? / reflection(리플렉션) 개념 (0) | 2024.11.12 |
---|---|
[Architecture] MVC, MVP, MVVM Pattern (0) | 2024.01.13 |
SDK vs API (0) | 2023.04.11 |
프레임워크(Framework) vs 라이브러리(Library) (0) | 2023.04.11 |
댓글