[Spring] 기본 자료형이 아닌 구체적인 자료형 생성하기

Hot Deal이라는 프로젝트를 진행하면서 어떻게 하면 데이터의 무결성을 보장할 수 있을지 고민해보았습니다.

 

가격이나 재고와 같은 특정 값을 다룰 때는 이 값들이 항상 올바른 범위를 가지도록 하는 것이 중요합니다. 그렇지 않으면 잘못된 값이 비즈니스 로직에 흘러들어가 시스템 전체에 오류를 일으킬 수 있기 때문입니다.

 

이러한 문제를 해결하기 위해 구체적인 자료형을 생성해 보았습니다.

 

Java의 기본 자료형이 아닌, 값 자체에 대한 제약 조건을 포함하는 Price와 Quantity 클래스를 만들어 활용했습니다. 이로써 코드 중복을 줄이고, 생성과 동시에 유효성 검증을 통해 데이터 무결성을 보장할 수 있습니다.


 

1. 왜 기본 자료형이 아닌 구체적인 자료형을 선택했을까?

가격(Price)과 재고(Quantity)는 특정 비즈니스 규칙에 따라 다뤄져야 하는 값입니다. 예를 들어, 가격은 항상 0 이상의 값이어야 하고, 재고 역시 0 미만으로 설정될 수 없습니다. 이처럼 비즈니스 상의 규칙이 존재하는 값을 단순히 기본 자료형(int, BigDecimal 등)으로 처리한다면, 각 값이 생성될 때마다 이러한 제약 조건을 코드 곳곳에서 검증해줘야 합니다. 이로 인해 중복 코드가 생기고, 유지보수가 어려워질 수 있습니다.

 

따라서, 가격과 재고에 대한 고유한 제약 조건을 Price와 Quantity라는 구체적인 자료형에 포함시켜, 한 곳에서 유효성을 검증하도록 설계했습니다.


 

2. Price 클래스 구현

Price 클래스는 가격을 나타내는 값 객체입니다. 이 클래스는 값이 0 이상이어야 한다는 조건을 가지고 있으며, 이러한 조건을 생성자에서 검증하도록 구현했습니다.

@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Price {

    @Column(nullable = false)
    private BigDecimal price;

    public Price(BigDecimal price) {
        if (price == null || price.compareTo(BigDecimal.ZERO) < 0) {
            throw new HotDealException(INVALID_PRICE);
        }
        this.price = price;
    }
}

 

Price 클래스는 다음과 같은 특징을 가지고 있습니다.

  • @Embeddable을 사용해 JPA에서 값 타입으로 사용될 수 있도록 설정했습니다.
  • 생성자에서 가격이 null이거나 0 미만일 경우, Exception을 발생시켜 잘못된 가격이 입력되지 않도록 했습니다.
  • Price는 개별 상품의 가격을 나타내거나, totalPrice와 같이 총 가격을 나타내는 필드 값으로도 활용될 수 있습니다.

 


 

3. Quantity 클래스 구현

Quantity 클래스는 재고를 나타내는 값 객체입니다.

이 클래스 역시 재고 값이 0 이상이어야 한다는 조건을 가지고 있으며, 필요에 따라 재고를 감소시키는 기능도 포함하고 있습니다.

@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Quantity {

    private Long quantity;

    public Quantity(Long quantity) {
        if (quantity == null || quantity < 0) {
            throw new HotDealException(INVALID_QUANTITY);
        }
        this.quantity = quantity;
    }

    public Quantity decrease() {
        synchronized(this) {
            if (this.quantity <= 0) {
                throw new HotDealException(INVALID_QUANTITY);
            }
            return new Quantity(this.quantity - 1);
        }
    }
}

 

Quantity 클래스의 주요 특징은 다음과 같습니다.

  • 생성자에서 quantity가 null이거나 0 미만일 경우 예외를 던지도록 하여 잘못된 재고 값 입력을 방지합니다.
  • decrease() 메서드를 통해 동기화된 방식으로 재고를 하나 줄이는 기능을 제공하며, 이때 재고가 0 이하로 내려가면 예외를 발생시켜 재고 부족을 방지합니다.

 


 

4. 구체적인 자료형의 이점

구체적인 자료형을 사용하는 이 접근 방식의 장점은 다음과 같습니다.

  • 유효성 검증: 클래스의 생성자에서 유효성 검증이 진행 되기 때문에 객체 생성 시 자동으로 검증이 이루어집니다. 이를 통해 코드 중복이 줄어들고, 잘못된 값이 시스템에 들어오는 것을 방지할 수 있습니다.
  • 가독성 향상: 가격이나 재고가 BigDecimal이나 Long으로 선언된 코드보다 Price와 Quantity 같은 구체적인 클래스 이름을 통해 더 명확하게 표현됩니다. 이를 통해 코드의 가독성이 향상됩니다.
  • 비즈니스 로직의 캡슐화: 가격과 재고에 대한 비즈니스 로직이 각각의 클래스 내부에 캡슐화되어 외부에서는 이 클래스들을 통해서만 접근할 수 있게 되었습니다.