끝을 보는 용기

Day 088 - Spring 심화 프로젝트 3단계 진행 중, 팀 프로젝트 전에 다 같이 코드 작성 규칙을 정하다.

writingforever162 2025. 1. 2. 23:49

1. 프로젝트 진행 상황 및 계획

🥇 Spring 심화 프로젝트 도전 과제 3단계 끝내기 (진행 중, 25.01.03 완료 목표)
🥈 Spring 심화 프로젝트 필수 과제 2단계 끝내기 (진행 중, 25.01.03 완료 목표)

🥉 Spring 심화 프로젝트 도전 과제 4단계 끝내기 (진행 전, 25.01.04 완료 목표)
4️⃣ Spring 심화 프로젝트 도전 과제 5단계 끝내기 (진행 전, 25.01.04 완료 목표)

5️⃣ Spring 심화 프로젝트 도전 과제 6단계 끝내기 (진행 전, 25.01.05 완료 목표)

 

2. 고민

Q1. ifPresent()를 쓸까, isPresent()를 쓸까? 

더보기
package org.example.expert.domain.auth.service;

import lombok.RequiredArgsConstructor;
import org.example.expert.config.JwtUtil;
import org.example.expert.config.PasswordEncoder;
import org.example.expert.domain.auth.dto.response.SignUpResponseDto;
import org.example.expert.domain.common.exception.InvalidRequestException;
import org.example.expert.domain.user.entity.User;
import org.example.expert.domain.user.enums.UserRole;
import org.example.expert.domain.user.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService {

  private final UserRepository userRepository;
  private final PasswordEncoder passwordEncoder;
  private final JwtUtil jwtUtil;

  @Transactional
  public SignUpResponseDto signUp(
      String email,
      String password,
      String userRole
  ) {

    userRepository.findByEmail(email)
        .ifPresent(
            user -> {
              throw new InvalidRequestException(
                  "Email is already registered"
                  );
            }
        );

    String encodedPassword = passwordEncoder
        .encode(password);

    UserRole role = UserRole.of(userRole);

    User user = new User(
        email,
        encodedPassword,
        role
    );
    
    User savedUser = userRepository.save(user);

    String bearerToken = jwtUtil.createToken(
        savedUser.getId(),
        savedUser.getEmail(),
        savedUser.getUserRole()
    );

    return new SignUpResponseDto(bearerToken);
  }
}
더보기
package org.example.expert.domain.auth.service;

import lombok.RequiredArgsConstructor;
import org.example.expert.config.JwtUtil;
import org.example.expert.config.PasswordEncoder;
import org.example.expert.domain.auth.dto.response.SignUpResponseDto;
import org.example.expert.domain.common.exception.InvalidRequestException;
import org.example.expert.domain.user.entity.User;
import org.example.expert.domain.user.enums.UserRole;
import org.example.expert.domain.user.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService {

  private final UserRepository userRepository;
  private final PasswordEncoder passwordEncoder;
  private final JwtUtil jwtUtil;

  @Transactional
  public SignUpResponseDto signUp(
      String email,
      String password,
      String userRole
  ) {

    boolean isEmailRegistered = userRepository
        .findByEmail(email)
        .isPresent();

    if (isEmailRegistered) {
      throw new InvalidRequestException(
          "Email is already registered"
      );
    }

    String encodedPassword = passwordEncoder
        .encode(password);

    UserRole role = UserRole.of(userRole);

    User user = new User(
        email,
        encodedPassword,
        role
    );
    
    User savedUser = userRepository.save(user);

    String bearerToken = jwtUtil.createToken(
        savedUser.getId(),
        savedUser.getEmail(),
        savedUser.getUserRole()
    );

    return new SignUpResponseDto(bearerToken);
  }
}

A1. 처음에는 ifPresent() 메서드(method)를 활용했으나 userRepository.findByEmail(email) 부분은 다른 데서도 쓰일 가능성이 매우 높았고, boolean 변수를 활용하여 '무엇을 검증하는지' 한눈에 보이도록 구현하고 싶었다. 이런 이유로 isPresent() 메서드를 활용했다.

 

3. 팀 프로젝트 전에 팀에서 정한 코드 작성 규칙(코드 컨벤션, code convention)

① DTO 클래스(class) 이름 짓는 법

- Create / Read / Update / Delete + 엔티티(entity) 이름 + Request / Response + Dto

- 단, 회원가입은 Create 대신 SignUp으로, 로그인은 SignIn으로 짓는다.

- 예시) CreateMemberRequestDto / UpdateTodoResponseDto / ManagerResponseDto
② '수정'은 메서드, 변수, 클래스 상관없이 'update'로 통일

- 'change' 및 'modify'는 사용하지 않기로 했다. 

③ List 변수 이름 짓는 법 

- 객체 이름 + List 
- 예시) List<UserResponseDto> userDtoList / List<Todo> todoList
④ List는 반드시 ArrayList로 먼저 초기화하기

List<Manager> managerList = new ArrayList<>();
        
managerList = managerRepository.findAllByTodoId(todo.getId());

List<ManagerResponseDto> managerDtoList = new ArrayList<>();

⑤ 클래스 이름 짓는 법

- 객체 이름 + Controller / Service / Repository 이름 
- 예시) UserService, ManagerRepository
⑥ DTO(Data Transfer Object) 이름은 requestDto / responseDto 둘 중 하나로 짓기 

@PatchMapping("/edit/{id}")
public ResponseEntity<Void> updateUser(
        @PathVariable UUID id,
        @RequestBody @Valid UserUpdateRequestDto requestDto
)

⑦ return 할 때 new ResponseEntity<>() 사용하기

return new ResponseEntity<>(responseDto, HttpStatus.CREATED);

⑧ 생성자는 어노테이션(annotation) 대신 직접 입력하기

- 나중에 어노테이션을 삭제해야 하는 상황이 왔을 때 곤란해질 수 있으며, 지나치게 의존하면 내부 구현이 어떻게 이루어지는지 모를 수 있으므로 직접 입력하기로 했다.

⑨ if문의 조건식은 boolean 변수로 작성하기

boolean isUserMismatch = !ObjectUtils.nullSafeEquals(
    user.getId(), 
    todo.getUser().getId()
    );

if (isUserMismatch) {
   throw new InvalidRequestException("User does not match");
}

⑩ 컨트롤러(Controller)의 어노테이션(annotation)은 하나씩 줄 바꾸기 

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {

  private final UserService userService;

  @GetMapping("/{userId}")
  public ResponseEntity<UserResponseDto> readUserById(
      @PathVariable long userId
  ) {
    UserResponseDto responseDto = userService.readUserById(userId);

    return new ResponseEntity<>(responseDto, HttpStatus.OK);
  }

  @PutMapping
  public ResponseEntity<Void> updatePassword(
      @Auth AuthUser authUser,
      @RequestBody UpdatePasswordRequestDto requestDto
  ) {
    userService.updatePassword(
        authUser.id(),
        requestDto
    );

    return new ResponseEntity<>(HttpStatus.OK);
  }
}

 

4. 회고

도전 과제 3단계가 정말 뜯어고쳐야 할 부분이 넘쳐 나서 아침에 다 같이 모여 90분 동안 코드 작성 규칙을 미리 정했다. 개인 프로젝트라서 지금 당장 지켜야 할 의무는 없으나 미리 연습하면 좋으니, 규칙에 따라 리팩토링(refactoring)을 진행했다. 내일은 적어도 4단계까지 깔끔하게 끝내서 주말에 테스트 코드 수정하기인 5단계와 스스로 문제를 정의하고 해결해야 하는 6단계에 오롯이 집중할 수 있다. 내일은 오늘보다 더 집중하고, 한 번 더 운동해서 건강을 챙기도록 해야겠다.