Embedded 를 사용해야하는 이유

Jake·2024년 4월 12일
1
post-thumbnail

임베디드 타입

안녕하세요 여러분. 오늘은 임베디드 타입에 대해서 알아볼게요. JPA에서는 새로운 값 타입을 사용자가 정의하여 사용할 수 있는데 이를 임베디드 타입이라고 불러요.

새로운 값 타입에서 중요한 부분이 있어요.

임베디드 타입도 int, String 과 같이 값타입으로 데이터베이스에 저장되어요

아래의 예시를 보며 기본 값타입과 임베디드 타입에 대해 비교해볼게요.

기본 값타입

여러분은 위 코드를 보고 어떤생각이 드실까요 ?

저게 뭐 어때서 ? 혹은 String 값은 속성으로 자주 사용되는거 아니야 ? 라고 생각하실 수 도 있습니다.

이렇게 생각하셨다면 정말 잘 오셨어요 !


만약 위와 같이 작성한다면 공통된 속성을 3가지로 분리하였네 .. 이를 하나로 묶어서 관리할 수는 없을까? 라고 고민해볼 수 있을거에요.

사실 A 회원의 도시, 거리, 우편번호 이렇게 관련된 정보들이 흩어져 있는 코드보다 -> A 회원의 집 주소 정보 와 같이 묶어져 있는 코드가 더 명확하게 느껴질거에요.

회원이 공통된 관심사에 대해 상세한 데이터를 하나하나 가지는 것 보다 관심사를 묶어서 객체 지향적으로 관리하기 위함이에요.

임베디드 타입

위와 같이 Address라는 주소 타입의 클래스를 정의해주고 사용하는 것이 더욱 좋아요.

장점

임베디드 타입을 사용하게되면 좋은 점은 아래와 같아요.

  • 재사용
  • 높은 응집도
  • Address 객체의 validateUserAddress() 메서드처럼 해당 값 타입만 사용하는 의미있는 메서드를 만들 수 있습니다.

임베디드 타입을 사용하는 방법은 위와 같이 정의 하는 곳에 @Embeddable을 표시하고 사용하려는 곳에 @Embedded를 표시하여 사용할 수 있으며 임베디드 타입은 기본 생성자가 필수 입니다.

유저 엔티티

그래서 저는 현재 위와 같이 식별자를 제외한 모든 속성에 대해 임베디드 타입을 사용하고 있어요.

예를 들어 UserPassword의 경우 비밀번호 encode, 검증 등이 수행되어야 하므로 따로 관리가 많이 필요해요. 이러한 요구사항이 있어서 아래와 같이 구현을 해보았어요.

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserPassword {
    private static final int MIN_PASSWORD_LENGTH = 8;
    private static final int MAX_PASSWORD_LENGTH = 18;

    @Column(name = "password")
    private String password;

    public UserPassword(String rawPassword, CustomPasswordEncoder passwordEncoder) {
        validateNotNull(rawPassword);
        validateUserPasswordLength(rawPassword);
        this.password = passwordEncoder.encode(rawPassword);
    }

    private void validateNotNull(String password) {
        if (Objects.isNull(password)) {
            throw new UserBadRequestException(ErrorCode.BAD_REQUEST, "패스워드는 필수값입니다.");
        }
    }

    private void validateUserPasswordLength(String password) {
        if (password.length() < MIN_PASSWORD_LENGTH || password.length() > MAX_PASSWORD_LENGTH) {
            throw new UserBadRequestException(ErrorCode.BAD_REQUEST,
                    MessageFormat.format("패스워드는 {0}자 이상, {1}자 이하여야 합니다.",
                            MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH));
        }
    }
}

위와 같이 검증 로직을 넣어서 사용할 수 있어요.

이렇게 되면 예외처리, 재사용성, 의미있는 메소드 들의 장점을 모두 가져갈 수 있어요.

0개의 댓글

관련 채용 정보