Refactoring/Moonkey

[졸업작품] spring boot로 작업한 뭉키를 다시 돌아보며 (4) - Entity의 무분별한 Setter 사용의 문제점

수짱수짱 2023. 3. 22. 19:59

3. Entity에서 Setter를 사용하게 되면 객체의 일관성을 보장하기 어려움


(1) 데이터 무결성, 일관성 저해

 

Entity 클래스는 데이터를 나타내는 클래스로 사용된다. 이 클래스에는 데이터베이스 테이블 열과 대응되는 필드들이 포함된다.

이러한 필드들은 private로 선언되어 외부에서 직접적으로 접근이 불가능하도록 하였으나 public으로 선언된 getter와 setter 메서드를 통해 이 필드에 접근할 수 있게 한다.

 

그러나, setter를 무분별하게 사용하게 된다면 데이터의 무결성이 깨질 수 있다.

예를 들어, Entity의 필드 중 하나가 null일 수 있다면 setter를 이용해 해당 필드에 null 값을 할당하면 데이터 무결성이 깨진다. (데이터 무결성 중 개체 무결성)

 

Entity 필드가 null일 수 있을 때 setter를 통해 null값을 설정하면 데이터 무결성이 깨질 수 있는 이유?

 

Q. Entity 필드가 null일 수 있을때 setter를 통해 null을 넣으면 데이터 무결성이 깨지는 이유가 뭐야?

 

 

 

또한, setter를 이용하여 Entity의 필드를 무작위로 변경하면 데이터베이스의 일관성이 깨질 수 있다.

Setter를 무분별하게 남용하면 Entity의 값을 변경할 수 있으므로 객체의 일관성을 보장할 수 없다.

객체의 일관성을 유지하기 위해 객체 생성 시점에 값을 넣어줌으로 Setter 사용을 줄일 수 있다.

// 1. 빌더패턴 사용
Member meber = Member.Builder()
	.username("name")
 	.tel("01012345678")
	.build();
    
// 2. 객체 생성자 설정
@Bean
public Member(String username, String tel){
	this.username = username;
	this.tel = tel;
}

 

또는 기본 생성자 접근자를 protected로 변경하면 new Member() 사용을 막을 수 있어 객체의 일관성을 더 유지할 수 있다.

protected로 설정하는 이유는 JPA 기본 스펙 상 기본 생성자가 필요한데 protected로 제어하는 것 까지 허용되기 때문이다.

@Entity
@Getter
public class Member{
	...
    protected Member(){}; // 기본 생성자 protected로 접근 제어
}

 

혹은 롬복을 사용하여 @NoArgsconstructor 어노테이션(파라미터가 없는 기본 생성자 생성) 설정을 통해 간단하게 설정할 수 있다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member{
	...
    protected Member(){}; // 기본 생성자 protected로 접근 제어
}

 

 

(2) Setter는 의도를 알기 힘들다

 

Setter 메소드를 통해 필드의 값을 변경하는데 이는 무엇을 하는 메소드인지 한번에 알 수 없다.

Member member = new Member();
member.setName("이름2");
member.setTel("01012345678");
...
member.set...

위 예제와 같이 간단한 변경의 경우는 알아볼 수 있지만

복잡해진다면 객체의 값을 변경하는 행위가 무엇을 위해 변경하는지 한 눈에 알 수 없다.

 

 

따라서, 아래 코드처럼 객체에서 메소드를 제공하여 변경하면 변경 의도를 한 번에 알 수 있고

객체 자신의 값을 변경하는 것이 객체 지향 관점에도 더 올바르다.

member.changeBasicInfo("이름2", "01012345678"); 
// 멤버의 기본정보를 수정한다는 것을 한 눈에 알 수 있는 메소드 이름
// Member Entity 내부 메소드
public void changeBasicInfo(String name, String tel){
	this.name = name;
    this.tel = tel;
}

 

(3) 결론

 

따라서 Java Spring에서는 Enity 클래스에 대해 필요한 경우에만 Setter를 사용하도록 권장한다.

만약 Entity 클래스의 상태를 변경해야 하는 경우는 해당 필드를 초기화하는 생성자를 이용하거나, 다른 메소드를 이용하여 변경하는 것이 안전하다.

 

무분별한 Setter 사용금지는 Entity뿐만 아니라 객체 생성 & 변경시 모두 해당하는 부분이다,

객체의 일관성을 유지할 수 있어야 프로그램의 유지 보수성을 끌어 올릴 수 있기 때문에 일급 컬렉션 상용 등 많은 개발자들이 객체의 일관성을 유지하기 위해 노력을 기울이고 있다.


Reference

- chat gpt

- https://velog.io/@aidenshin/%EB%82%B4%EA%B0%80-%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94-JPA-%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%9E%91%EC%84%B1-%EC%9B%90%EC%B9%99

- https://velog.io/@alicesykim95/DB-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AC%B4%EA%B2%B0%EC%84%B1