Skip to content
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] 김예찬 강화하기 #4

Open
wants to merge 38 commits into
base: yechan-kim
Choose a base branch
from

Conversation

yechan-kim
Copy link
Member

@yechan-kim yechan-kim commented May 29, 2024

미션 실행 결과

[테스트 실행 터미널 캡쳐 이미지 파일 첨부]
image

API 기능 명세서

  • POST /users/register - 회원가입
  • POST /users/login - 로그인
  • GET /users/check-duplicate-id - id 중복 확인
  • PATCH /items- 아이템 추가
  • GET /items - 내 아이템 조회
  • POST /enhance - 아이템 강화하기 및 결과 조회
  • GET /items/top10 - 상위 10개 아이템 조회

해결하지 못한 문제

  • 인증을 원하는 부분의 API를 hasRole("USER")authenticated()을 통해 권한을 지정해 주려고 했으나, 403 오류가 반환되어 모든 API를 permitAll로 권한 없이 접근이 가능하도록 한 문제
  • 요구사항에는 제한된 레벨이 없으나, 레벨이 제한되어 있는 문제

@yechan-kim yechan-kim self-assigned this May 29, 2024
Copy link
Member

@rootTiket rootTiket left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! Dto를 record로 구성하고 자바 스터디에서 공부하고 있는 스트림, 람다 문법을 적극적으로 활용해서 코드 가독성을 올리고 계신게 눈에 띕니다
코멘트를 추가하였으니 읽고 의견 부탁드려요!

private final BladeService bladeService;

@PatchMapping("/items")
public ResponseEntity<BladeCreateResponse> createBlade(@RequestHeader("Authorization") String authorizationHeader, @RequestBody @Valid BladeCreateRequest bladeCreateRequest) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid 어노테이션을 쓰시는 이유가 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vaild를 사용해서 RequestDTO들의 유효성을 검사하기 위해서 입니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO들의 입력 유효성 검사를 백엔드 / 프론트 엔드 중 어느쪽에서 하는게 맞을지 같이 고민해보면 좋을 거 같아요

@Transactional
public BladeCreateResponse createBlade(String authorizationHeader, BladeCreateRequest bladeCreateRequest) {
String userEmail = jwtService.extractEmailFromToken(authorizationHeader);
User user = userRepository.findByUsername(userEmail).orElseThrow(IllegalStateException::new);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유저가 존재하지 않을 때 예외를 직접 구현하시면 더 좋을 것 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외 객체를 만드는 것이 아직 익숙하지 않아서 학습하고 있습니다 추후에 리팩토링 해보겠습니다.

Comment on lines 57 to 58
User user = userRepository.findByUsername(userEmail).orElseThrow(IllegalStateException::new);
Blade blade = bladeRepository.findByUser(user).orElseThrow(IllegalStateException::new);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위 코멘트와 비슷한 맥락이지만 같은 예외가 나올 경우 어디서 예외가 발생했는지 찾기 어려울 수 있습니다. 같은 종류의 에러라도 발생한 원인(유저를 찾지 못한다, 칼을 찾지 못한다) 같이 어느 부분에서 예외가 발생하는지 알 수 있게 하는 것이 관리면에서 더 편할 것 같습니다 :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네! 감사합니다!

Comment on lines 70 to 85
if (Math.random() <= blade.getLevel().getSuccessProbability() + increaseProbability) {
blade.updateLevel(BladeLevel.fromLevel(blade.getLevel().getLevel() + 1));
bladeRepository.save(blade);
return BladeEnhanceResponse.of(blade, "강화에 성공했습니다.");
}

if (Math.random() <= blade.getLevel().getDestroyProbability()) {
blade.updateLevel(BladeLevel.fromLevel(0));
bladeRepository.save(blade);
return BladeEnhanceResponse.of(blade, "검이 파괴되었습니다.");
}

blade.updateLevel(BladeLevel.fromLevel(blade.getLevel().getLevel() - 1));
bladeRepository.save(blade);
return BladeEnhanceResponse.of(blade, "강화에 실패했습니다.");
}
Copy link
Member

@rootTiket rootTiket May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bladeRepository.save(blade) 코드가 중복되고 있는데 변경사항을 가장 나중에 저장하여 중복코드를 줄여보는 것은 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반환되는 객체가 다르기 때문에 저장하고 반환하는 로직만 생각해서 이 부분을 고려하지 못 했던 것 같습니다. 해당 사항은 수정하겠습니다!

Comment on lines 88 to 91
List<Blade> top10Blade = bladeRepository.findTop10ByOrderByLevelDesc();
return top10Blade.stream()
.map(Top10BladeResponse::of)
.collect(Collectors.toList());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변수로 리스트를 가져와서 stream으로 만드는 것 보다

        return bladeRepository.findTop10ByOrderByLevelDesc().stream()
                .map(Top10BladeResponse::of)
                .collect(Collectors.toList());

로 수정하는 것은 어떨까요? 불 필요한 선언이 줄어들 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 개선하겠습니다!

public interface UserRepository extends JpaRepository<User, UUID> {
Optional<User> findByUsername(String email);

boolean existsByUsername(String email);
Copy link
Member

@rootTiket rootTiket May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raw 타입으로 가져오시는 이유가 있을까요? Boolean으로 바꾸시는 건 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Row Type으로 받아도 문제가 없어서 수정하지 않고, 그냥 지나친것 같습니다. 수정하겠습니다!

@yechan-kim yechan-kim changed the base branch from main to yechan-kim May 29, 2024 13:42
Copy link
Member

@jwnnoh jwnnoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다!

return ResponseEntity.ok(bladeService.enhance(authorizationHeader, bladeEnhanceRequest));
}

@GetMapping("/items/top10")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컨트롤러단에 RequestMapping을 통해 /item으로 uri를 우선 구분해주고,
이후 /top10 방식으로 uri를 매핑해주면 더욱 좋을 것 같습니다.

@RequestMapping("/item")
/*
...
*/
@GetMapping("/top10")

Copy link
Member Author

@yechan-kim yechan-kim May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당컨트롤러에는 /items/enhance가 같이 존재하는데 어떻게 처리하면 좋을까요?

@RequiredArgsConstructor
@Builder
@Entity
@Table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엔티티하고 테이블 어노테이션은 중복된 기능을 가집니다.
둘 중 하나를 선택해서 제거하는 것을 추천드립니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다! @Entity로 통일하겠습니다!

return Arrays.stream(BladeLevel.values())
.filter(l -> l.getLevel().equals(level))
.findFirst()
.orElse(BladeLevel.LV12);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러를 따로 명시해주지 않고 최대 레벨로 반환하는 이유가 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0레벨에서 강화에 성공할 확률은 100%이기 때문에 0미만의 레벨은 나올 수가 없습니다.
하지만 13 이상의 레벨은 나올 수 있기 때문에 13레벨 이상이 나오면 최대 레벨로 반환하는 로직으로 구현했습니다.
원래는 최대 레벨 이후로는 확률이 동일해 확률은 동일하고 레벨만 상승하게 하려는 기능을 구현하려고 했으나, 아직까지 구현하지 못해 임시로 저렇게 조치를 해두었습니다. 추후에 기능이 구현된다면 해당 부분은 수정할 예정입니다!

private final BladeService bladeService;

@PatchMapping("/items")
public ResponseEntity<BladeCreateResponse> createBlade(@RequestHeader("Authorization") String authorizationHeader, @RequestBody @Valid BladeCreateRequest bladeCreateRequest) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO들의 입력 유효성 검사를 백엔드 / 프론트 엔드 중 어느쪽에서 하는게 맞을지 같이 고민해보면 좋을 거 같아요

import leets.enhance.gloal.error.ErrorCode;
import leets.enhance.gloal.error.exception.ServiceException;

public class TooLongBladeNameException extends ServiceException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커스텀 예외를 추가로 정의하신 부분은 좋아요!


// 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authenticationManager.authenticate(authenticationToken)로 조금 더 간단하게 구현할 수 있을 것 같은데 한 번 고려해보시는 건 어떨까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants