카테고리 없음

✅ 나만의 개발 규칙 정리

creator7087 2025. 5. 4. 11:32
아래의 규칙이 정답이 아닐 수는 있다. 하지만 지금까지 경험으로 이렇게 했을 때 실수를 줄일 수 있었다.

1. 주석은 메소드의 목적에만 작성한다

  • 설명: 메소드가 무엇을 하는지에 대해서만 주석을 달고, 어떻게 구현했는지에 대한 주석은 가능한 한 배제합니다.
  • 이유: 과도한 주석은 코드 변경 시 함께 관리해야 할 대상이 되어 오히려 유지보수의 부담이 커질 수 있습니다.

💡 팁: 코드 자체가 잘 읽히도록 이름 짓기와 구조 개선을 우선하고, 정말 필요한 부분에만 간결한 주석을 달자.

 

2. Request/Response 객체는 별도의 DTO(Entity)로 분리하여 작성한다

  • 설명: 컨트롤러나 서비스에서 직접 엔티티(Entity)를 사용하지 않고, 반드시 요청(Request)과 응답(Response)에 알맞는 DTO를 분리하여 사용합니다.
  • 이유:
    • 엔티티를 직접 사용하는 방식은 단일 책임 원칙(SRP)을 위반하고, 유효성 검증/직렬화/변환 등 다양한 관심사들이 뒤섞이는 구조가 됩니다.
    • DTO 분리는 역할을 명확히 나눠주며, 확장성과 유지보수성을 높입니다.
    • 또한 DTO 내부에 toEntity(), from(Entity) 같은 정적 팩토리 메서드를 명시함으로써, 변환 책임을 캡슐화하고 외부 호출자(Service, Controller)의 복잡도를 줄일 수 있습니다.

💡 팁 1: 요청 DTO에는 @NotBlank, @NotNull, @Pattern 등의 검증 어노테이션을 붙여 사용자 입력 검증까지 처리하도록 설계하세요.
💡 팁 2: 응답 DTO는 from(Entity) 정적 메서드를 사용해 변환 책임을 한곳에 집중시키면, 테스트 및 재사용이 훨씬 쉬워집니다.

✅ 예시

더보기

// 요청 DTO
@Getter
@Builder
public class ShopRequestDto {
    private String shopName;
    ...
    public Shop toEntity(User user) {
        return Shop.builder()
            .shopName(shopName)
            ...
            .user(user)
            .build();
    }
}

// 응답 DTO
@Getter
@Builder
public class ShopResponseDto {
    private String storeName;
    ...
    public static ShopResponseDto from(Shop shop) {
        return ShopResponseDto.builder()
            .storeName(shop.getShopName())
            ...
            .build();
    }
}

 

3. for문과 삼항 연산자는 가급적 자제한다

  • 설명: 복잡하거나 중첩된 for문, 삼항 연산자는 가독성을 떨어뜨리고, 버그나 오해의 소지가 커집니다.
  • 이유: 추후 코드 분석이나 수정 시 의도를 파악하기 어려워 유지보수가 어려워집니다.

💡 팁: Stream, if-else, Optional 등을 적극 활용하고, 로직은 별도의 메서드로 분리하는 습관을 들이자.

 

4. 서비스 계층의 테스트 코드는 Best Case를 먼저 작성한다

  • 설명: 서비스 계층에서 정상 흐름에 대한 테스트(Best Case)는 구현 직후 빠르게 작성합니다.
  • 이유: 구현 직후 테스트 코드를 작성하면, 수정 포인트가 명확해지고 불필요하거나 목적에서 벗어난 수정을 방지할 수 있습니다.

💡 팁: 테스트 함수 이름은 given-when-then 패턴을 따르도록 작성하여, 테스트 목적과 기대 결과를 명확히 하자.

 

5. 유효성 검증은 별도의 validateEntity() 또는 서비스의 validateXXX() 메서드로 분리한다

  • 설명
  • 이유:
    • 비즈니스 로직과 검증 로직이 섞이면 코드 흐름이 복잡해지고 테스트하기 어려워짐
    • 검증 실패 시 빠르게 예외 처리할 수 있어, fail-fast 설계에 적합
더보기

public void validateEntity() {
    if (minDeliveryPrice < 0) {
        throw new IllegalArgumentException("최소 배달비는 0 이상이어야 합니다.");
    }
    if (openTime.isAfter(closeTime)) {
        throw new IllegalArgumentException("영업 시작 시간이 종료 시간보다 늦을 수 없습니다.");
    }
}

💡 팁: validateEntity()는 Service 계층에서 엔티티 생성 전 호출하는 것이 일반적입니다.
💡 팁: Spring Validation(@Valid)이 부족한 비즈니스 규칙 검증을 보완할 때 유용합니다.

 

6. @Setter 사용을 자제하고 불변 객체(Immutable Object)를 지향한다

  • 설명: 엔티티나 DTO에 무분별하게 @Setter를 사용하면 예측하지 못한 값 변경이나 JPA dirty checking 오작동을 유발할 수 있다.
  • 이유:
    • @Setter는 객체 일관성 유지에 불리하고, 무분별한 쿼리 생성을 유도할 수 있음
    • 특히 JPA에서는 필드 값 변경 = update 쿼리 생성 조건이 되므로, 원치 않는 UPDATE가 발생할 수 있음
    • 의도를 가진 메서드(changeStatus(), updateAddress())로 명시적 변경하는 것이 안전함
더보기

// Bad Practice
@Setter
private String address;

// Good Practice
private String address;

public void updateAddress(String newAddress) {
    this.address = newAddress;
}

 

7. if-else보다는 if만 사용하기

  • 설명: 조건문에서 else를 사용하는 대신, 가능한 한 if만 사용하여 코드의 가독성을 높입니다.
  • 이유: if-else 구조가 복잡해지면, 코드 흐름을 파악하기 어려워질 수 있으며, 조건문을 단순화함으로써 더 명확하게 의도를 전달할 수 있습니다. 또한, if만 사용할 경우 조건이 하나씩 독립적으로 평가되므로, 각 조건에 대한 수정이나 확장이 용이합니다.
💡 팁: 조건문이 길어지지 않도록 최대한 간결하게 유지하고, 필요 시 메서드로 분리하여 가독성을 높입니다.