-
Notifications
You must be signed in to change notification settings - Fork 50
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
[BE][Team09][Bat & Pyro] API 를 JDBC 와 연동 #59
base: ghojeong
Are you sure you want to change the base?
Conversation
[BE] JDBC연동 - category class
[BE] category 테스트 코드 작성
[BE] JDBC 연동 도메인, 데이터베이스 데이터 삽입
[BE] DTO 생성 (get요청 불가능)
[BE] JDBC 와 서버를 연동
[BE] 주문하기 기능 구현
[BE] JDBC Template 으로 N + 1 문제 해결
[BE] N+1 문제 해결 & 주문하기 기능 구현
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.
빡빡한 일정중에 코드 리뷰까지 요청하시느라 대단히 고생 많으셨습니다. 💯
우선 전반적으로 일정에 쫓기다보니 통합 테스트는 물론이고 유닛 테스트도 많이 부족하네요. 이 부분은 개선되기를 바랍니다.
아울러 enum
을 조금 더 적극적으로 사용해 보시면 전반적인 코드 퀄리티를 높일 수 있을 것 같습니다.
그리고 조금 더 쉽게 쉽게 생각하며 코딩하기를 권해 드리고 싶네요. 한번 꼬아서 생각하는 바람에, 코드도 꼬인 것 같은 부분이 여럿 있네요.
수고 많으셨습니다. 🥇
if (dishService.order(detailHash, count)) { | ||
return ResponseEntity.ok().body("주문완료"); | ||
} | ||
return ResponseEntity.ok().body("주문불가"); |
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.
dishService.order()
의 리턴 타입이 스트링이었으면 코드가 조금 더 간결해졌겠네요.
같은 메소드를 소비하는 다른 소비처가 있나요? 그리고 그곳이 boolean
타입 리턴을 필요로 하나요?
그렇지 않다면, 서비스에서 바로 스트링을 내리는 구현도 좋을 것 같습니다.
다만 지금은 주문의 상태에 관한, 그러니까 경우의 수 를 다루는 메소드이므로 enum
을 사용하기에 아주 적절한 상황으로 보입니다.
public enum OrderResult {
ORDER_SUCCESSFUL("주문완료"),
ORDER_NOT_MADE("주문불가")
...
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.
다만 지금은 주문의 상태에 관한, 그러니까 경우의 수 를 다루는 메소드이므로 enum 을 사용하기에 아주 적절한 상황으로 보입니다.
enum 을 더 적극적으로 사용해보도록 하겠습니다!
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.
enum 생각을 하지 못하고 개발하였습니다....
image 구분할 때도 enum으로 했으면 더 좋았을 것 같습니다.
감사합니다.
@GetMapping("/main") | ||
@ApiOperation(value = "메인 요리", notes = "메인 요리의 목록을 반환합니다.") | ||
public ResponseEntity<List<DishDto>> getMainList() { | ||
List<DishDto> dishes = dishService.getList(1); | ||
List<DishDto> dishes = dishService.getList(1L); |
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.
1L
, 2L
은 상수로 관리돼야 할 것 같군요.
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.
이것도 enum 으로 main 과 1L 상수를 하나로 묶는게 좋겠군요.
생각없이 막코딩한 밑천이 다 드러나네요...
import java.util.Objects; | ||
|
||
public class Delivery { | ||
private String deliveryType; |
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.
type
이라면... 문자열 필드보단 더 좋은 방법이 있지 않을까요?
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.
type 이라면, enum 으로 만들어서 관리하는 편이 훨씬 좋겠군요.
지적해주셔서 감사합니다.
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.
'deliveryType',' imageType' 그리고 sale에서 'Badge' 모두 enum으로 관리하면 더 좋았을 것 같습니다.
감사합니다.^^
|
||
@Autowired | ||
public DishDao(DataSource dataSource) { | ||
jdbcTemplate = new JdbcTemplate(dataSource); |
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.
JdbcTemplate
도 의존성 주입을 받을 수 있습니다.
어떻게 하면 될지 검색해 보시고, 그렇게 하시는 편이 좋겠습니다.
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.
JdbcTemplate 도 의존성 주입을 받을 수 있습니다.
와! 이건 상상도 못했는데, 찾아보겠습니다.
알려주셔서 감사합니다.
@Query("SELECT image.* from sidedish.image INNER JOIN sidedish.dish_image ON image.id = dish_image.image WHERE image.type = 'thumb' AND dish_image.dish = :detailHash;") | ||
List<Image> findThumbImagesByDish(String detailHash); | ||
|
||
@Query("SELECT image.* from sidedish.image INNER JOIN sidedish.dish_image ON image.id = dish_image.image WHERE image.type = 'detail' AND dish_image.dish = :detailHash;") | ||
List<Image> findDetailImagesByDish(String detailHash); |
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.
WHERE image.type = ?
부분의 조건을 삭제하고, Service 에서 image.type 에 따라 dto 에 다르게 값을 넣어주면 되겠네요.
불필요하게 쿼리가 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.
파라미터값에 detail, thumb 을 받아도 될 것같습니다.
불필요한 쿼리메소드 줄이는 것에 신경써서 코딩하겠습니다.
감사합니다.
|
||
public class DishDetailDto { | ||
private final List<String> thumbImages; | ||
private final int point; | ||
private final Integer point; |
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.
int
에서 Integer
가 된 특별한 이유가 있나요?
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.
insert 를 하는 초기화 sql 중에서 point 의 값이 비어있는 Record 들이 있어서,
터지는 것을 방지하기 위해서 임시로 Integer 로 바꾸었습니다.
코드를 바꾸는 좋지 못한 해결책 같네요.
// return dishRepository.findAllByCategoryId(categoryId) | ||
// .stream().map(this::convert) | ||
// .collect(Collectors.toList()); | ||
} | ||
|
||
// private DishDto convert(Dish dish) { | ||
// String detailHash = dish.getDetailHash(); | ||
// List<Delivery> deliveries = deliveryRepository.findAllByDish(detailHash); | ||
// List<Sale> sales = saleRepository.findAllByDish(detailHash); | ||
// return DishDto.from(dish, deliveries, sales); | ||
// } |
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.
삭제하도록 하겠습니다.
List<Image> thumbImages = imageRepository.findThumbImagesByDish(detailHash); | ||
List<Image> detailImages = imageRepository.findDetailImagesByDish(detailHash); |
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.
결국 두 종류의 이미지를 모두 불러와야 하는군요.
그렇다면 Image
안에 thumb
, detail
구분이 가능한 필드만 있으면, 한번에 불러와서 DTO로 넘겨도 되는 거 아닐까요?
DTO가 만들어질 때 두 개를 구분해서 넣으면 될 것 같은데요. 어떻게 생각하세요?
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.
아, 그게 확실히 더 효율적일것 같습니다.
동의합니다.
Dish dish = getDish(detailHash); | ||
QuantityDto quantityDto = getDetailQuantity(detailHash); | ||
if (quantityDto.getQuantity() > count) { | ||
int upqua = quantityDto.getQuantity() - count; |
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.
upqua
라는 변수명을 보고 그 뜻을 알아볼 수 있는 사람은 단언컨대 한 명도 없을 것 같습니다...
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.
급하게 코딩하느라 변수명 신경 못썼습니다.
updatedQuantity 라고 의도했습니다...
부족한 부분을 콕 찝어서 말씀해주셔서 감사합니다. |
금요일날 시연이 끝나서, 리뷰를 받을 수 있을까 걱정했는데, 다음주 미션을 할 때는 특히 테스트 코드를 신경써서 개발을 해 볼 수 있도록 하겠습니다! |
저 역시 프로젝트 기간이 끝나서 리뷰를 못 받지 않을까 했었는데, 리뷰주셔서 감사합니다.~ 프로젝트는 기간이 정해져 있어 구현에만 집중하여 코드가 많이 부족합니다. 감사합니다. |
#20 의 피드백들을 반영하려다 보니, 구현할 내용이 자꾸만 커져버려서 너무 뒤늦게 PR 을 올리게 되었습니다.
JDBC 와 데이터베이스가 익숙치 않아서 시간이 너무 오래 걸려 죄송합니다.
피드백 주신대로 Spring profile 을 이용해서, H2 와 MySQL 의 분기처리가 쉽게 일어나도록 하였습니다.
기존의 지나치게 거대했던 Dish 도메인 객체도 Image, Sale, Delivery 등으로 분리될 수 있도록 하였습니다.
아직 미구현된 부분은 다음과 같습니다.
refreshable 여부를 결정하는 컴포넌트의 설계 및 구현이 아직 완성되지 않았으며,
익숙치 않은 Spring JDBC 를 사용하다보니, Derived Queries 를 제대로 활용하지 못하고 쿼리를 직접 작성하게 되었습니다.
(Derived Queries 로 발생하는 버그를 며칠간 제대로 해결하지 못해서 시간을 날리다 보니, 뒤늦게 그냥 쿼리를 작성하게 되었습니다.)
지금은 프로젝트 규모가 크지 않다보니 직접 쿼리를 짜는게, Derived Queries 보다 개발 속도가 빠른 것 같습니다.
익숙치 않은 삽질을 계속하다보니, 미흡한 부분이 많습니다.
N+1 문제도 아직 제대로 해결을 하지 못했는데, 쿼리 수정을 통해 해결할 수 있도록 하겠습니다.
#20 에서 주신 피드백 덕분에, 정말로 여러가지를 더 시도할 수 있었습니다.
언제나 좋은 피드백 감사합니다!
그리고 욕심을 부리다가 피드백에 빠르게 반응을 하지 못해서 죄송합니다.