Entity에 setter 사용을 지양하라

diense_kk·2023년 6월 26일
0

SpringBoot

목록 보기
1/10

처음에는 entity에 getter와 setter를 모두 생성하여 사용했었다.
그런데 많은 개발자분들이 setter를 작성하는 것은 바람직하지 못하다고 한다.

Entity를 작성할 때 setter를 작성하면 어째서 좋지 못한 것인지, 왜 setter 를 지양해야 하는지, 그럼 setter를 사용하면 안되는 것인지 알아보자.

왜 setter를 지양해야 할까?

1. 사용한 의도를 쉽게 파악하기 어렵다.

Post post = new Post();
post.setId(1L);
post.setUserId("member1");
post.setTitle("제목입니다.");

위 코드의 경우 게시글 정보 Entity인 post를 set 메서드를 통해 값을 변경하는데 게시글의 값을 생성하는 것인지, 변경하는 것인지 정확한 의도를 파악하기 어렵다.

더군다나 객체의 내부 값이 복잡할 경우 더더욱 한눈에 알아보기 힘들 것이다.

2. 일관성을 유지하기 어렵다.

public Post updatePost(Long id) {
    Post post = findById(id);
    post.setTitle("제목을 수정합니다.");
    post.setCont("내용을 수정합니다,");
    return post;
}

위 코드의 경우 게시글을 변경하는 메소드인데, public으로 작성된 setter 메소드를 통해 어디서든 접근이 가능하기에 의도치 않게 post의 값을 변경하는 경우가 발생할 수 있다.

그렇다면 결국 post 객체의 일관성은 무너지게 되는 것이다.

그렇다면 setter 없이 어떻게 데이터를 수정 할 수 있는가?

setter의 경우 JPA의 Transaction 안에서 Entity 의 변경사항을 감지하여 Update 쿼리를 생성한다. 즉 setter 메소드는 update 기능을 수행한다.

여러 곳에서 Entity를 생성하여 setter를 통해 update를 수행한다면 복잡한 시스템일 경우 해당 update 쿼리의 출처를 파악하는 비용은 어마어마할 것이다.

그렇다면 어떻게 setter를 배제할까? 아니 setter를 어떤 방식으로 대체하는지 알아보자.

1. 사용한 의도나 의미를 알 수 있는 메서드를 작성하자.

@Getter
@Entity
public class Post {
	
    private Long id;
    private String userId;
    private String title;
    private String cont;
    
    public void updatePost(Long id, String title, String cont) {
        this.id = id;
        this.title = title;
        this.cont = cont;
    }
}
post.updatePost(1L, "수정할 제목입니다.", "수정할 내용입니다.");

위와 같이 하면 setter 메소드를 작성하는 것보다 행위의 의도를 한눈에 알기 쉽다.

따라서 setter를 public으로 열어두는 것보다는 별도의 메서드를 통해 update 처리를 객체지향스럽게 쓰는 게 좋다.

2. 생성자를 통해 값을 넣어 일관성을 유지하도록 하자. (feat. @Builder)

@Getter
@Entity
public class Post {

    private Long id;
    private String userId;
    private String title;
    private String cont;

    @Builder
    public Post(Long id, String userId, String title, String cont) {
        this.id = id;
        this.userId = userId;
        this.title = title;
        this.cont = cont;
    }
    
    // ... 이하 생략
}
Post post = Post.builder()
		.id(1L)
        .userId("member1")
        .title("제목입니다.")
        .cont("내용입니다.")
        .build();

setter를 배제하기 위해 여러 생성자를 작성할 수도 있는데, 위와 같이 lombok의 @Builder 애노테이션을 통해 많은 생성자를 사용할 필요 없이 setter의 사용을 줄일 수 있다.
또한 빌더 패턴을 통해 post 객체의 값을 세팅할 수 있다.

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Post {

    private Long id;
    private String userId;
    private String title;
    private String cont;

    protected Post(Long id, String userId, String title, String cont) {
        this.id = id;
        this.userId = userId;
        this.title = title;
        this.cont = cont;
    }
}

그리고 위와 같이 생성자의 접근제어자를 protected로 선언하면 new Post() 작성이 불가하기 때문에 객체 자체의 일관성 유지력을 높일 수 있다.

그리고 lombok에서 제공하는 @NoArgsConstructor 애노테이션을 사용하여 더 편하게 작성할 수 있다.

사실 Entity를 작성할 때 무조건적으로 setter를 배제하는 강박관념을 가질 필요는 없다.
그냥 경우에 따라 setter가 필요하면 사용하면 된다.

단순히 하나의 필드만 변경할 경우 setter도 사용할 수 있고, 별도의 의미를 가진 비즈니스 메소드를 작성할 수도 있는 것이다.

핵심 내용은 setter를 외부에 노출하는 것을 줄이는 것이다.
만약 setter를 사용할 경우 public setter를 통해 외부에서 아무 제약없이 사용할 수 있으니 이것을 사용하는 개발자들은 해당 setter 호출여부에 대해서 고민이 되기 때문이다.

요약 -> lombok 좋네, 자바 공부 열심히

0개의 댓글