✍️ 개발 기록

[👀 Owing] 멀티모듈 - 모듈 간 순환참조 이슈 해결 과정 💥

ming412 2024. 11. 5. 14:34

진행하고 있는 프로젝트에서 멀티모듈을 적용하며 모듈 간 순환참조 이슈가 발생했고,

그 해결 과정을 기록해두려 한다.

 

현재 상황

현재 설계

 

- `Owing-Domain`: 애플리케이션의 핵심 도메인 로직을 담당하는 모듈이다. 주요 엔티티, 비즈니스 규칙, 도메인 서비스 등을 포함한다. Owing-Domain은 애플리케이션의 핵심 비즈니스 규칙과 모델을 정의하고, 가능한 한 외부 시스템(API, 데이터베이스, UI 등)에 종속되지 않아야 한다.

- `Owing-Api`: 애플리케이션의 외부 진입점 역할을 하며, HTTP 요청을 처리하고 응답을 반환하는 등 애플리케이션의 외부와 상호작용하는 부분을 담당하는 모듈이다. 컨트롤러, DTO, 요청/응답 매핑 로직 등을 포함한다.

 

즉, 아래처럼 Owing-Api 모듈이 Owing-Domain 모듈을 참조하고 있는 상황이다.

 

Owing-Api가 Owing-Domain을 참조하는 형태

 

모듈 간 순환참조 발생

이러한 상황에서, 아래와 같이 DomainService에서 Dto를 직접 참조하니 다음과 같은 에러 메시지가 나타났다.

 

`UniverseDomainService.java`

@Transactional
public Universe updateUniverse(Universe universe, UpdateUniverseRequest updateUniverseRequest) {
    universe.updateName(updateUniverseRequest.getName());
    universe.updateDescription(updateUniverseRequest.getDescription());
    universe.updateImageUrl(updateUniverseRequest.getImageUrl());
    return universe;
}

 

Circular Dependency Warning

 

순환참조가 발생할 가능성이 있다는 것인데, 멀티모듈을 처음 접해보니 각 모듈간 참조 관계가 익숙치 않았다.

따라서 DomainService에서 Dto를 참조하는 모습을 시각화해보니 순환참조가 발생한 이유를 알 수 있었다.

 

DomainService에서 Dto 참조 시 순환참조 발생

 

Owing-API에서 Owing-Domain을 참조하는 방향으로 서비스가 흘러가야 하는데, 그 반대 방향으로의 참조가 생긴 것이다.

 

순환참조 해결

이전 코드처럼 DomainService에서 Dto를 직접 참조하는 것이 아닌, Universe 객체를 참조하는 방식으로 해결했다.

Mapper를 이용해 수정할(=새로운) Universe 객체를 조립한다.

 

`UniverseDomainService.java`

@Transactional
public Universe updateUniverse(Universe oldUniverse, Universe newUniverse) {
    Universe updatedUniverse = oldUniverse.updateUniverse(newUniverse);
    return updatedUniverse;
}

 

`UpdateUniverseUseCase.java`

@Transactional
public UniverseShortInfoResponse execute(Long universeId, UpdateUniverseRequest updateUniverseRequest) {

    Universe oldUniverse = universeAdaptor.findById(universeId);
    Universe newUniverse = universeMapper.toEntity(oldUniverse, updateUniverseRequest); // Mapper를 이용해 객체 생성
    Universe updatedUniverse = universeDomainService.updateUniverse(oldUniverse, newUniverse);
    return universeMapper.toShortInfoResponse(updatedUniverse);
}