-
Notifications
You must be signed in to change notification settings - Fork 6
BE 코드 컨벤션
Leetaehoon edited this page Aug 8, 2024
·
1 revision
1.1 IntelliJ Code Style은 우테코 스타일을 적용한다.
2.1.1 클래스 상수, 멤버 변수, Static 메서드, Instatnce 메서드순으로 선언한다.
2.1.2 final은 기본적으로 붙이지 않는다. 필요한 경우에만 붙인다.
2.1.3 entity 클래스에는 equals, hashcode, toString을 반드시 선언한다.
public class Controller {
private static final int NUMBER = 1;
private final ReservationApplicationService reservationApplicationService;
private final MemberService memberService;
public static Controller of() {
}
public static void hello() {
System.out.println("hello");
}
public void hi() {
System.out.println("hi");
}
}
2.2.1 주요 annotation(Entity, Service…)를 맨위에 선언한다.
2.2.2 Lombok 관련 어노테이션은 하위에 선언한다.
@Service
@Transactional(readOnly=true)
@NoArgsContructor
class Service {
}
3.1.1 첫번째 필드는 개행을 추가한뒤 선언한다.
3.1.2 어노테이션이 붙은 필드는 개행을 추가한다.
@Entity
@Getter
public class Member extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private Name name;
@Embedded
private Email email;
@Column(nullable = false)
private String password;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
public boolean isAdmin() {
return role == Role.ADMIN;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Member)) {
return false;
}
Member member = (Member) o;
return Objects.equals(getId(), member.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
@Override
public String toString() {
return "Member{" + "id=" + id + ", name=" + name + ", email='" + email + '\'' + '}';
}
}
3.1.3 Interface의 메서드 선언마다 개행을 추가한다.
public interface ReservationRepository extends JpaRepository<Reservation, Long> {
Optional<Reservation> findReservationByDateAndTimeAndTheme(LocalDate date, ReservationTime time, Theme theme);
boolean existsByTimeId(long timeId);
boolean existsByThemeId(long themeId);
}
3.1.4 클래스 내부가 비어있는 경우 개행을 추가한다.
record Dto(String name) {
}
3.2.1 ResponseEntity에서 120줄이 넘어갈 경우에만 개행을 추가한다.
@PostMapping("/logout")
public ResponseEntity<Void> logout(HttpServletResponse response) {
responseHandler.expire(response);
return ResponseEntity.ok().build();
}
3.2.2 매개변수 시그니처가 120줄이 넘어갈 경우, 인자당 개행을 추가한다.
@PostMapping("/signup")
public ResponseEntity<MemberResponse> signUp(
@RequestBody @Valid SignUpRequest signUpRequest,
@RequestBody @Valid SignUpRequest signUp
) {
SignUpCommand signUpCommand = new SignUpCommand(
signUpRequest.name(),
signUpRequest.email(),
signUpRequest.password()
);
MemberResponse memberResponse = authService.signUp(signUpCommand);
return ResponseEntity.created(URI.create("/login")).body(memberResponse);
}
public List<MyReservationInfo> findMyReservations(Member member) {
List<MemberReservation> memberReservation = memberReservationRepository.findByMemberId(member.getId());
return memberReservation.stream()
.map(this::add)
.toList();
}
3.4.1 파라미터에 어노테이션이 없는 경우 필드 사이에 개행을 두지 않는다.
public record AvailableTimeResponse(
long timeId,
LocalTime startAt,
boolean alreadyBooked
) {
}
3.4.2 파라미터에 어노테이션이 있는 경우 필드 사이에 개행 둔다.
public record MemberReservationRequest(
@NotNull(message = "예약 시간 id는 필수 값입니다.")
@Positive
Long memberId,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "Asia/Seoul")
@NotNull(message = "예약 날짜는 필수 값입니다.")
LocalDate date,
@NotNull(message = "예약 시간 id는 필수 값입니다.")
@Positive
Long timeId
) {
}
4.1.1 ’ // ‘이후에 스페이스를 한번 사용한다.
4.1.2 ‘&’ 와 단어를 붙인다.
@DisplayName("결제에 성공하면, 응답을 반환한다.")
@Test
void successfulPayment() {
// given
String paymentKey = "tgen_20240528172021mxEG4";
String paymentType = "카드";
BigDecimal totalAmount = BigDecimal.valueOf(1000L);
PaymentRequest paymentRequest = new PaymentRequest(totalAmount, "MC45NTg4ODYxMzA5MTAz", paymentKey);
PaymentResponse okResponse =
new PaymentResponse(paymentKey, "DONE", "MC4wOTA5NzEwMjg3MjQ2", totalAmount, paymentType);
doReturn(okResponse).when(paymentClient).confirm(any());
// when
paymentService.pay(paymentRequest, memberReservation);
// then
Optional<Payment> optionalPayment = paymentRepository.findByPaymentKey(paymentKey);
assertAll(
() -> assertThat(optionalPayment).isNotNull(),
() -> assertThat(optionalPayment.get().getPaymentType()).isEqualTo(PaymentType.from(paymentType)),
() -> assertThat(optionalPayment.get().getAmount()).isEqualTo(new Price(totalAmount))
);
}
4.2.1 @Test 위에는 @DisplayName으로 테스트 설명을 적는다.
@DisplayName("가격 도메인 테스트")
@Test
class PriceTest {
@DisplayName("형식에 맞지 않은 가격 생성 시, 예외가 발생한다.")
@ParameterizedTest
@ValueSource(doubles = {-1000.0, -1.1, 210000000000000000L})
void invalidPrice(Double invalidPrice) {
// given&when&then
BigDecimal bigDecimal = BigDecimal.valueOf(0);
assertAll(
() -> assertThat(new Price(bigDecimal).getPrice()).isEqualTo(bigDecimal),
() -> assertThatThrownBy(() -> new Price(BigDecimal.valueOf(invalidPrice)))
.isInstanceOf(IllegalArgumentException.class)
);
}
}
@DisplayName("가격 도메인 테스트")
@Test
class create_invalidMoney() {
}
/**
* need some help
* @param reservationTimeCreate
* @return ReservationTimeResponse
*/
@Transactional
public ReservationTimeResponse create(ReservationTimeCreate reservationTimeCreate) {
LocalTime time = reservationTimeCreate.startAt();
if (reservationTimeRepository.existsByStartAt(time)) {
throw new BadRequestException(ErrorType.DUPLICATED_RESERVATION_TIME_ERROR);
}
ReservationTime reservationTime = new ReservationTime(time);
return ReservationTimeResponse.from(reservationTimeRepository.save(reservationTime));
}
/**
* need some help
* @param reservationTimeCreate
* @return
*/
@Transactional
public ReservationTimeResponse create(ReservationTimeCreate reservationTimeCreate) {
LocalTime time = reservationTimeCreate.startAt();
if (reservationTimeRepository.existsByStartAt(time)) {
throw new BadRequestException(ErrorType.DUPLICATED_RESERVATION_TIME_ERROR);
}
// 도와줘 냥인 제발...
ReservationTime reservationTime = new ReservationTime(time);
return ReservationTimeResponse.from(reservationTimeRepository.save(reservationTime));
}
- 집단명사 사용하는 것을 권장합니다. 이상적인 것은 아니지만 복수형 쓸 수 있습니다. → 웬만하면 단수형으로 작성합니다.
- 예) staff, employees
-
tbl
과 같은 접두사를 사용하지 않습니다. - 테이블명을 컬럼명으로 쓰지 않습니다.
- 가능하면 두 테이블명을 연결해서 관계 테이블 이름을 만드는 걸 지양합니다.
- 예) 다대다 테이블 → 일대다, 다대일로 해결하는 경우
- 항상 단수를 사용합니다.
- 테이블 기본키(PK)로 id를 사용하지 않습니다.
- 항상 소문자를 사용합니다.
- 고유명사처럼 의미 전달이 안되는 경우, 예외입니다.