백엔드/ORM

[TypeORM] 왜 엔티티 클래스 프로퍼티를 private으로 할 수 없을까?

eess 2024. 9. 9. 16:00

문제 상황

 

  • TypeORM 사용 중 Entity 클래스의 프로퍼티를 private으로 변경했더니 이런 에러가 발생했습니다.
    "Property "id" was not found in "Expense". Make sure your query is correct."
  • 처음에는 프로퍼티 이름 앞에 언더스코어를 붙여서 매핑이 안 되는 건가 했는데, 프로퍼티를 public으로 해야만 데이터베이스와 객체가 자동으로 매핑되는 것이었습니다.
  • JPA를 사용할 때는 엔티티의 모든 멤버 변수를 private으로 선언하고 getter & setter를 두어 캡슐화를 하여, 엔티티에 비즈니스 로직을 담은 public 메서드를 두어 서비스에서 호출하는 것이 도메인 주도 설계의 정석(?)이라고 알고 있습니다... TypeORM에서도 이와 비슷하게 해보고 싶었으나 엔티티 클래스의 private 프로퍼티를 지원하지 않는 것으로 보였습니다.

 

왜 TypeORM에서는 엔티티의 private 프로퍼티를 허용하지 않을까?

왜인지 궁금해져서 구글링 해보았는데, TypeORM GitHub issue에서 이와 관련한 TypeORM 개발자의 생각을 엿볼 수 있었습니다.

해당 이슈는 "Support for private entity attributes"라는 제목으로 엔티티의 private 프로퍼티를 지원하는 것에 대한 제안이었습니다.

 

이슈를 작성한 분의 생각은 다음과 같습니다.

  • 도메인 주도 설계에서는 Getter/Setter를 사용하는 대신, 비즈니스 로직을 처리하는 메서드를 가지는 것을 권장한다.
  • 지금도 비즈니스 로직을 처리하는 메서드를 만들 수 있지만, 프로퍼티가 public이면 실수로 엔티티의 상태를 직접 수정하는 문제가 발생할 수 있다. 그러나 엔티티 프로퍼티를 private으로 선언하면 repository에서 해당 프로퍼티를 선택할 수가 없다.
  • 따라서 엔티티 프로퍼티를 private으로 유지하면서도 repository에서 접근해 쿼리를 날릴 수 있는 방법을 제안한다.

 

이에 대한 답변은 아래와 같습니다.

  • 엔티티의 속성을 private으로 만드는 방법이 유일한 캡슐화 방식은 아니다.
  • 비즈니스 로직이나 속성 접근 제어가 필요한 경우에는 그 목적에 맞는 별도의 모델을 만들어 사용하는 것이 더 좋은 방법일 수 있다.
  • 엔티티는 데이터베이스 스키마 정의용으로만 사용하는 것이 좋다.
  • 캡슐화가 부족하다는 주장에는 동의하지 않으며, 도메인 주도 개발을 따르는 대규모 시스템에서 TypeORM을 사용하고 있는데 캡슐화에 문제가 없었다. 
  • 캡슐화를 추구할수록 오버엔지니어링이 될 수 있다. 시스템에 정말 그 정도의 캡슐화가 필요한지 다시 한 번 생각해보라.

 

나의 생각

TypeORM 개발자의 코멘트를 보았을 때 핵심 내용은 아래와 같다고 생각했습니다.

  1. 캡슐화 수준을 사용자에게 맡긴다.
  2. 엔티티는 스키마 정의용으로만 사용한다.

클린 코드 6장의 내용을 조금 참고해보자면 '자료 구조'와 '객체'는 다르다고 이야기 합니다.

클린 코드에서 이야기하는 자료 구조는 공개 변수만 있고 함수가 없는 클래스, 객체는 비공개 변수를 조작할 수 있는 함수만 공개합니다.

이 둘이 혼합된 구조의 한 가지 사례로 ORM에서 주로 사용되는 Active Record 패턴이 있는데, 엔티티가 데이터 관리와 비즈니스 로직 처리의 두 가지 역할을 동시에 수행하여 단일 책임 원칙을 따르지 않게 되는 문제가 있습니다. 

 

TypeORM 개발자가 도메인 모델을 따로 만드는 방법을 추천한 점과 엔티티는 스키마 정의용으로만 사용하라는 이야기를 한 것으로 보아, 두 가지 용도를 하나의 객체에서 처리하는 것에 대해 동의하지 않는 것으로 보였습니다. 

 

개인적으로는... 캡슐화를 할수록 오버 엔지니어링이 될 수 있다는 말에는 동의합니다. TypeORM을 사용할 때는 엔티티 클래스의 프로퍼티가 public인 만큼 어디까지, 어떻게 엔티티를 캡슐화할 것인지 많은 고민이 필요할 것 같습니다.

 

 

참고 

https://cupeanimus.tistory.com/87

https://www.reddit.com/r/Nestjs_framework/comments/ih9hfd/nestjs_typeorm_how_to_enforce_encapsulation/

https://github.com/typeorm/typeorm/issues/3548

https://jojoldu.tistory.com/251