본문 바로가기

Design

DDD의 Entity와 JPA의 Entity는 같은 걸까?

DDD와 JPA에는 엔티티(Entity)라는 같은 이름이 나온다.

그 엔티티라는 이름이 동일하다 보니 그 역할과 개념이 섞이게 된다.

 

웹에서 검색해보면 아와 같이 설명하는 경우가 있는데 언듯보면 비슷하다.

  • DDD에서의 Entity: 비즈니스 도메인 관점에서 문제를 해결하기 위한 객체입니다. 엔티티의 정체성(identity)는 ID로 표현됩니다.
  • JPA에서의 Entity: javax.persistence 패키지의 @Entity라는 애너테이션이 붙어있다. Persistence, 즉 데이터베이스와 매핑이 되는 객체이다. 식별이 가능한 키, 즉 @Id 필드가 필요하다.

실전에서는?

ID라는 비슷한 개념을 가지고 있기에 JPA의 엔티티가 비즈니스 로직에 침범하는 것을 자주 봤다.

심지어 Repository를 넘어, Service 심지어 Controller까지 JPA의 엔티티가 와서 사용되는 경우를 보았다.

나는 그 JPA 엔티티를 Repository와 맞닿아 있는 Service까지로 하기로 타협을 하고 경계(boundary)를 그었다.

그 경계를 넘어서는 JPA의 엔티티가 아닌 일반 POJO 객체가 움직였다. POJO를 세부적으로 나누어보면 구분할 수 있는 ID가 있었으므로 (DB의 PK랑은 같은 경우도 다른 경우도 있었다) VO보다는 DDD의 Entity였다.

클린 아키텍처 가라사대...

로버트 C. 마틴의 클린 아키텍처를 본 사람이라면 이런 혼동의 개념이 적으리라 생각한다.

또한 책에서 DDD와 JPA의 엔티티가 다르다는 식으로 직접적으로 언급이 되지는 않았다.

하지만, 30장에서 The Database Is a Detail(데이터베이스는 세부사항이다)에서는 아래와 같은 문장이 나온다.

From an architectural point of view, the database is a non-entity—it is a detail that does not rise to the level of an architectural element. Its relationship to the architecture of a software system is rather like the relationship of a doorknob to the architecture of your home.
아키텍처 관점에서 볼 때 데이터베이스는 엔티티가 아니다. 즉, 데이터베이스는 세부사항이라서 아키텍처의 구성요소 수준으로 끌어올릴 수 없다. 소프트웨어 시스템의 아키텍처와 데이터베이스의 관계를 건물로 비교하면 건물의 아키텍처와 문 손잡이의 관계와 같다.

바로 데이터베이스가 (DDD의) 엔티티가 아니라고 분명히하고 있다. ORM 기술의 스펙인 JPA 역시 마찬가지로 세부사항이므로 마찬가지이다.

 

또한 34장의 시몬 브라운(Simon Brown)이 기고한 글에도 포트와 어댑터(Ports and Adapters, Hexagonal Architecture)에 대한 설명에서 OrdersRepository가 Orders라는 간단한 이름으로 바뀌는 과정이 나온다.

OrderServiceImpl 이 의존하는 대상이 바뀌었다.

이는 도메인 주도 설계(DDD)라는 세계관에서 비롯된 명명법으로, 도메인 주도 설계에서는 '내부'에 존재하는 모든 것의 이름은 반드시 '유비쿼터스 도메인 언어(ubiquitous domain language)'관점에서 기술하라고 조언한다. 바꿔 말하면, 도메인에 대해 논의할 때 우리는 '주문'에 대해 말하는 것이지, '주문 리포지터리'에 대해 말하는 것이 아니다.

클린 코드 가라사대...

6장 객체와 자료구조(Objects and Data Structures)에서 활성 레코드(Active Record) 라는 이름으로 짧게 나오는데 이것이 JPA의 Entity와 비슷하다고 생각한다. PHP진영의 Laravel 쪽의 Eloquent 의 Eloquent Model 도 유사하다.

Active Records are special forms of DTOs. They are data structures with public (or bean-accessed) variables; but they typically have navigational methods like save and find. Typically these Active Records are direct translations from database tables, or other data sources.

Unfortunately we often find that developers try to treat these data structures as though they were objects by putting business rule methods in them. This is awkward because it creates a hybrid between a data structure and an object.

The solution, of course, is to treat the Active Record as a data structure and to create separate objects that contain the business rules and that hide their internal data (which are probably just instances of the Active Record).

이 글을 쓰게 된 계기

두 가지 게시물이 이 글을 쓰게 되었다. 일종의 기록의 목적이다.

DDD Entity in ORM and Java 

stack overflow 에 DDD Entity in orm and java 라는 질문이 있었다.

질문 목록

  1. In above sample of hibernate OrderLine is Entity, but is OrderLine still a DDD entity ?
  2. And more generally, can we say that any jpa/Hibernate @Entity is DDD entity, or not ?
  3. It seems to me, that OrderLine is a good example of Jpa/Hibernate entity that is not a DDD entity, is it ?
  4. In terms of relational databases could we say, that Jpa @Entity that is mapped in database as OnDeleteCascade is not a DDD Entity, but it is still a value object ?
  5. Is hibernate @Embedded always a DDD value object ? (seems yes, it has no identity)
  6. Do we say that BillingCustomer is the same DDD Entity as MarketingCustomer (assuming both of them represent the same Customer John Doe born 01.01.1980 wiht ssn 12-34-56)? This would imply that in java two different classes, even not having common parent (except from Object) can represent the same DDD entity. If so, how should equals be implemented in above classes ?
  7. Should java equals return true for two different java classes representing the same DDD entity ?
  8. How would we implement below with java and hibernate :
    @Entity Person has @Embedded Address, Person class has getters and setters and Address only getters ? And to change address street we would do sth like person.setAddress (Address.builder(person.getAddress()).setStreet("newStreet").build()) ?

Robert Bräutigam의 답변

  1. No, a Hibernate Entity should never be a DDD Entity.
  2. Not, JPA/Hibernate Entity should never be a DDD Entity.
  3. Correct.
  4. No, JPA Entities/Value Objects have no direct relation to DDD Objects.
  5. No, no relation.
  6. No, objects' identity can refer to pure conceptual things. BillingCustomer and MarketingCustomer are conceptually different things, so they would never equal, even though the "real" human behind them is the same. In general "real" has a different meaning in software designs. We consider everything "real" that is part of the business (i.e. part of the Ubiquitous Language), even if some or even most of it is not "real" in the conventional sense.
  7. No, equals() should also conform to normal Java rules. Objects of different classes should never equal. It would be extremely confusing. Define another relation, for example matches(), or sameCustomer(), etc.
  8. Don't know what you mean.

엔티티(Entity)와 값 객체(Value Object)의 차이에 달린 질문

jaeyeolshin 님의 블로그 중 엔티티(Entity)와 값 객체(Value Object)의 차이 라는 글에 어떤 분이 유사한 질문을 남겼다.

만들면서 배우는 클린 아키텍처

  • 원제: Get your hands dirty on clean architecture

2023년 회사에서 스터디 진행중인 "만들면서 배우는 클린 아키텍처"의 2장에는 아래와 같은 그림이 나온다. (17쪽)

그림 2.2 도메인 인터페이스를 도입함으로써 의존성을 역전시킬 수 있고, 그에 따라 영속성 계층이 도메인 계층에 의존한다.

도메인에서 Entity와 JPA 같은 ORM-Managed Entity 가 명확하게 분리되어 있음을 알 수 있다.