오늘 진행한 학습 요약
1. 플러스 주차 개인 과제
- 필수 과제 + 트러블 슈팅
- 1. Transactional에 대한 이해
- 2. 인가에 대한 이해
- 3. N+1에 대한 이해
- 4. DB 접근 최소화
- 5. 동적 쿼리에 대한 이해
- 6. 필요한 부분만 갱신하기
- 7. 리팩토링
- 8. 테스트 코드
- 도전기능 + 트러블 슈팅
- 9. 테스트 코드
- 10. 테스트 환경 분리
- 11. AWS 활용 마스터
2. 알고리즘 코드카다 Day61(작성 생략)
CodingTest Git-hub 링크 : https://github.com/chews26/CodingTest
학습 정리
1. 플러스 주차 개인 과제
- 필수 과제 + 트러블 슈팅
- 1. Transactional에 대한 이해
- 🤔 문제
- @Transactional 어노테이션만 추가 되는거 아니였나? 왜 안되지
- 😎 해결방법
- 기본적으로 Spring은 RuntimeException 및 그 하위 클래스 발생, Error 발생시에만 롤백을 한다고한다.
- Checked Exception 및 하위 클래스는 롤백되지 않는다.
- Unchecked Exception인 IllegalArgumentException, NullPointerException을 사용하거나,
@Transactional(rollbackFor = Exception.class) 속성을 사용해 Checked Exception의 롤백을 강제 할 수 있다. - 따라서 IllegalArgumentException을 추가하여 null 값이 입력될 경우 롤백이 되도록 하였다.
- 😶 고민
- 블로그를 작성하면서 코드를 다시 보니 현재는 null 값에 대해서만 에러체크를 하고 있는데 좀 더 세부적으로 에러를 체크하는 코드로 작성할 필요가 있어보인다..
- 2. 인가에 대한 이해
- 🤔 문제
- 인터셉터로 인증 인가를 모두 사용하면 filter로 @Bean 등록을 안해도 되지 않나?
- 😎 해결방법
- 맞다 인터셉터를 사용하여 인증/인가 작업을 모두 할 수 있는 경우 동일한 작업을 수행하는 @Bean은 등록 할 필요가 없다고 한다.
- 그렇다면 이 경우 FIlter는 무슨 역할을 수행할 수 있을까?
- Flter는 주로 Interceptor보다 더 낮은 수준에서 동작해야 하는 작업을 처리하는 데 사용할 수 있다고 한다.
- 전역적인 요청 처리 (CORS 처리)
- 보안 기능 (JWT 토큰 인증, SSL/TLS인증 강제화, IP차단)
- 요청 데이터 전처리
- 응답 데이터 후처리
- Interceptor의 선행 작업
- 😶 고민
- Filter를 응용하기 위해선 CORS 처리, JWT토큰, SSL/TLS에 대해 추가 학습이 필요하겠다.
- 3. N+1에 대한 이해
- 🤔 문제
- 모든 예약을 조회할 때 연관된 테이블에 있는 정보를 가져오면서 N+1 문제가 발생한다는 전제로 이를 해결해야한다. N+1문제를 어떻게 해결하지? 왜 N+1문제를 해결해야하지?
- 😎 해결방법
- JPA 성능최적화 강의를 수강하고 이에 대해 궁금점을 해소할 수 있었다.
- 결론적으로 DB에 여러번 접근할걸 한번만 접근해서 필요한 모든 데이터를 가져오면 된다.
- 맞다 DB에는 많이 접근하지 않는게 좋다!!! 서버 운영할때도 DB서버에 ssh로 붙는것조차 조심했다..
- 가장 중요한 이유로는 네트워크 왕복이 1번일때보다 100번일때 훨씬 느리다 따라서 네트워크 비용이 매우 많이 발생되고 100번의 쿼리가 실행되어야하므로 데이터베이스에도 부하가 증가된다.
- 따라서 N+1문제를 해결할 수 있는 방법은 여러가지가 있지만 기존 작성되어 있는 쿼리문에서 N+1문제가 발생할 수 있기 때문에 JOIN FETCH를 통해 연관된 엔티티들을 즉시 로딩하여 추가 쿼리가 발생하지 않도록 수정하였다.
- 😶 고민
- @EntityGraph랑 @BatchSize등을 사용해서 N+1를 해결하는 법을 추가 공부해야겠다.
- 4. DB 접근 최소화
- 🤔 문제
- for문으로 User Id를 조회하고 있는데 어떻게 해야 DB접근을 최소화할 수 있지? 한번만에 userId를 모두 가져올 순 없을까?
- 😎 해결방법
- 그렇다 한번만에 가져올 수 있는 방법이 있었다(?)..
- findById는 한유저만 조회해서 가져온다. 따라서 for문으로 유저 모두를 조회하여야만 했다면 findAllById는 모든 유저에 대해 조회를 해서 한번에 값을 가져온다.
- 그래서 findAllById 메서드를 사용해서 List로 값을 반환하였다.
- 😶 고민
- 원론적인 문제를 해결하긴 했는데 조회할 사용자가 많아지는 경우에는 DB에 부하를 일으킬수도 있다고 생각이 들었다..
- 추후에는 데이터를 페이징처리하여 조회하는것으로 코드를 작성하는것이 좋을 것 같다.
- 5. 동적 쿼리에 대한 이해
- 🤔 문제
- 도대체 동적 쿼리가 뭐야! QueryDSL은 뭐야!!
- 도대체 어떻게 사용하는거야 ㅠㅠ (강의를 봐도 모르겠다...💀)
- userId, itemId 조건 데이터 존재 여부에 따라 동적으로 검색을 수행하라고?!
- QueryDLS로 작성은 일단 했다. 근데 왜 조건에 따라 검색이 안되지?
- 😎 해결방법
- 진짜 처음부터 마지막까지 하나도 쉬운게 없던 QueryDSL작성이었다.
- 동적 쿼리(Dynamic Query)는 쿼리 조건이 고정되어 있지 않고, 런타임 시점에 사용자 입력이나 조건에 따라 쿼리가 동적으로 생성되는 쿼리를 의미한다고 한다. QueryDSL은 JPA를 더욱 효율적으로 사용할 수 있도록 지원하는 타입세이프한 SQL 빌더 라이브러리로 컴파일 타임에 에러를 방지하고 가독성을 높여준다고 한다. 쨋든 좋은 친구(?)
- QueryDSL을 위한 초기 구성이 조금 복잡한데 한번 따라하니까 그렇게 어렵게 느껴지진 않았다.
- 조건에 따라 검색이 안되던 문제는 BooleanBuilder를 통해 여러개의 조건을 조합해야한다고한다. 그리고 이를 where절에 조립한 빌더에 넣어서 판별한다고 한다..! 그러니까 null인지 아닌지에 여부에 따라 쿼리가 검색되는 조건이 변경된다!
- 😶 고민
- QueryDSL은 여전히 어렵다 공부를 많이 해야겠다..
- 6. 필요한 부분만 갱신하기
- 😎 해결방법
- @DynamicInsert 어노테이션 및 coulumDfinition을 활용했다.
- 7. 리팩토링
- 😎 해결방법
- else if문을 제거하고 if문과 And를 활용했다.
- status를 enum으로 관리하도록 추가하였다~!
- 8. 테스트 코드
- 🤔 문제
- assertTrue? assertFalse? 도대체 어떻게 테스트를 검증하는거지? 어디에 어떤 메서드를 사용해야하지?
- 😎 해결방법
- assertEquals(expected, actual)은 두 값이 같은지 확인한다,
- assertNotEquals(unexpected, actual)은 두 값이 같지 않은지 확인한다.
- assertTrue(condition), assertFalse(condition)는 조건이 false인지 확인한다.
- 따라서 성공과 실패를 테스트하기 위해서는 위 메서드를 적절히 조합해서 테스트를 통과하도록 하면 된다.
- 따라서 검증하는 패스워드값이 암호화가 제대로 되었는지 passwordEncoder를 거친값과 아닌값을 비교하는 등의 테스트를 통해서 Encoding이 잘 되고 있는지 테스트를 진행하였다!
- 🤔 문제
- status가 null이 아니고 기본값으로 설정한 PENDING으로 설정되어있는지 확인하는데 단순히 itemstatus에 null 값을 넣어서는 테스트가 불가능했다.
- 😎 해결방법
- 영속성컨테스트를 활용했다..!
- 입력받은 값에서 status를 제외한 값을 입력했을 때 status의 기본 값인 PENDING으로 입력되는 지를 확인할 수 있다. .fulsh로 반영한다
- 그리고 변경된 값을 조회하도록 .clear를 통해 데이터베이스에서 새로운 데이터를 조회한다.
- 따라서 테스트 데이터베이스에 접근하여 테스트할 수 있도록 테스트 테스트 데이터베이스를 구성하였다!
- 1. Transactional에 대한 이해
- 도전기능 + 트러블 슈팅
- 9. 테스트 코드
- 😶 고민
- @WebMvcTest를 사용하여 Reservation Controller Test를 추가하였다.
- HttpStatus 예외처리를 잘해야겠다고 느꼈다.
- Json요청데이터를 가공해야하는 방법을 더 공부해야겠다.
- 기존 작성된 컨트롤러는 대부분 void로 선언되어있어 반환값이 없어 결과값을 비교하는데 어려움을 겪었다.
- @ExtendWith를 사용하여 Service Test를 추가하였다.
- 작성된 메서드들에 대해 테스트들을 대부분 작성하여 Missed Instructions를 80%이상 올렸으나 Missed Branches로 출력값에 대한 테스트들은 절반도 채우지 못하였다.
- 결론적으로 retrun값 모두를 체크해야하는데 그것을 하지 못했다 ㅠㅠ
- 다른 서비스나 컨트롤러에 대해서도 시간이 되면 테스트코드를 추가하고 싶은데 아직 테스트 코드를 작성하는게 쉽지는 않다.. jaCoCO를 활용해서 테스트가 커버되지 않은 부분을 체크하면서 코드를 작성하면 좀 더 수월할 것 같다.
- @WebMvcTest를 사용하여 Reservation Controller Test를 추가하였다.
- 10. 테스트 환경 분리
- 😶 고민
- Entity 테스트를 위해 사전에 테스트 환경을 분리했다. 처음에는 테스트 서버로 H2서버를 구성하였으나 계속 에러가 발생하여(하루종일 매달렸다ㅠ) 결국 테스트서버도 Mysql로 구성하였다.
- H2 데이터베이스를 활용하는 법을 좀 더 공부해야겠다.
- 😶 고민
- 11. AWS 활용 마스터
- 😶 고민
- 강의를 다 수강하지 못해서 오늘안에는 다 하지 못하였다.
- 내일 과제 제출전에 할 수 있으면 한번 도전해보고자 한다!
- 😶 고민
- 9. 테스트 코드