-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1단계 - 웹 자동차 경주] 제이미(임정수) 미션 제출합니다. #69
Conversation
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
Co-authored-by: the9kim <[email protected]>
안녕하세요 제이미! 리뷰어 카프카입니다. 블랙잭 미션때 만나뵙고 이번에 두 번째 리뷰를 함께하게 되었네요! 이번 미션은 스프링에 첫 발을 내딛는 미션인 만큼, 적절한 수준에서 학습이 필요한 부분 위주로 코멘트 드리겠습니다. 리뷰는 금일 저녁 8시 ~ 9시 사이에 진행 예정입니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 제이미, 리뷰어 카프카입니다.
코드를 깔끔하게 잘 작성해 주셨네요! 필요한 기능들에 대한 구현이 잘 되어있음을 확인했습니다.
현재 단계에서 요구되는 사항은 충족했다고 생각되어, 학습이 필요한 부분에 대해서만 코멘트 남겨두었습니다.
본격적인 논의는 2단계를 진행하면서 함께 나누어봅시다 😄
이번 단계는 approve 하겠습니다.
작업하시느라 고생 많으셨습니다!
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@RestController |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RestController 어노테이션이 어떤 역할을 하고 있는지 혹시 인식하고 있을까요?
여기에 추가로 Controller 어노테이션과의 차이도 알아두면 좋은데, spring을 입문하는 시점에 가볍게 학습해보기를 권합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Controller
는 View를 @RestController
는 json을 반환한다는 간단한 설명을 보고 @RestController
를 사용하게 되었습니다.
그런데 조사해본 결과 @RestController
는 @Controller
에 @ResponseBody
를 추가한 형태라는 것을 알게 되었습니다. @Controller
역시 ResponseEntity를 사용하면 View가 아닌 Json 데이터 등도 반환할 수 있게 되네요!
@ResponeBody
에 대해서도 찾아본 결과 ResponseEntity 대신 객체를 바로 반환할 수 있는 형태인 것도 알게 되었습니다.
그런데 현재 제 코드에서는 HttpStatus를 설정할 필요까지는 없었으니 굳이 ResponseEntity를 사용할 필요가 없겠네요!
@RestController를 사용하되 ResponseEntity가 아닌 객체를 반환하도록 수정해 보았습니다! (수정 로직 바로가기)
그런데 보통 HttpStatus로 설정하는 경우가 많은지 궁금합니다.
또한, HttpStatus도 함께 설정해 반환해야 하는 경우 ResponseEntity를 통해 반환하는 것과 @ResponseBody
로 설정한 뒤 HttpStatus는 @ResponseStatus
를 통해 설정하는 것 중 어떤 것을 사용하는 것이 선호되는지도 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 부분은 상황마다 다르긴 합니다. 상태코드를 명확히 전달하고 싶다면 ResponseEntity를 사용하기도 하고, ResponseEntity와 비슷하게 상태코드와 옵셔널한 에러코드, 그리고 제네릭으로 선언된 DTO를 담는 반환용 클래스를 만들기도 해요. 이렇게 하면 내부적으로 에러 타입등을 정의해서 에러 발생시 내려보낼 수 있지요.
현재 스펙에서는 DTO만 내려보내줘도 충분해 보입니다. 다만 4xx, 5xx 에러 발생시 적절하게 핸들링이 되어야겠지요? (이 부분에 대해서는 지속적으로 학습을 진행해 봅시다)
이렇게 다양한 방법으로 반환이 가능하다는 것을 학습해서 좋다고 생각합니다. 💯
this.jdbcTemplate = jdbcTemplate; | ||
} | ||
|
||
public long insert(int trialCount, String winners) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
데이터 추가 시 auto_increment로 생성되는 id를 반환해주도록 잘 작성해주셨네요! 좋습니다 👍
@@ -1,7 +1,18 @@ | |||
-- TODO: 기능 구현에 필요한 내용을 추가하거나 수정하세요. | |||
CREATE TABLE PLAY_RESULT ( | |||
CREATE TABLE RESULTS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테이블을 잘 작성해 주셨네요! 두 개로 나눠 저장하면서 게임 정보와 플레이어(레이싱카) 정보를 저장하겠군요. 💯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다만 현재 테스트를 확인해보시면, 개별로 돌리면 문제가 없지만 전체 테스트를 한 번에 돌리면 실패하는 케이스가 발생하고 있어요.
제 생각엔 data.sql 이 그 원인으로 보이는데, 이 부분에 대해 확인해보고 학습해보면 좋을 것으로 생각되어요.
다른 크루들 중에도 비슷한 케이스를 겪는 경우가 보였는데, 가볍게 이야기를 나눠보는 것도 도움이 되겠네요.
해당 사항은 근본적으로 수정하려면 아직 학습하지 않은 내용이 필요할 수 있어, 우선 현상을 관찰하는데에 집중해주시면 좋겠습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전체 테스트를 한 번에 돌려 확인하는 것을 잊었네요…!
안 되는 이유를 고민해본 결과 모든 테스트에 @SpringBootTest를 달았기 때문이라 생각합니다.
@SrpingBootTest는 Application과 똑같이 모든 빈을 생성하는 등 Application과 동일한 환경을 만들어 주는 것으로 알고 있습니다.
이때, data.sql 코드가 반복적으로 실행되며 동일한 테이블을 여러개 만들려고 하기에 충돌이 발생합니다.
그래서 data.sql 쿼리문 상단에 DROP TABLE
쿼리문으로 테이블이 이미 존재한다면 DROP 하도록 설정했습니다. (로직 바로가기)
추가적으로 기존에는 모든 테스트에서 @SpringBootTest로 수행했는데 Controller 외에는 SpringBootApplication과 동일한 환경이 필요하지 않을 뿐더러 모든 Bean을 로드할 필요가 없기 때문에 daoTest와 serviceTest 각각 @JdbcTest
와 @ExtendWith(MockitoExtension.class
로 수정해보았습니다.
RacingCarServiceTest
의 경우 Application을 실행시킨 환경까지는 필요하지 않기 때문에
그런데 SpringBoot Application을 재실행시키게 되면 항상 db는 초기화가 되었는데 @SpringBootTest는 그렇지 않은 것인지 궁금합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋습니다. 정확하게 원인을 파악해 주셨네요!
이 부분의 경우 @jdbcTest 를 통해 해결하도록 가이드하고 있는데, 이미 관련해서 학습을 잘 해주셨네요. 💯
이러한 현상이 생긴 이유는, 테스트 클래스 가동시 빈을 올려두고 각각의 테스트를 진행하기 때문으로 알고 있습니다.
그래서 테스트 순서에 따라 성공하기도 하고 실패하기도 하는 테스트가 생겨요. 아래의 예를 봅시다.
- 테스트메소드1: DB에 데이터 1개 삽입
- 테스트메소드2: DB가 비어있을 경우 findAll을 수행하면 빈 컬렉션이 반환되는 것을 확인
2->1 순으로 진행하면 문제가 없겠지만, 1->2 순으로 진행하면 의도한 바와 다른 결과가 나오겠지요.
이를 막기 위해 beforeEach나 afterEach 등으로 대응해줄 수 있지만요,
현재의 경우에서는 앞서 말씀해주신 @jdbcTest 를 통해 테스트 단위별로 트랜잭션을 설정해주는 것이 간편합니다.
this.numberGenerator = numberGenerator; | ||
} | ||
|
||
@PostMapping("plays") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 post로 입력을 받고 있는데, get으로 입력받는 것과의 차이가 무엇일까요?
이번 학습을 시작하면서, http에 대해 간단히 학습해두시면 좋을 것으로 생각됩니다. 시간이 난다면 아래 책을 봐두어도 좋습니다.
그림으로 배우는 HTTP & Network(설명이 친절하고 기본적인 내용만 빠르게 훑기 좋아서 추천합니다. )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그리고 혹시 크롬 개발자 도구를 이전에 사용해 본 적이 있을까요?
미션을 진행하는 웹 페이지에서 개발자 도구를 켠 뒤 요청을 보내보면, 어떤 식으로 요청이 발송되고 어떤 식으로 응답이 오는지 자세히 볼 수 있어요. 앞으로 미션 진행하시면서 해당 도구의 도움을 많이 받으시리라 생각됩니다.
현재 개발자 도구를 통해 아래 오류를 확인할 수 있는데, 그 이유 및 상태 코드의 의미를 분석해보면 2단계를 진행할 때 유용할 거에요.
(제이미자 잘못 구현해서 나는 것은 아니고, 정상 동작입니다. 다만 그 코드가 발생하는 이유를 학습해보면 좋겠습니다!)
- 이력조회 페이지 접근시 405 에러 발생
- 게임하기 메뉴에서 빈 값을 보낼 시 500 에러 발생
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get과 post에 대해 간단하게 알고 있습니다.
post의 경우 클라이언트에서 서버로 데이터를 전송할 때 body에 담아 url에 노출되지 않도록 하며 데이터를 전달하는 방식으로 알고 있습니다.
반면, get의 경우 url 뒤에 ?key=value 형식으로 데이터를 서버에 전달해 주는 것으로 알고 있습니다.
네트워크에 대한 개념이 제대로 잡혀있지 않는데 책 추천 감사합니다!
레벨 2동안 해당 책을 열심히 읽어봐야겠군요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개발자 도구에서 항상 console과 elements만 봤었는데 네트워크는 제대로 본 적이 없었네요!
500 에러는 서버 동작에서 발생한 에러 중 예측하지 못한 에러를 뜻하네요. 이전 step 1에서 값 검증도 중 예외 값이 들어온다면 Exception을 생성해 반환했기 때문이네요.
반면 405 에러는 URL로 요청 중 HTTP 메서드가 허용되지 않는 상황으로 해당 메서드가 없거나 설정이 잘못된 경우(get인데 post로 매핑 등) 등에서 발생하는 오류인 것으로 보이네요!
현재 제 경우에서는 500에러가 뜨는 것이 맞는 것이고요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 의도한 바 이상으로 학습을 잘 해주셨네요! 에러별로 분석을 잘 해주셨습니다.
이에 대해서는 예외 핸들러를 만들어서 대응해줄 수 있습니다.
https://www.baeldung.com/exception-handling-for-rest-with-spring
위에 다양한 방법으로 핸들링하는 가이드가 나와있는데요, 일단 현재 레벨에서는 controller 내에 exceptionhandler 메소드를 만들어두면 좋을 것으로 생각됩니다.
안녕하세요 카프카 제이미입니다!
블랙잭 미션에 이어 이번 웹 자동자 경주 미션에서도 만나게 되었네요!
이번 미션을 통해 Spring을 처음 사용해보게 되어 아직 완벽하게 이해하지 못하고 사용하게 된 것들도 많은 상태입니다.
그래서 이번엔 어떤 질문을 해야 할지 감이 오지 않네요..!
전체적인 구조 및 Spring을 제대로 사용했는지 확인해주시면 감사하겠습니다!
이번 리뷰도 잘 부탁드립니다.
감사합니다!