인프런 커뮤니티 질문&답변

jieun ha님의 프로필 이미지
jieun ha

작성한 질문수

실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)

companion object사용에 관하여 + entity class의 올바른 메서드 사용

작성

·

493

1

안녕하세요. 우선 양질의 kotlin과 jpa관련 강의제공해주셔서 감사합니다.

덕분에 어느정도 갈피를 잡을 수있었어요.

어설픈 질문이지 않을까 걱정도 되지만, 조심스레 여쭤봅니다.

[21강에 사용되는 companion object 의 fun fixture]

해당 메소드는 객체가 생성될때 기본값을 가지도록 되어있는데 해당방식은 실제 프러덕션코드 에서도 적용할 수 있는 방식일까요?

만약 그렇다면 다음과같이 직접적으로 field의 초기값을 설정하는것과 어떻게다른지 궁금합니다.

@Entity
class Book(
  val name: String = "",

  @Enumerated(EnumType.STRING)
  val type: BookType = BookType.COMPUTER,

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Long? = null,
) {

  init {
    if (name.isBlank()) {
      throw IllegalArgumentException("이름은 비어 있을 수 없습니다")
    }
 }

  fun generateIntegrateName(): String {
    return type.toString() + name
  }

  companion object {
    fun fixture(
      name: String = "책 이름",
      type: BookType = BookType.COMPUTER,
      id: Long? = null,
    ): Book {
      return Book(
        name = name,
        type = type,
        id = id,
      )
    }
  }
}

만약 test를 위해서만 존재하는 코드라면, entity class안에 test만을 위한코드가 존재하는게 자연스러운 구조인가요?

[entity와 관련된 값 구성 강제하기]

entity filed에는 정의되지 않아 Database에 column으로존재하진않지만, dto로 반환하는 integrateName의 생성을 강제하고 싶을때는 위코드의 fun generateIntegrateName 을 entity에 구성하여 dto에서 사용되는것이 올바른 방법인지 궁금합니다.

data class BookInfoResponse(
    val integrateName: String,
) {
    companion object {
        fun of(entity: Book): BookInfoResponse {
            return BookInfoResponse(
                integrateName = entity.generateIntegrateName()
            )
        }
    }
}
val book = bookRepository.findByName("이상한 나라의 엘리스")
    ?: throw IllegalArgumentException("잘못된 요청값입니다.")
val result = BookInfoResponse.of(entity = book).integrateName

강의내용과 검색등의내용을 짜집기해서 사용해보고있는데 막상 구현을하고 보니 적절한 방법인지 알길이 없어서 고민하다 질문드립니다.

시간 내어주셔서 감사드립니다.

답변 1

1

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요, jieun ha님! 좋은 질문 주셔서 감사드립니다. 😊 하나씩 답변 드려 보겠습니다.

 

[fun fixture 관련]

  • 해당 메소드는 객체가 생성될때 기본값을 가지도록 되어있는데 해당방식은 실제 프러덕션코드 에서도 적용할 수 있는 방식일까요?

네 맞습니다, fixture 함수는 객체가 생성될 때 기본값을 갖도록 되어 있습니다. (default parameter라고 불리죠!) 말씀해주신 "프로덕션 코드"가 테스트 코드 / 프로덕션 코드를 구분할 때 쓰는 의미인지, 아니면 프로덕션 레벨의 코드라는 의미의 "프로덕션 코드"인지 정확하지는 않지만, 어떤 경우건 이런 방식은 꽤 자주 사용되는 방식입니다.

실제 자바에서 메소드 오버로드 기능이 있는 것도, 특정 함수를 부를 때 (= 혹은 특정 객체를 만들 때) 특정 파라미터에 대한 기본값을 설정하기 위함 중 하나입니다.

 

  • 만약 그렇다면 다음과 같이 직접적으로 field의 초기값을 설정하는것과 어떻게다른지 궁금합니다.

이 부분은 말씀해주신 "다음"이 정확히 어떤 부분인지 한 번더 알려주시면 답변드릴 수 있을 것 같습니다 😭 비교 대상의 두 코드를 알려주시면 바로 답변드릴 수 있도록 하겠습니다!

 

  • 만약 test를 위해서만 존재하는 코드라면, entity class안에 test만을 위한코드가 존재하는게 자연스러운 구조인가요?

아~~ 좋은 질문이신데요! 이 부분은 살짝 애매합니다! 개발자 분에 따라서는 entity class 안에 테스트용 코드를 두는 것을 싫어하시는 분도 계시고, 크게 상관하지 않는 분도 계십니다. 결국 테스트를 위해 객체 생성을 해야 하는데, 객체 생성 함수를 어디에 둘 것인가에 관한 문제이죠. 저는 개인적으로 크게 상관하지는 않고 어떤 방식이건 통일된 방식이 적용되어 있으면 좋다~ 라고 생각하는 편입니다.

 

[entity와 관련된 값 구성 강제하기]

와우!! 잘 하셨습니다~ 😊

fun generateIntegrateName(): String {
  return type.toString() + name
}

물론 이 함수가 DTO에 있어야 할지 / Entity에 있어야 할지는 목적이나 상황에 따라 달라질 수 있지만, 해당 함수가 여러 DTO에서 재활용되거나, 비즈니스적인 의미가 있다면 충분히 Entity에 들어가도 괜찮습니다.

 

추가로, Kotlin에서는 위와 같은 경우 함수 대신 프로퍼티를 사용할 수도 있습니다.

val integrateName: String
  get() = type.toString() + name

 

또한, (Java이건, Kotlin이건) Enum을 사용하실 때는 name 이라는 프로퍼티를 더 적극적으로 사용하셔도 좋습니다. 😊

val integrateName: String
  get() = type.name + name

 

답변이 도움이 되었으면 좋겠습니다. 감사합니다!! 🙇

jieun ha님의 프로필 이미지
jieun ha

작성한 질문수

질문하기