오늘은 코드카타 SQL 62번 문제와 알고리즘 60, 61번 문제를 풀고, 심화 Spring 강의를 다 들었다!
오늘은 1개의 SQL 문제를 풀었는데, 두 날짜를 주고, 두 날짜의 차이가 30이 이상이면 특정 문자를, 아니면 다른 문자를 출력하는 것이었다.
case when과 datediff을 사용해 쉽게 해결할 수 있을 줄 알았으나.. 왠지 모르게 계속 정답이 아니었다.
그런데,, 알고보니 datediff는 시작하는 날짜는 포함하지 않기 때문에, datediff() >= 30으로 잡는 것이 아니라 datediff() >= 29로 잡았어야 했다..
자바 스트림의 range에서도 그렇고 계속 범위 때문에 틀리는 일이 많다..
이런 것들 사용할 때는 범위를 어떻게 포함하는지 잘 보고 써야겠다..
오늘은 2개의 알고리즘 문제를 풀었다.
첫 번째 문제는 약수의 개수를 더하고, 약수의 개수가 limit를 넘는다면 다른 숫자로 바꾸고, 약수의 개수를 합하는 문제였다.
사실 이 문제는 풀이 자체가 어려웠던 것은 아니었다.
그런데, for문을 사용해 약수의 개수를 구하다보니 주어진 숫자가 커지면 for문의 반복 횟수가 늘어나고, 그러니 풀이 시간이 늘어나 런타임 오류가 계속 생겼다.
그래서 처음에는 입력받은 숫자를 반으로 나눠서 약수의 개수를 구해보려고 했지만, 계속해서 실패했고..
결국은 입력받은 숫자의 제곱근을 구해서 약수의 개수를 구할 수 있었다.
차라리 풀이 자체에 문제가 있었다면 해결하기가 더 쉬웠겠지만, 런타임 오류를 해결해야 하는 것이다보니 더 어려웠다..
두 번째 문제는 빈 칸이 있는 로또를 받았을 때, 가능한 최대 순위와 최저 순위를 계산하는 것이었다.
그런데 사실 빈칸을 제외한 순위를 계산하고, 빈칸이 모두 맞았을 때와 모두 틀렸을 때를 생각하면 되는 것이었기에 큰 어려움 없이 풀 수 있었다.
오늘 푼 문제와 풀이는 깃허브를 통해 업로드해두었다.
GitHub 보러가기
오늘 드디어 강의를 다 들었다!!!
남은 5주차의 강의 내용들은 통합 테스트를 진행하는 방법이었다.
통합 테스트란, 애플리페이션의 여러 구성 요소들을 묶어서 시스템의 동작 흐름을 검증하는 것이다.
예를 들어, Http 요청을 보냈을 때 Controller가 API를 잘 받아내고 있는지, Service의 메서드가 호출되면 리포지토리에 잘 저장하고 있는지 등을 확인하는 것이다.
통합 테스트에서는 계층의 연관관계와 의존성을 사용해야 하기 때문에 Mock 객체를 사용하지 않는다.
그래서 테스트에 소요되는 시간이 단위 테스트에 비해 오래걸린다.
그래서 현업에서는 Service보다는 Controller를 테스트하기 위해 통합 테스트를 많이 진행한다고 한다.
Controller 테스트를 진행할 때는 HTTP 요청을 보내주는 역할이 필요하기 때문에,
MockMvc를 사용해 인위적으로 HTTP 요청을 만들어 테스트를 진행한다.
MockMvc에 HTTP 메서드, API, 토큰 정보, Body 내용 모두 담아서 요청을 만들어주고,
반환되는 값이 200 OK인지, 내용이 잘 포함되어 있는지 등을 확인할 수 있다.
이렇게 심화 Spring 강의가 모두 끝났다!!
사실 대부분 스탠다드반 세션 때 다뤘던 내용이라 크게 어려웠던 부분들은 없었지만,
과제를 통해서 이런 저런 부분들의 연습을 진행해봐야겠다.
더 자세한 설명과 실습 내용은 노션에 정리해두었다.
Notion 확인하기
이전 과제들은 이런저런거 만들기라 이름이 있었는데..
이번 과제는 제공받은 프로젝트에서 코드를 개선하고, 기능을 추가하는 등의 내용이라 이름이 없다...
이번 과제는 필수과제 4단계와 도전과제 3단계로 구성되어 있는데,
필수과제는 프로젝트를 세팅하고, 트러블슈팅을 진행하고, 코드를 리팩토링 하는 등을 요구하고,
도전과제는 API 로그를 남기고, 제공받은 프로젝트를 원하는대로 리팩토링하고, 최대한 많은 테스트 코드를 만들어보는 것을 요구한다.
사실 필수과제 부분들이 굉장히 쉬웠다.
뭔가 문제가 요구하는 내용들을 이해하고, 커밋 메시지를 작성하는 데에 시간이 많이 걸렸지 사실 문제를 해결하는 데에는 거의 한 레벨에 10분도 안 걸린 것 같다.
0단계로는 프로젝트를 세팅해야 했는데, application.yml 파일이 누락되어 있어 yaml 파일을 생성하고, DB 연결을 해주면 됐다.
이때 JWT의 시크릿 키도 생성을 해주었는데, JwtUtil 파일에 @Value("${jwt.secret.key}")로 경로 설정이 되어있음에도 클릭하면 ‘cannot find declaration to go’가 나온다는 문제가 있었다.
그런데 이건 인텔리제이의 캐시 문제였기 때문에 캐시를 무효화하고 재시작하니 잘 해결되었다.
1단계는 커스텀 어노테이션을 만들어 사용하는 ArgumentResolver가 작동하지 않는다는 문제를 해결하는 것이었다.
ArgumentResolver.. 안배운줄 알았는데 숙련 주차 때 강의에서 다뤘던 내용이더라..
그래서 강의 내용을 보고 생성에서 놓친 부분을 찾아서 수정해주었고, 문제를 잘 해결할 수 있었다.
2단계는 3가지 요구 상황에 맞춰 코드를 개선하는 것이었는데,
서비스 단계에서 로직의 순서를 바꾸고, if-else 문에서 필요없는 else문을 없애고, 누락된 Validation을 추가하는 것 뿐이었다.
2단계는 정말.. 쉽게 해결이 되었지만 문제가 요구하는 상황을 이해하는 데에 시간이 정말 정말 많이 걸렸다...
국어 실력을 좀 늘려야겠다..
3단계에서는 기존에 Fetch Join을 통해 해결했던 N+1 문제를 EntityGraph 기반의 구현으로 수정하라는 것이었다.
이것도.. 그냥 Fetch Join을 사용하던 쿼리문을 수정하고, @EntityGraph 어노테이션을 붙이기만 하면 됐다.
EntityGraph 어노테이션에서 필드명으로 연결을 해줘야 하는데, 테이블 이름으로 잘못 입력해서 잠시 헤매긴 했지만,,
그래도 금방 문제가 어디인지를 알고 해결할 수 있었다.
마지막으로 4단계에서는 동작하지 않는 테스트코드를 동작하게 만드는 것이었다.
어떤 것은 테스트 코드를 잘못 작성해서, 어떤 것은 서비스 로직을 잘못 작성해서 동작이 제대로 되지 않았는데,
이게 왜 제대로 동작하지 않는지를 파악해서 수정하면 됐다.
여기에서는 문제라기보다는 처음 보는 어노테이션이나 메서드들이 등장해서 관련 내용들을 찾아보느라 시간을 조금 썼다.
오늘 테스트 코드 실습을 많이 해보았기 때문에 문제를 푸는 것은 금방 끝낼 수 있었다ㅎㅎ
오늘은 이렇게 필수과제의 요구사항들을 모두 끝냈다!!
이제 과제 제출까지 하루 반이 남았는데, 그 안에 도전과제의 요구사항들도 빠르게 해결해봐야겠다.
내가 작성한 코드는 깃허브에 업로드해두었다.
GitHub 보러가기
사실 이번에도 과제 시작하기 전에 엄청 겁먹었었다.
월요일에 반나절을 땡땡이 쳐서 늦게 시작하기도 했고,,
과제 문서를 10번을 넘게 봐도 과제 내용이 이해가 안 돼서 녹화된 발제 영상을 5번은 돌려봤는데 그래도 이해가 안 되더라.
(그래서 사실 다른 사람들 어떻게 푸는지 훔쳐봤지만..)
그리고 뭔가 필수과제는 너무 간단한 내용들을 요구하고 있어서 '정말 이렇게 푸는게 맞다고?'를 한 100번은 반복한 것 같다.
그리고 매번 새롭게 내가 작성해보기만 했지 다른 사람이 작성해놓은 코드를 분석해보려고 하니 정말 어려웠다.
왜 매번 API 명세서를 작성하라고 하고, 리드미 파일을 작성하라고 하시는지를 이제야 이해했다.
제공받은 프로젝트를 이해하기 위해 한줄 한줄 뜯어보며 포스트맨에 API를 저장해두었다.
그럼에도 아직 뭔지 이해되지 않는 내용들이 있지만..
이건 내일 도전과제를 하며 알아가봐야겠다.