프로젝트/팀 개발일지

[Spring Boot/Toy Project] Quostomize - 코드리뷰에서 배운 점(ResponseEntity.noContent().build(), Fetch Join, @EntityGraph, 생성자 레벨 @Builder 패턴 사용)

Se On 2024. 11. 20. 22:40

💭 초기 목표

  • REST API의 응답 처리 방법을 학습하고, 팀 내에서 통일된 코딩 스타일 적용하기
  • JPA의 lazy 로딩 문제를 해결하여 성능 최적화를 달성하기
  • 빌더 패턴 사용 시 안전한 객체 생성 방식을 채택하기

🖼️ 현실

1. ResponseEntity 사용

  • 초기에는 모든 성공 응답에 ResponseEntity.ok().build()를 사용했으나, 코드리뷰를 통해 상황별로 더 적합한 응답 방식을 학습하였습니다.
  • ResponseEntity.noContent().build() (추천)
    • 반환값이 없음을 명시적으로 나타내야 할 때 사용합니다.
    • 클라이언트와 명확한 의사소통이 필요할 때 적합합니다.
    • DELETE 요청, 비동기 작업 시작, 또는 리소스 업데이트 후 반환 데이터가 필요하지 않은 경우에 권장됩니다.
  • ResponseEntity.ok().build()
    • 기존 REST API가 일반적으로 200 OK를 반환하도록 설계되어 있을 때 사용합니다.
    • 반환값이 없지만 성공 상태임을 간단히 나타낼 때 적합합니다.
    • GET, POST 요청에서 특정 데이터 없이 성공 상태만 반환하려는 경우 사용 가능합니다.

 

2. JPA Lazy 로딩 문제

  • findBy... 메서드
    : findCardBenefitsByCardDetailCardSequenceIdAndIsActive 메서드에서 lazy 로딩으로 인해 예상치 못한 N+1 문제가 발생하였습니다.
  • 이를 해결하기 위해 두 가지 방법을 학습하였습니다.
  • Fetch Join: 명시적으로 쿼리 내 JOIN FETCH 키워드를 사용합니다. 
@query("SELECT cb FROM CardBenefit cb JOIN FETCH cb.cardDetail JOIN FETCH cb.upperCategory JOIN FETCH cb.lowerCategory WHERE cb.cardDetail.cardSequenceId = :cardSequenceId AND cb.isActive = :isActive")
Set findCardBenefitsByCardDetailCardSequenceIdAndIsActive(@param("cardSequenceId") Long cardSequenceId, @param("isActive") boolean isActive);
  • @EntityGraph: 코드 가독성을 높이며 연관 엔티티를 한 번에 로드합니다.
@entitygraph(attributePaths = {"cardDetail", "upperCategory", "lowerCategory"})
Set findCardBenefitsByCardDetailCardSequenceIdAndIsActive(Long cardSequenceId, boolean isActive);
  • 코드리뷰를 통해 JPA 기본 동작을 이해하고, 성능 최적화를 위해 추가적인 설정이 필요함을 깨달았습니다.

 

3. Builder 패턴 사용

  • 클래스 레벨 @Builder의 위험성을 인지하였습니다.
    • 모든 필드가 빌더에 노출되어, @Id 등 의도하지 않은 필드가 설정될 가능성이 있기 때문입니다.
  • 생성자 레벨에 @Builder를 적용하여 더 안전한 객체 생성을 보장하였습니다.

✏️ 배운 점

  • 코드리뷰를 통해 사소한 선택이라 생각했던 ResponseEntity 사용 방식이 실제로는 클라이언트와 서버 간의 명확한 의사소통에 큰 영향을 미친다는 점을 배웠습니다.
  • JPA의 기본 lazy 로딩 동작과 이를 해결하는 방법(fetch join, @EntityGraph)을 이해하면서, 성능 최적화와 유지보수성 간의 균형을 고려할 필요성을 인식하였습니다.
  • 빌더 패턴 사용 시 안전성과 명확성을 최우선으로 해야 함을 깨달았습니다.

🎯 목적

지속할 점

  • ResponseEntity.noContent().build()와 같은 상황별로 적합한 응답 방식을 선택해 클라이언트와의 소통을 강화하였습니다.
  • 성능 최적화를 위해 JPA에서 즉시 로딩(fetch join, @EntityGraph)을 활용하였습니다.

개선할 점

  • lazy 로딩 문제를 미리 감지하고 방지할 수 있도록 추가적인 테스트 케이스 작성할 예정입니다.
  • 빌더 패턴 적용 시, 자동 생성 필드가 빌더에 포함되지 않도록 리팩토링하였습니다.
반응형