3. [6] 코드 다듬기: 로컬 함수와 확장

  • DRY 원칙(Don't Repeat Yourself)을 피하기는 쉽지 않다.
  • 메서드 추출 리팩토링을 통해서 긴 메서드를 부분부분 나눠서 재활용 하는 것은 가능하다.
  • 해당 해결방법의 경우 더 복잡해지기에, 메서드를 별도의 내부 클래스에 넣게 된다면 불필요한 준비코드가 늘어난다.
  • Kotlin에서는 추출한 함수를 원 함수에 중첩시킬 수 있다.
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
  if(user.name.isEmpty()) {
    throw IllegalArgumentException(
      "Can't save user ${user.id}: Empty Name"
    )
  }

  if(user.address.isEmpty()) {
    throw IllegalArgumentException(
      "Can't save user ${user.id}: Empty Address"   // 필드 검증이 중복된다.
    )
  }

  // user를 데이터베이스에 저장하는 부분
}
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
  fun validate(user: User, value: String, fieldName: String) {
    if(value.isEmpty()) {
      throw IllegalArgumentException(
        "Can't save user ${user.id}: empty ${fieldName}"
      )
    }
  }

  validate(user, user.name, "Name")
  validate(user, user.address, "Address")     // 로컬 함수를 호출해서 각 필드를 검증한다.
}
  • 검증 코드를 로컬 함수로 분리하였다. 그 결과, 중복을 없애고 코드 구조를 깔끔하게 유지한다.
  • 중복된 로직은 사라졌고, 필요하면 User의 다른 필드에 대한 검증을 추가하는 것도 간단하다.
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
  fun validate(value: String, fieldName: String) {
    if(value.isEmpty()) {
      throw IllegalArgumentException(
        "Can't save user ${user.id}: " + "empty ${fieldName}"
      )
    }
  }
}
  • 이제 saveUser의 user 파라미터를 중복으로 사용하지 않고, 바깥 함수의 파라미터에 직접 접근한다.
class User(val id: Int, val name: String, val address: String)

fun User.validateBeforeSave()(user: User) {
  fun validate(value: String, fieldName: String) {
    if(value.isEmpty()) {
      throw IllegalArgumentException(
        "Can't save user ${user.id}: empty ${fieldName}"
      )
    }
  }

  validate(name, "Name")
  validate(address, "Address")
}

fun saveUser(user: User) {
  user.validateBeforeSave() // user를 DB에 저장
}
  • 검증 로직을 User 클래스를 확장한 함수로 만드는 것도 가능하다.
  • User는 내가 만든 코드 기반에 존재하는 클래스이지만, 해당 경우 검증 로직은 User 이외에서는 쓰이지 않는다.
  • User를 간결하게 유지하면 생각해야 할 내용이 줄어들어서 더 쉽게 코드를 파악할 수 있다.
  • 확장함수를 로컬함수로 지정할 수 있지만, 깊이가 깊어지면 코드를 읽기 어려워지기 때문에, 일반적으로 한 단계만 함수를 중첩시킨다. [User.validateBeforeSave를 saveUser 내부에]

'Kotlin in Action' 카테고리의 다른 글

5. [2] Collection 함수형 API  (0) 2024.02.25
5. [1] 람다 식과 멤버 참조  (0) 2024.02.25
3. [5] 문자열과 정규식 다루기  (0) 2024.02.22
3. [4] Collection 처리  (0) 2024.02.22
3. [3] 확장 함수와 확장 프로퍼티  (0) 2024.02.22