TIL (ToDay I LearNEd)/K P T (keeP, pRoBlem, Try) & 트러블슈팅

순환 참조란? Circular Dependency (일정 관리 앱 서버 DEVELOP 트러블 슈팅)

sooyeoneo 2024. 11. 15. 10:03

지난 일정 관리 앱 서버를 만들었던 부분에 user를 추가하여 develop을 했다.

JDBC 형식을 기반으로 하여 만들었던 서버를 JPA를 활용하여 만드는 방식으로 변경된다.

 

좀 더 보완된 ERD

 

오류 1

시작부터 오류가...

처음 BaseEntity에 User와 Schedule 클래스를 만들고 SQL문이 잘 나오는 지 확인하기 위해서 어플리케이션을 실행하였는데,

 

초장부터 오류가 나서 당황했지만, 

천천히 확인해보니

 

application.properties 에 데이터베이스의 이름을 잘못 입력한 것을 확인하였다.

 

 

먼저 생성했던 데이터베이스의 이름과 동일하게 입력 해준다.

 

 

다시 실행하니 SQL문이 잘 나오는 것을 확인할 수 있다.

 

이 밖에도 대부분의 오류가, 대소문자를 구별하지 못하거나 오타가 난 경우가 너무 많았다.

사소한 실수가 치명적인 실행 오류를 발생시켜서 매우 당황스럽고, 부끄러웠다..

오탈자를 잘 확인하고 타입이 무엇인지를 좀 더 명확히 인지해서 대소문자 실수를 해서는 안되겠다.

 

 

오류 2

로그인 기능 구현까지 어떻게 잘 마무리하고 나서 포스트맨에 요청을 보내기 위해 Application을 실행을 해준다.

당연하게(?) 오류가 생긴다.

 

 

한참을 해매다가 메서드 하나에서 문제가 발생한 것을 알게 되었다.

 

처음에 메서드가 잘 걸려있어서 다행이라고 생각했는데... 

 

순환 참조

참조하는 대상이 서로 물려 있어서 참조할 수 없게 되는 현상을 말한다.

한마디로 전혀 참조되지 않고 있었다...

 

순환 참조는 여러가지 문제를 일으킬 수 있어서 최대한 피하는 것이 좋다. 발생하면 해결하자

  • 메모리 누수 : 객체들이 서로를 계속 참조하면, 메모리에서 해제되지 않은 객체가 계속 쌓이면서 메모리 누수가 발생
  • 예측 불가능한 동작 : 순환 참조는 어떤 객체가 먼저 생성될 지, 또 어떤 객체가 어떤 다른 객체를 참조할지 예측이 어렵다. 
  • 가비지 컬렉션 오버헤드 : 순환 참조를 가진 객체는 가비지 컬렉션의 오버헤드를 증가시킨다. 가비지 컬렉터는 순환 참조를 가진 객체를 찾아내고 처리하는데 추가적인 자원이 소모된다.
  • 코드 복잡도 증가 : 순환 참조를 가진 객체들은 객체 간의 의존성이 복잡해지며, 코드의 가독성과 유지보수성을 저하시킨다. 순환 참조 객체들 중 어떤 한 객체에서 디버깅을 했을 때, 순환 참조가 되고 있는 객체들이 연쇄적으로 영향을 받을 수 있어 위험하다.

 

순환 참조는 클래스나 빈(Bean)이 서로를 참조하는 상황을 의미한다.

클래스 A가 클래스 B를 참조하고

클래스 B가 클래스 C를 참조하고

클래스 C가 다시 클래스 A를 참조하는..

 

순환참조가 발생하면, 객체 생성 시점에서 무한루프에 빠지게 되어 

프로그램이 정상적으로 동작하지 않을 수 있다.

 

이러한 문제를 해결하기 위해서는 순환참조가 발생하지 않도록 설계를 잘해야 하는데,

객체 간의 의존성을 최소화하고 의존성 주입 방법을 적절히 선택하여 해결한다.

 

해결 방법 정리

예시 상황 - A 클래스와 B 인터페이스가 순환 참조인 경우

1. 의존성 역전

  1. C 인터페이스를 만든다.
  2. A 클래스와 B 인터페이스 C 인터페이스를 참조하는 형식으로 개선

2. 외부 클래스 이용

C 클래스를 의존하게 만드는 B 인터페이스에 있는 로직을 외부 클래스로 뺀다.

  1. B 인터페이스가 C 인터페이스를 의존하는 것을 제거
  2. C 인터페이스와 B 인터페이스의 의존 관계를 외부(D 인터페이스)에서 연결한다. 

 

그러나 한정된 시간적 여유로 인해,

당장 문제를 일으키는 메서드를 제거하여 코드 복잡도를 개선하는 것이 빠른 해결 방법이라고 판단하였다.

 

그래서 entity.Schedule에 있는 getUserId( ) 메서드를 삭제하기로 하였다! 

 

파란색으로 표시된 부분은 원래 getUserId로 Id를 받고 있다고 메서드를 입력한 코드이다.

모두 getUserId -> schedule.getUser( ).getId( )로 바꿔준다.

ScheduleServiceImpl 에서 수정

 

ScheduleResponseDto 에서도 수정

 

 

코드를 수정한 후

다시 실행해보면 정상적으로 작동된다.



 

 

 

 

 

 

TIL 11월 15일