코틀린으로 스프링부트를 사용하는 방법을 공부하다가 Setter에 대해 의문이 들었다.
@Entity
@NoArgsConstructor
class Post(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long,
@Column(nullable = false)
var title: String,
@Column(nullable = false)
var content: String
) {
fun update(title: String, content: String){
this.title = title
this.content = content
}
}
위와 같은 코드로 Post라는 Entity를 설정했다고 가정해보자.
코틀린에서 프로퍼티로 컬럼 3개를 설정했기 때문에 val id는 getter, var title, var content는 자동으로 getter와 setter가 생기게 된다.
Java였다면 하나하나 게터 세터 메서드를 만들어야 했거나, Lombok의 @Getter, @Setter 어노테이션으로 달아야 했다.
아니면 update같은 메서드를 따로 만들어 객체의 상태를 변경시키는 방법으로 Setter를 만들지 않고 상태를 변경했었다.
Getter는 단순히 접근만 가능하기에 큰 문제는 없을 수 있으나, Setter의 경우 캡슐화를 넘어서 객체의 상태까지 바꿀 수 있기 때문에 존재 자체가 추후 문제가 될 수 있다.
위의 Kotlin 코드에서도 update 메서드를 통해 var 컬럼인 title과 content를 수정할 수 있게 되었지만 Setter가 계속 열려있는 문제가 남아있다.
사용하지 않는 Setter가 계속 열려있는 문제를 해결할 수 없을까?
@Entity
@NoArgsConstructor
class Post(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long,
@Column(nullable = false)
private var title: String,
@Column(nullable = false)
private var content: String
) {
fun update(title: String, content: String){
this.title = title
this.content = content
}
}
Setter가 열린 var 프로퍼티를 private으로 선언해 외부에서 필드로 접근하는 것을 막아버린다.
하지만 이 방법은 Getter까지 막아버리므로 Getter는 살리고 Setter만 막는 방법은 아니다.
@Entity
@NoArgsConstructor
@Table(name = "POST")
class JpaPost(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column(nullable = false)
val title: String,
@Column(nullable = false)
val content: String
)
class Post(
val id: Long,
title: String,
content: String
) {
var title: String = title
private set
var content: String = content
private set
fun update(title: String, content: String){
this.title = title
this.content = content
}
}
도메인 레이어를 JPA와 연관관계를 끊은 구조이다.
이렇게 코드를 짜면 JPA의 Entity는 Setter가 여전히 남아있지만 애초에 코드상에서는 아래의 도메인 레이어로 접근하기 때문에 Setter를 차단할 이유 자체가 없어진다.
그리고 도메인 레이어상에서는 private set으로 선언되어있기 때문에 setter가 숨겨져있게되어 원하는 바를 만족하게 된다.
하지만 레이어를 나눈거 자체로 코드가 길고 유지보수가 힘들어지며, 양쪽 레이어를 매핑해야하는 수고로움이 들기 때문에 추천되는 방법은 아니다.
이 외에도 필드를 ()가 아니라 자바처럼 {}블록에 선언한 뒤 private set을 다는 방법도 생각해보았으나 이 방법은 Private setters are not allowed for open properties
가 뜨며 컴파일 조차 되지 않는다.
결론적으로 단순히 Setter를 막기 위해 위의 수고로움을 감당하는 것은 비효율적이라 생각한다. 코틀린 자체가 원하는 방향으로 가지 않으면 오히려 자바보다 더욱 코드가 길어지고 불편해지는 것을 느꼈다.
추후 더 좋은 방법을 찾거나 알아내면 이 포스트에 보충해서 작성을 할 것이다.