240229 TIL #334 Kotlin에서 Setter 공개 문제

김춘복·2024년 2월 29일
0

TIL : Today I Learned

목록 보기
334/571

Today I Learned

코틀린으로 스프링부트를 사용하는 방법을 공부하다가 Setter에 대해 의문이 들었다.


코틀린 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가 계속 열려있는 문제를 해결할 수 없을까?


해결책 고민

1. private 프로퍼티

@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만 막는 방법은 아니다.


참고 사이트: multifrontgarden

2. 프레임워크에 의존하지 않는 domain layer

@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를 막기 위해 위의 수고로움을 감당하는 것은 비효율적이라 생각한다. 코틀린 자체가 원하는 방향으로 가지 않으면 오히려 자바보다 더욱 코드가 길어지고 불편해지는 것을 느꼈다.

  • 추후 더 좋은 방법을 찾거나 알아내면 이 포스트에 보충해서 작성을 할 것이다.

profile
Backend Dev / Data Engineer

0개의 댓글