요새 글을 쓰지 않았지만
요만큼 프로젝트는 지금도 조금씩 조금씩 진행중이다.
이번에 백엔드 개발자님이 들어오셨는데
아는 게 많으셔서 배울 게 무지 많다!
개발자님이 기존 코드를 보시고 몇 가지 컨벤션을 제안해주셨다.
필수도 있고 선택도 있었는데 모두 괜찮은 방법들이라고 생각했고 그렇다면 고칠 수밖에 없지 !
1. 전역 변수를 지역 변수로 수정하자
기존에는 Email 서비스 등 전역 변수를 사용 중인 곳이 있었다.
그런데 싱글톤 객체에서 중간에 변경이 가능한 지역 변수를 사용할 경우
여러 스레드에서 접근을 하면 스레드 세이프 하지 않아 문제가 생길 가능성이 있다고 했다.
그래서 해당 코드를 수정해주었다.!
Before
private final SpringTemplateEngine templateEngine;
private final RedisUtil redisUtil;
private MimeMessage message;
@Value("${mail.id}")
private String fromEmail;
private String title;
private String template;
private final long EXPIRE_CODE_TIME = 60 * 15L;
private String randomCode = "";
private final String CHARSET = "UTF-8";
private final String HTML = "html";
After
@Override
public MimeMessage setTemplate(Mail type, String userEmail, String randomCode) throws MessagingException {
String key = "";
String value = "";
String title = "";
String template = "";
if (type.equals(Mail.JOIN)) {
title = "YOMANKUM * 가입 코드 전송";
template = "email/joinMailForm";
key = "code";
value = randomCode;
}
MimeMessage message = setMimeMessage(userEmail, key, value, title, template);
final long EXPIRE_CODE_TIME = 60 * 15L;
redisUtil.setDataExpire(userEmail, randomCode, EXPIRE_CODE_TIME);
return message;
}
사용하는 메서드 안에서 선언하도록 !
2. ResponseCode 직관적으로 수정
기존 ResponseCode 는 각 api 상태에 따라 LOGIN000 등,
생성자 메시지를 확인해봐야지만 진짜 상태를 알 수 있었다.
하지만 이 방법은 직관적이지 못하다고 판단했고. 기존 코드를 수정해주었다.
Before
// 로그인
LOGIN000("200 OK"),
LOGIN001("JSON DECODE ERROR"),
LOGIN002("Unsupported language"),
LOGIN003("No language value or Type"),
LOGIN004("Invalid data by user"),
// 이메일
EMAIL000("200 OK"),
EMAIL001("JSON DECODE ERROR"),
EMAIL002("Unsupported language"),
EMAIL003("No language value or Type"),
EMAIL004("Invalid data by user"),
// 가입
SIGNUP000("200 OK"),
SIGNUP001("JSON DECODE ERROR"),
SIGNUP002("User Duplicated"),
SIGNUP003("No language value or Type"),
SIGNUP004("Invalid data by user");
After
OK("200 OK"),
USER_NOT_FOUND("유저를 찾을 수 없습니다."),
EMAIL_CODE_NOT_MATCHED("이메일 코드가 다릅니다."),
EMAIL_ERROR("메일을 보낼 수 없습니다."),
EMAIL_NOT_FOUND("이메일을 찾을 수 없음."),
NOT_VALID("형식을 확인하세요."),
SNS_DOESNT_EXIST("존재하지 않는 SNS 입니다."),
TOKEN_NOT_VALID("토큰이 정확하지 않음."),
SNS_KEY_NOT_VALID("SNS 공개키가 맞지 않음.");
이제는 한 눈에 봐도 뭐가 잘못됐는지 확인 가능하다.
사실 private final String 으로 선언해도 되긴 하는데 아마 취향 차이일듯 하다..
3. Optional 에서 orElseThrow() 이용
사실 원래 해당 메서드를 이용중이었는데
Exception("message"); 이렇게 메시지를 넣고 싶었는데
orElseThrow() 를 사용하면
orElseThrow(Exception::new) 밖에 사용할 수 없어서 그냥 널을 반환한 뒤
if 문으로 검증했는데
orElseThrow() 도 예외에 메시지를 담을 수 있다는 걸 알려주셔서 기꺼이 수정했다!
Before
User findUser = userRepository.findByEmail(email)
.orElse(null);
if (findUser != null) {
log.error("해당 유저 존재하지 않음 : {}", email);
throw new IllegalArgumentException();
}
After
@Override
public void signUp(UserSignUpDto userSignUpDto) throws UserNotFoundException {
String email = userSignUpDto.getEmail();
String password = userSignUpDto.getPassword();
userRepository.findByEmail(email)
.orElseThrow(() -> new UserNotFoundException(ResponseCode.USER_NOT_FOUND));
굿!!
이제 Response.Code 로 상태도 관리할 수 있당 ㅇ_ㅇ
4. 사용자 정의 예외와 핸들러 추가
이것도 사실 원래 사용중이었는데....
왠지 사용자 정의 예외보다는 최대한 언어나 프레임워크가 제공하는 일반 예외만 사용해야 하는 거 아닐까? 싶어서
그냥 자바가 제공하는 예외로 바꿔놨었는데
사용자 정의 예외를 사용하는 게 더 낫다 하셔서 바꿈!
그리고 핸들러도 회사에서 쓰지 말라고, 그냥 try-catch 쓰라고 하셔서
긴가민가하면서 이게 맞나 하면서 요만큼 프로젝트 코드도 수정했었는데
서비스는 로직만 처리하고 예외 처리는 핸들러에 위임하는 게 맞다고 해주셔서 저는 기꺼이 수정했나이다...(감동)
Before
은 그냥 자바 제공 예외 사용
After
@Data
public class UserNotFoundException extends Exception {
private ResponseCode responseCode;
public UserNotFoundException() {
}
public UserNotFoundException(String message) {
super(message);
}
public UserNotFoundException(ResponseCode responseCode) {
this.responseCode = responseCode;
}
}
사용자 정의 예외 추가
예외가 터지면 ResponseCode 를 반환하고 싶었기 때문에 Response Code 를 받는 메서드를 추가했당..!
-> 생각해보니 이거 BaseException Class 만들어서 상속시키면 굳이 ResponseCode 생성자 추가 안 해도 되지 않을까 하는 생각
@PostMapping
@Operation(summary = "일반 회원 로그인", description = "일반 회원용 로그인")
public ResponseEntity<Response> login(@RequestBody @Valid LoginDto loginDto) throws UserNotFoundException {
컨트롤러까지 던져 던져~
@Slf4j
@RestControllerAdvice
public class UserExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(UserNotFoundException.class)
@ResponseBody
public ResponseEntity<Response> userNotFoundHandler(UserNotFoundException e) {
log.error("유저 에러 : {}", e.getResponseCode().getMessage());
e.printStackTrace();
return Response.badRequest(e.getResponseCode());
}
}
유저 관련 예외를 잡는 핸들러 추가
로그도 남겨주고
printStackTrace()로 어디서 에러가 났는지도 보여주고 싶었다.
5. 컨트롤러엔 오직 요청과 응답 책임만 주자
서비스엔 서비스 로직만
컨트롤러엔 요청을 받고 서비스에 요청을 해결하고 응답 객체를 반환하는 책임을 위임하고 다시 응답을 하는 것은 컨트롤러가 하자.
그러니까 컨트롤러는 응답, 요청의 책임만 주는 게 낫지 않냐는 의견을 주셔서 그대로 시도해보았다.
나는 사실 서비스가 응답을 주면 그걸 검증하고 반환하는 것까지 컨트롤러에 책임이 아닐까 생각했는데
나의 생각이 정확한 것도 아니고 일리있다고 생각했다.
(왜냐면 SpringSecurity 를 공부할 때 오직 응답과 요청을 하는 책임만 가진 객체가 있다고 배웠기 때문에
그것이 컨트롤러의 역할을 하는 것이고, 우리가 만드는 컨트롤러도 결국 똑같은 개념이지 않을까 싶었음)
그래서 바꿔따.
Before
@PostMapping("/email/check")
@Operation(summary = "메일 인증 코드 체크", description = "메일 인증 코드 체크")
public ResponseEntity<Response> checkEmailCode(@RequestBody @Valid EmailCodeDto emailCodeDto) {
boolean isSuccessMailCode = mailService.verifyEmailCode(emailCodeDto.email(), emailCodeDto.code());
if (!isSuccessMailCode) {
log.error("입력한 코드가 일치하지 않음 : {}", emailCodeDto.code());
return Response.badRequest(ResponseCode.EMAIL004);
}
return Response.ok(ResponseCode.EMAIL000);
}
}
지금은 검증하는 책임도 가지고 있다.
After
@PostMapping("/email/check")
@Operation(summary = "메일 인증 코드 체크", description = "메일 인증 코드 체크")
public ResponseEntity<Response> checkEmailCode(@RequestBody @Valid EmailCodeDto emailCodeDto) throws CodeNotFoundException, CodeNotValidException {
mailService.verifyEmailCode(emailCodeDto.email(), emailCodeDto.code());
return Response.ok(ResponseCode.OK);
}
}
이젠 오직 요청과 응답만 할 뿐이다.
나머지는 뭐 간략하게...
Token 을 사용하는 곳에서 쓰는 용어들을 enum으로 바꿔서 관리하거나.
@Getter
public enum Tokens {
TYP("typ"),
BEARER("Bearer"),
TOKEN_RESPONSE("tokenResponse"),
ACCESS_TOKEN("accessToken"),
REFRESH_TOKEN("refreshToken"),
ALGORITHM("SHA256withRSA"),
ID("id"), NICKNAME("nickname"), ROLE("role"),
SUB("sub");
private String realName;
Tokens(String realName) {
this.realName = realName;
}
}
그 외에 컨벤션으로 한 메서드에 코드를 15줄 이상 주지 말자던가 하는 게 있어서
메서드로 뽑아낸 경우도 있고
요런 느낌
그렇습니다!~~~~
재미있게 재미있게 개발중입니다.
이번 개발자님은 중간 탈주를 안 하실 거 같구
아는 것도 많으시구 좋으신 분 같아 기부니가 좋아요!
꼭 완성합시다 !
'프로젝트 > 개인 프로젝트) 요만큼' 카테고리의 다른 글
요만큼 ) 여전히 개발 진행중 (0) | 2024.03.02 |
---|---|
refactor ) 예외 상황을 좀 더 멋지게 처리해보자! (1) | 2024.02.01 |
새로운 백엔드 개발자님이 바로? 그리고 JWT ... (1) | 2023.11.07 |
백엔드 개발자가 런했다.. (0) | 2023.11.06 |
프로젝트 인원이 구해졌다. 드디어 백엔드랑 일해본다! (0) | 2023.11.05 |