본문 바로가기

회고록 모음/코드숨-스프링 과정 회고록

[회고록] 코드숨 Spring - 6주차 코드리뷰 (JWT)

[ 6주차 회고록 📚]

 

좋아하는 노래인 '볼빨간 사춘기 - 나의 사춘기에게' 에서 최애 가사

 


📌 커리큘럼 


📌 코드리뷰 with 깃허브

github.com/CodeSoom/spring-week6-assignment-1/pull/14

 

[Spring 6주차 과제] 로그인 만들기 by developerOlive · Pull Request #14 · CodeSoom/spring-week6-assignment-1

📍 과제 목표 지금은 모든 기능을 로그인을 하지 않고 사용할 수 있습니다. 고양이 장난감을 새로 등록하거나 수정, 삭제하는 기능은 인증된 사용자만이 사용할 수 있어야 합니다. JWT를 이용해

github.com


1. 한 것

- 코드숨 스프링 6회 강의 2개 듣기

 

- 과제 1 : JWT를 이용해 인증을 구현하여 로그인을 만들고, 인증된 사람만 등록/수정/삭제하도록 만들기

 

- 과제 2 : REST API 만들기 + 테스트 코드 작성 + API 테스트 통과 

 

- 과제 3 : 테스트 커버리지 100% 달성하기

 

- 과제 4 : e2e 테스트 통과하기 

 

테스트 커버리지

 

API 테스트


2. 배운 것

 

 

 

저번주(5주차) 동기분들의 회고록을 읽던 중, 동욱 동기님께서 남기신 글이 기억에 남았다.

 

'라이브러리를 도입하려고 한다면

도입하려는 이유 및 도입했을 때 장점 같은 것을 상세하게 적어 동료들을 설득시킬 수 있어야 된다는 것을 알게 되었다.'

 

그래서 나도 이번에 새로 배운 JWT에 대해 설명하는 글을 PR에 적어보았다. 

 

 

 

JWT라는 새로운 개념을 처음 접하다 보니, 분명 정리가 필요했다.

 

그런데 남에게 설명까지 할 수 있어야 한다면?

간단명료하되 정확해야 한다고 생각한다.

또한 이 기술을 쓰자고 설득할 수 있으려면 그 장점이 분명해야 한다.

 

그렇게 작성하기 위해서는 생각보다 많은 자료를 찾아보게 되는 것 같다.

이 과정에서 약간은 안개 같았던 JWT의 개념이 조금 더 선명해짐을 느낄 수 있었다.

 

그러다 예전에 읽었던 '완벽한 공부법'이라는 책의 일부 내용이 생각났다.

내가 아는 내용을 남에게 설명하려고 할 때 더 확실하게 공부가 된다는 그런 내용이었던 것으로 기억한다.

이번에 JWT를 설명하는 PR을 작성하면서 몸소 느낄 수 있었다.

 

 


 

이번 주에 과제를 하면서 중간에 나를 상당히 괴롭게 하는 것이 있었다.

 

API 테스트에서 통과 못했다고 와장창 던져주는 결과들 😭

 

 

코드를 수정하고, 몇 번이나 더 확인했다.

저렇게 한꺼번에 깨지는 걸 보니... 어느 순간 이건 코드의 문제가 아니라는 느낌은 왔는데, 정확한 해결법을 찾지 못하고 있었다.

할 게 많은데 여기에서 시간이 계속 허비되는 것 같아서 괴로웠다.

 

질문을 하기로 했다.

그리고 해결을 했다.

 

해결의 과정은 다음과 같았다.

 

 

 

 

종립 트레이너님 : 이런 상황에선 멘붕 하지 말고 메시지를 있는 그대로 읽고 대처해야 해요.

 

Session > POST /session > with not exists user > reponse token

 

위 내용의 의미가 무엇인가요?

 

POST /session으로 등록되지 않은 사용자 정보를 보냈을 때 400이 와야 한다는 거죠?

그런데 500이 오고 있어서 테스트에 실패하는 것입니다.

그러면 이거랑 관련된 코드를 봅시다. 어디를 고쳐야 하는지 감이 오는 곳이 있나요?

 

SessionController

 

등록되지 않은 사용자라면 아래에서 예외가 던져지겠죠?

 

AuthenticationService

 

 

이 예외와 관련된 @ExceptionHandler 가 있는지 확인해 보세요.

핸들러가 400을 응답하게 작성되어 있나요?

 

ControllerErrorAdvice

 

400이 등록되어 있네요.

저는 아래와 같이 400이 잘 들어옵니다.

 

 

.....?

이 부분이 최대 멘붕 포인트였다.

트레이너님이 내 코드를 clone 하신 후 테스트하신 것이기 때문에 분명 같은 코드인데

왜 나는 400 에러가 안 들어오고 트레이너님은 들어오시는 거지? 왜 때문에?!

 

 

일단 트레이너님처럼 내 터미널 창에서 아래 내용을 입력했다.

 

curl -s -H 'Content-Type: application/json' -D - -X POST --data '{"email": "notexists@email.com","password": "wrong password"}' 'http://localhost:8080/session'

 

 

그래... 500 에러... Internal Server Error... 내부 서버 오류... 

'서버는 잘 돌아가고 있는데 대체 내부 서버 오류가 무엇이란 말인가...'

이 생각에 막혀 더 이상 혼자 해결을 못하고 질문을 드렸던 상황이었다.

 

 

 

저 메시지를 읽어보세요. DB에서 조회를 하려 했지만 에러가 난 거네요.

application.yml 확인해보세요

내부 서버 오류는 응답이 그렇게 나온 거고요,

메시지를 읽어보면 invalid data access 이렇게 나오죠?

 

저랑 소연님 소스코드는 같지만 DB 상태가 달라서 발생하는 실패 같네요

소연님 DB에 잘못된 값이 들어있거나

DB 설정이 잘못됐거나 그럴 거예요.

 

메시지 나오는 걸 보고 단어 하나라도 무심히 넘기지 않고 해결하는 습관을 키우시면 됩니다.

지금 h2 db가 아마 소연님 컴퓨터 로컬 디스크 드라이브에 저장되어서 돌아갈 거예요

인메모리로 돌리시던가

DB 데이터 파일을 지우고 새로 가동해 보시면 해결될 수 있을 것 같아요.

 

 

 

 

application.yml

 

jpa.hibernate.ddl-auto를 create로 바꿨더니 해결됐다.

 

 

 

📍spring.jpa.hiberante.ddl-auto 속성

  • 옵션
    - none: 자동 생성하지 않음
    • create: 항상 다시 생성
    • create-drop: 시작 시 생성 후 종료 시 제거
    • update: 시작 시 Entity 클래스와 DB 스키마 구조를 비교해서 DB 쪽에 생성되지 않은 테이블, 칼럼 추가 (제거는 하지 않음)
    • validate: 시작 시 Entity 클래스와 DB 스키마 구조를 비교해서 같은지만 확인 (다르면 예외 발생)

 

 

에러를 해결하다가 코드 문제가 아닌 것 같아서

동기인 종명님께도 혹시 제 코드를 clone 해서 돌려봐 주실 수 있냐고 부탁을 드렸었는데 테스트 통과가 잘 된다고 하셨다.

종명님도 application.yml 파일에 jpa.hibernate.ddl-auto 부분이 문제일 수도 있을 것 같다고

트레이너님과 거의 동시에 답변을 주셨다.

저 원인을 한 번에 찾아낸 종명님도 대단하시다....

 

 

JPA 내부동작에 대해서 제대로 모르는 것 같아서 공부가 더 많이 필요하다...

 


 

 

 

 

나도 처음에는 진성님과 같이 값이 아닌 인터페이스로 파라미터를 전달했을 때의 이점이 정확히 이해되지 않았다.

 

몇 번이고 트레이너님의 답변을 읽었는데,

내가 이해한 게 맞는지 의심이 들었다.

저렇게 코드를 수정했을 때의 큰 장점이 무엇인지 내 스스로 설명하기 어려웠기 때문이다.

 

다시 트레이너님께 문을 두드렸다.

 

 

이해할 수 있도록 늦은 밤까지 도움을 주시는 트레이너님께 감사한 것은 말할 것도 없고.... (눙물....)

 

나도 누군가 어떤 개념에 대해 정말 궁금해하는 사람에게 

이런 열정으로 설명할 수 있는 사람이 된다면 정말 정말 좋겠다 라는 생각을 했다. 

 

 


 

커밋했던 코드 중에 System.out.println을 사용해서 값을 확인한 부분이 있었다.

트레이너님께서 @Slf4j를 검색해보라고 하셔서 이 어노테이션에 대한 공부를 했다.

 

사용법은 간단한데 은근히 적용이 안 돼서 포기할까 하다가

씨름 끝에 log.info("~~")로 로그 찍기 성공..!

 

콘솔창 (왜 log.debug("~~")로 안 찍히는지는 이유를 잘 모르겠다....)

 

사실, 나는 System.out.println에 대한 애정(?)이 있다. 

 

예전에 디버깅할 때 대체 어디가 에러인지 잘 안 잡히는 상황에서

니가 이기나 내가 이기나 해보자 싶어서 

코드 한 줄 한 줄에 다 System.out.println 로그를 찍어서 어떤 데이터가 전달이 안 되고 있는지 확인한 적이 있었다.

 

그렇게 조금은 무식하지만.... 결국은 에러를 해결한 경험이 있어서 그런지 좀 고맙기도 하고

그냥 로그 찍자 하면 System.out.println 이게 제일 먼저 생각난다.

 

이제는 트레이너님 말씀대로 System.out.println과 안녕을 하는 것이 좀 더 세련된 방법이겠지만서도...

아직은 좀 떠나보내기 싫은 마음도 있다. (웃겨....ㅎ)

 


다른 동기분들의 PR 중에서도 진짜 배울게 많은데,

더 잘 기억하고 싶어서 몇 개만 회고록에도 남겨본다. 

 

병호 동기님 PR

 

병호 동기님 PR

 

라스 동기님 PR

어노테이션이 굉장히 고마운 존재라고만 생각했었는데... 내가 아직 모르는 이면이 있나 보구나.

 


3. 느낀 것

 

코드숨 시작한 이래로 제일 힘든 한 주였다.

다른 외부적인 이유 없이 오직 코드숨 과제와 공부를 하면서 오는 힘듦이었다.

 

강의에서 보여주시는 JWT 구현이 처음에는 잘 안 들어와서 멍하니 보다가 한 3번 돌려보고 나서야 과제를 겨우 시작할 수 있기도 했었고, 

위에서 언급했던 에러를 해결하느라 많은 시간을 썼던 부분도 있었고,

여러 테스트 전체 통과도.... 다 만만치 않았다. 

 

결국엔 에러 해결을 위한 도움도 받고,

열심히 하는 동기님들 보면서 자극도 받고,

여차저차 다시 멘탈을 잡아서 과제를 통과하긴 했지만 중간에 심적으로 상당히 힘들었던 것 같다.

 

 

 

 

종립 트레이너님 :

어떤 것을 만들어야 하는지에 대해 전체를 다 머리 속에 담지 않아도 괜찮아요.

전체를 다 머리 속에 담으려 하다 보면 규모가 일정 이상 되면 무조건 헷갈릴 수 밖에 없고 자신감을 잃게 됩니다.

 

우리가 왜 캡슐화를 하고, 클래스를 나누고, 메소드를 작게 나누고, 인터페이스를 왜 만드는지 생각해 보셔야 해요.

계속 나누고 쪼개고 추상화하고 private으로 숨기고 하는 이유는 바로

우리가 한 번에 기억할 수 있는 양이 아주 작기 때문이에요.

 

그래서 소연님이 수업을 따라가며 어려움을 느끼신 것은 이상한 일이 아니에요.

 

 

 

유독 고민이 많았던 한 주였다고 말씀드렸는데, 

중요한 본질을 말씀해 주시면서

어려움을 느낀 것이 이상한 일이 아니라는 한 마디가 참 위로가 되기도 했다.

 


4. 자기 선언

 

회고록을 작성하는 일요일인 오늘,

2021년 들어 처음으로 러닝을 했다.

 

날이 추워지기 전 일주일에 2-3번 러닝을 할 때는 5km를 뛰는 게 많이 힘들진 않았는데

한 2개월 만에 뛰니까 2km를 뛰는데도 꽤나 힘들었다.

 

처음 러닝을 시작할 때는 어땠을까?

당연히 2km를 뛰는 게 힘들었다.

근데 뛰다 보니 5km도, 10km도 뛸 수 있는 사람이 됐었다.

 

프로그래밍도 러닝과 똑같을 거라고 생각한다.

처음엔 너무 힘들었던 것도, 존버 하다 보면 언젠간 덜 힘들어지겠지.

뭐든지 존버가 어렵다!