[내일배움캠프Spring-31일차] 과제 트러블슈팅

2025. 4. 1. 14:44·백엔드 부트캠프/TIL
 

🤔 고민했던 부분 

프로젝트 하면서 고민했던 부분을 담아보았다.

 

1️⃣ 생성자 전달 방식 vs 정적 팩토리 메서드 방식

🔍 문제 상황

" 실제 데이터 Entity 를 dto 로 담을려고 하고 있다. 그런데 두 가지 방식 중 어떤 방식으로 선택해야하는지 고민하게 되었다. "

1. dto 를 지금 생성자로 this.~ 만든 후, 그걸 다시 new ~ 하여 불러주는 방법.

2. dto 를 toDto() 라는 함수를 통해서 return 을 dto 로 바꾸어주는 메서드를 활용하는 방법

🧠 문제 분석

" 생성자 vs 정적 팩토리 메서드 비교 "

1️. 생성자 (new)

✅ 장점

  • 직관적이며 익숙한 방식이다.
  • 컴파일 타임에 오류를 쉽게 발견할 수 있다.
  • 불변 객체에서 final 필드 초기화가 용이하다.

❌ 단점

  • 메서드명을 가질 수 없어 어떤 변환을 수행하는지 알기 어렵다.
  • 불필요한 new 호출이 필요해 코드가 길어진다.
  • 생성자 오버로딩이 많아질 경우 가독성이 저하된다.
  • 반환 타입을 유연하게 변경할 수 없다.
  • 객체를 재사용할 수 없어 매번 새로운 인스턴스를 생성해야 한다.

2. 정적 팩토리 메서드 (from(), of(), valueOf() 등)

✅ 장점

  • 의미 있는 메서드명을 사용할 수 있어 가독성이 좋다.
  • 객체 생성을 캡슐화할 수 있다.
  • 다양한 입력 형식을 지원할 수 있다.
  • 반환 타입을 유연하게 지정할 수 있다.
  • 객체 재사용 및 싱글턴 패턴 적용이 가능하다.

❌ 단점

  • 상속이 불가능해 서브클래스에서 재사용하기 어렵다.
  • 프로젝트 내 네이밍 컨벤션이 일관되지 않으면 혼란을 초래할 수 있다.

🔑 문제 결론

" 일반적인 DTO 변환에는 from(User user)을 추천 "

비교 항목 생성자 (new) 정적 팩토리 메서드 (from)
가독성 의미 불명확 메서드명을 통해 직관적으로 전달 가능
유연성 new 키워드 필요 필요 시 캐싱된 객체 반환 가능
확장성 생성자 오버로딩이 많아질수록 복잡해짐 다양한 입력을 받는 여러 메서드 정의 가능
반환 타입 항상 해당 클래스의 인스턴스 반환 서브클래스나 인터페이스 구현체 반환 가능
객체 재사용 매번 새로운 객체 생성 필요 시 캐싱된 객체 반환 가능
싱글턴 패턴 지원 불가능 가능

- 단순한 객체 생성 → 생성자 (new)

- 객체 변환 & 유연한 생성 필요 → 정적 팩토리 메서드 (from())


2️⃣ Client에서 Server로 Data를 전달하는 방법 고려

🔍 문제 상황

일정의 댓글을 조회하는 과정에서 일정의 ID를 어떤 방식으로 받아올지 고민했다.

1. api 관점에서 "/comments/postID" 이런식으로 PathVariable 를 받아 오는게 나을지.

2. PostId 를 Dto 에 담아서 보낼지

2가지 방식을 고민하고 있었다.

🧠 문제 분석

1. API URL 설계

  • API를 설계할 때 자원(Resource) 단위로 URL을 정리하는 것이 좋다고 알려져 있다.
  • 따라서 댓글(Comment)을 조회하거나 추가할 때, 상위 객체인 Plan을 통해 접근하는 방식이 더 적절하다고 판단된다.

2. Post ID를 DTO에 포함할지?

  • Post ID를 DTO에 포함하는 방식은 확장성이 좋지만, Controller에서 의미 파악이 어려울 수 있다는 고민이 있었다.
  • DTO에 포함하면 확장성이 좋아진다.
  • 하지만 Controller만 보고 의미를 직관적으로 이해하기 어려울 수도 있음.

=> 최종 결정

  • DTO에 포함하는 방식을 사용하지 않고, URL에서 Plan ID를 통해 접근하는 방식으로 통일하자

🔑 문제 결론

" /plans/{id}/comments 방식으로 API를 설계하기로 하기로 했다!

이렇게 하면 API의 계층 구조가 명확해지고, 특정 Plan에 속한 댓글을 조회한다는 점에서 요청 api 가 직관적이게 된다. "

- 고려한 URL 방식은 아래와 같다.

  • ❌ /comments/{postId} → 개별 자원인 Comment에 직접 접근하는 방식
  • ✅ /plans/{id}/comments → Plan을 통해서 접근하는 방식

! 추가적인 정리

- API를 설계할 때 자원(Resource) 중심의 URL을 따르는 것이 좋다는 원칙을 적용했다.

- 따라서 댓글(Comment)은 Plan을 통해 접근하는 방식(/plans/{id}/comments)을 선택했다.

- 또한, Post ID를 DTO에 포함하는 방식은 확장성은 있지만 Controller에서의 가독성을 고려하여 사용하지 않기로 결정했다.

- 이러한 고민 과정을 거쳐 최종적으로 API를 /plans/{id}/comments 방식으로 설계 했다.

3️⃣ HttpServletrequest 의 DTO 변환 로직의 위치 고민

🔍 문제 상황

" 컨트롤러에서 HttpServletrequest를 LoginDto로 변환하는 것이 맞을까? 아니면 서비스 계층에서 처리하는 것이 더 좋을까? "

🧠 문제 분석

1. 컨트롤러에서 처리하는 경우

  • 요청(Request)을 받는 관점에서 적절하다.
  • 요청 데이터를 검증하고, DTO로 변환하여 서비스로 전달하는 것이 역할에 맞다.

2. 서비스에서 처리하는 경우

  • request가 서비스에 종속될 수 있다.
  • 서비스 계층의 재사용성이 낮아질 가능성이 있다.
  • 따라서 이 방식은 적절하지 않다고 판단.

🔑 문제 결론

" 컨트롤러에서 LoginDto로 변환하는 방식이 더 적절하다고 판단하여 선택! "

4️⃣ 패키지를 Entity 별로 분리한 이유

🔍 문제 상황

Dto 의 파일이 많아져서 분류를 할 필요성이 생겼음

🧠 문제 분석

- Entity를 기준으로 기능을 만들기 때문에 Entity 별로 패키지를 만드는 게 편리할 거 같음

- 오류 발생 시 Entity, Request, Response를 함께 확인해야 함

- 관련된 파일들을 한 패키지에 묶으면 유지보수가 용이

🔑 문제 결론

" Entity를 기준으로 패키지를 나누면 연관된 클래스들을 한 곳에서 관리할 수 있어 유지보수가 쉽다! "

5️⃣ Repository 에서 Optional 로 데이터를 넘기기

🔍 문제상황

" Repository 의 Optional 데이터를 Optional 그대로 넘길지 아니면 OrElseThrow 형식으로 null 값을 처리한 상태로 넘길지 고민했다. "

🧠 문제 분석

  • Repository에서 Optional을 반환하면 Service 계층에서 이를 해석하고 예외를 처리해야 하므로, 서비스 로직이 복잡해짐.
  • Optional로 감싸진 Entity는 바로 사용하기 어렵고, 불필요한 래핑 해제 로직이 생김.
  • Service에서 직접 Optional을 다루게 되면 도메인 객체를 이용한 비즈니스 로직 구성 시 불편함 발생.
  • 계층 분리 원칙에 따라 예외는 Service에서 처리하는 것이 일반적이지만, 도메인과 서비스 간의 효율적인 흐름이 깨질 수 있음.
  • Repository는 단순히 데이터를 제공하는 역할인데, Optional 자체도 데이터를 바로 주는 방식에는 부적절할 수 있음.

🔑 문제 결론

  • Optional은 Repository 내부에서 적절히 처리하고, 유효한 Entity를 직접 반환하는 방식이 더 나음.
  • 유효성 검사 및 예외 처리는 Repository에서 하고, Service에서는 필요한 객체만 바로 활용할 수 있게 한다.
  • Repository에 default 메서드를 두어 예외를 던지도록 구성하면 좋음.
  • 이렇게 하면 서비스는 비즈니스 로직에만 집중할 수 있음.

6️⃣ 로그인 기능은 PostMapping

🔍 고민 상황

로그인 기능을 만들 때 @GetMapping을 사용할지, @PostMapping을 사용할지에 대한 고민이 생김.
로그인이 단순히 데이터 조회(GET)처럼 보일 수도 있지만, 실제로는 서버의 상태를 변경하므로 어떤 방식이 REST 원칙에 더 부합하는지 판단이 필요함.

🧠 문제 분석

  1. 로그인은 서버 상태를 변경하는 작업이다.
    • 로그인 시 서버는 세션 생성 또는 토큰 발급 등을 통해 상태를 변화시킨다.
    • 단순 조회가 아닌, 인증 및 보안 관련 처리가 포함됨.
  2. POST는 상태 변경을 위한 HTTP 메서드이다.
    • POST는 데이터를 전송하여 서버의 상태를 바꾸거나 새로운 리소스를 생성하는 데 사용된다.
    • 로그인은 새로운 리소스를 생성하진 않지만, 인증 상태를 생성한다는 점에서 POST가 적절하다.
  3. GET은 안전하고 멱등적이어야 한다.
    • GET 요청은 서버의 상태를 변경하지 않아야 하며, 같은 요청을 여러 번 보내도 결과가 같아야 한다.
    • 로그인은 그 자체로 서버에 변화를 일으키므로 GET에 부적절하다.

🔑 문제 결론

  • 로그인은 반드시 POST 방식으로 처리해야 한다.
  • 서버 상태(세션 생성, 토큰 발급 등)를 변경하는 행위이기 때문에 GET이 아닌 POST가 REST 아키텍처 원칙에 부합한다.
  • 보안 측면에서도 GET은 URL에 정보가 노출될 수 있어, 로그인과 같은 민감한 작업에 적절하지 않다.
  •  

 

 

트러블 슈팅

실제 에러가 났던 부분을 정리한 부분입니다. 😮

 

1️⃣ 원인 분석 불가 오류

🔍 문제 상황

- 406 에러가 떴다.해당 에러는 클라이언트가 요청한 콘텐츠 형식을 서버가 지원하지 않을 때 발생한다. 

- 일단 DB 에 처리는 되어진 상황인데 응답 Json 만 반환되지 않는 것이다.

🧠 문제 분석

- Response Dto 에 문제가 있는 거 같다.

- 실제 DB 에는 반영이 잘 되었는데, 반환만 못한 것이니 Dto 오류 형식에 문제가 있는 것이다.

🔑 문제 결론

- 이번 오류가 신기한게 나는 뭐 특별히 만진게 없다.

- 근데 해결이 됐다. 왜일까.. ? dto 의 코드 속에서 주석이 하나 빠졌었나 싶다.

2️⃣ 페이징 빈배열 반환

🔍 문제 상황

- 페이징 구현 후 테스트 하는 상황에서 자꾸 빈배열만을 반환했다.

🧠 문제 분석

- 코드에 디버그를 찍고, 확인해보았는데 특별한 오류는 없었다. log 를 찍어보았는데도 오류는 보이지 않고 그저 빈배열만 찍혔다.

- 왜일까 왜일까 30분간 해맸는데, 내가 입력값으로 PageNumber 를 큰 값을 주고 있었다.

🔑 문제 결론

- PageNumber 값을 적절하게 낮추어주니 문제가 해결됐다.

- 해당 부분을 생각 못해서 엄한 곳만 수정했다. 그나마 긍정적으로 생각하는게.. 해당 부분을 거치면서 Page Info 도 map 형태로 정리하여 반환해주는 코드를 만들었다.

 

'백엔드 부트캠프 > TIL' 카테고리의 다른 글

[내일배움캠프Spring-33일차] CH 3 일정 관리 앱 Develop 完  (0) 2025.04.03
[내일배움캠프Spring-32일차] CH 3 일정 관리 앱 Develop Lv7~Lv8, Refactoring  (1) 2025.04.02
[내일배움캠프Spring-30일차] CH 3 일정 관리 앱 Develop Lv2~Lv6  (0) 2025.03.31
[내일배움캠프Spring-29일차] CH 3 일정 관리 앱 Develop Lv0~Lv1  (0) 2025.03.28
[내일배움캠프Spring-28일차] Spring DI/IoC  (1) 2025.03.27
'백엔드 부트캠프/TIL' 카테고리의 다른 글
  • [내일배움캠프Spring-33일차] CH 3 일정 관리 앱 Develop 完
  • [내일배움캠프Spring-32일차] CH 3 일정 관리 앱 Develop Lv7~Lv8, Refactoring
  • [내일배움캠프Spring-30일차] CH 3 일정 관리 앱 Develop Lv2~Lv6
  • [내일배움캠프Spring-29일차] CH 3 일정 관리 앱 Develop Lv0~Lv1
sintory-04
sintory-04
🚀🚀🚀
  • sintory-04
    Sintory Dev Blog
    sintory-04
    글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (289)
      • 백엔드 부트캠프 (111)
        • TIL (97)
        • WIL (0)
        • 문제풀이 (7)
        • 기타 (6)
      • 백엔드 부트캠프[사전캠프] (35)
        • TIL (16)
        • 문제풀이 (17)
        • 기타 (1)
      • Troubleshooting (11)
      • 코딩 공부 (118)
        • Java (28)
        • Baekjoon-Java (24)
        • Programmers-Java (40)
        • Spirngboot (11)
        • typescript (1)
        • JavaScript (6)
        • Spring 입문 (8)
      • 프로젝트 (8)
        • ToDoApp(FireBase) (3)
        • ToDoApp(Spring) (5)
      • 기타 (4)
  • 블로그 메뉴

    • 소개
    • Github
  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
sintory-04
[내일배움캠프Spring-31일차] 과제 트러블슈팅
상단으로

티스토리툴바