[스프링] 엔티티에서 @Setter 사용을 지양해야 하는 이유와 빌더패턴

peeerr·2023년 2월 25일
0

Spring

목록 보기
2/10
post-thumbnail

📌 엔티티 클래스에서 @Setter 사용을 지양해야 하는 이유


1. Setter 메서드 사용 시 의도 파악이 어렵다.

@Setter 사용 시 메서드명은 setXxx()가 될 것이다.
이러한 메서드명은 어떤 의도로 이 메서드를 사용한 건지 파악을 하기 매우 어렵다.

-> 의도를 파악하기 쉽게 메서드명을 설정해야 한다.
예를 들어 분실물의 발견 여부를 체크하는 필드가 있다고 가정해 보자.

public class Item {
    public void foundItem() {
        this.found = true;
    }
}

public void 분실물_발견됨() {
    item.foundItem();
}

이런식으로 단순히 setter를 사용하는 것보다 의도를 정확하게 드러내는 것이 중요하다.

2. 값이 변경되면 안되는 필드가 변경될 수 있다.

@Setter 를 클래스 단위에 붙여두면 막 변경하면 안되는 필드에도 setter 메서드가 만들어 진다.
이렇게 되면 다른 개발자가 그냥 이 메서드를 사용해 버릴 수 있다.

-> 변경이 필요하지 않는 필드는 setter 메서드를 만들면 안된다. 다른 개발자도 변경할 수 있는 메서드가 없는 것을 보고 "아 이 필드는 막 변경해서는 안되는 필드구나."라고 생각할 것이다.

3. 유지보수 하기가 어렵다.

예를 들어 다음과 같이 @Setter를 사용한 회원 엔티티 클래스가 있다고 가정해 보자.

@Getter @Setter
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;

    private String password;

}

이제 회원 로직은 다 개발된 상태에서 이메일 필드를 추가하고자 한다.

그럼 회원가입, 회원 정보 수정 등 여러 곳에서 유지보수 작업을 해야 한다.
프로젝트가 매우 클 경우 해야 될 작업이 너무 많아 개발자가 어디를 수정해야 하는 지조차 찾기 힘들며 일일이 수정하기 너무 번거롭다.

-> 생성자나 빌더 패턴을 사용하자.

  • 엔티티 자체에서 유지보수를 진행할 수 있어 바로 오류 위치가 뜨므로 유지보수가 굉장히 편리해 진다.

📌 생성자 방식 적용


다음과 같은 의문이 들 수 있다.

그럼 setter 메서드를 사용하지 않으면 DB에는 어떻게 반영하는거지?

  • 생성자를 통해 값을 넣고 DB에 반영하면 된다.

다음 예제를 보자.

@Getter
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;

    private String password;
    
    @Column(unique = true)
    private String email
    
    public Member(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

}
  • @Setter 를 사용하지 않고 생성자 를 사용하였으며, email 필드를 추가하였다.
Member member = new Member("user", "abc123");

memberRepository.save(member);

이제 위와 같은 기존 로직에서 바로 오류 표시가 뜰 것이다. 그럼 다음과 같이 email을 추가해 주면 된다.

Member member = new Member("user", "abc123", "abc@abc.com");

memberRepository.save(member);

setter 메서드를 사용했다면 오류 위치가 바로 뜨지 않아 찾기 번거로웠을 것이며, 필드마다 setter를 사용해야 하므로 코드가 더 길었을 것이다.

하지만 생성자를 사용한 방식에도 문제점이 존재한다.

문제점

  1. 가독성이 떨어진다.

파라미터 위치가 정확해야 하는데 이게 어떤 필드랑 매칭이 되는지 직접 엔티티 클래스에 들어가서 확인해보아야 하고.. 굉장히 번거롭다.

  1. 파라미터 위치를 실수하면 발견하기 어렵다.
Member member = new Member("abc123", "user", "abc@abc.com");

memberRepository.save(member);

위와 같이 usernamepassword 위치를 반대로 적었다고 가정해 보자. 그럼 실행하기 전까지 문제를 발견할 수 없다.

현재는 파라미터가 적기 때문에 별 문제 없을 거라 생각할 수 있지만 파라미터가 굉장히 많다면 실수하기도 쉽고 가독성도 매우 안좋을 것이다.

-> 빌더 패턴을 사용하면 이러한 문제를 해결할 수 있다.

📌 빌더 패턴 적용

@Getter
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;

    private String password;
    
    @Column(unique = true)
    private String email
    
    @Builder
    public Member(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

}
  • @Builder 를 적용하였다.
Member member = Member.builder()
    .username("user")
    .password("abc123")
    .email("abc@abc.com")
    .build();
  • 이렇게 빌더 패턴을 적용하면 어떠한 필드에 어떤 값을 넣는 지 정확하게 명시하기 때문에 가독성도 챙기고 생성자와 같이 파라미터 위치를 실수할 일도 없다.
profile
개발 공부

0개의 댓글