이번 글에서는 프로젝트를 진행하다 보면 자주 마주하게 되는 질문, “도메인과 엔티티를 꼭 분리해야 할까?”에 대해 이야기해보며 정리해보려고 해요. 특히 협업과 유지보수 측면에서 이 분리가 왜 중요한지, 어떤 장점이 있는지를 함께 살펴보겠습니다! ✨
@Entity
어노테이션과 함께 사용되는 객체예요.엔티티와 도메인을 분리하면 데이터베이스의 변화가 도메인 로직에 영향을 주지 않아, 시스템이 더 안정적으로 관리될 수 있어요. 이는 UI 변화로부터 엔티티를 보호하기 위해 DTO를 사용하는 것과 유사한 맥락이에요.
도메인과 엔티티를 분리할 때 명확한 기준은 바로 PK(기본키)의 유무예요. 데이터베이스와 관련된 PK를 가진 객체는 엔티티로, PK와 관계없이 비즈니스 로직을 수행하는 객체는 도메인으로 분리할 수 있어요.
@Embeddable
public class ProductName {
private final String value;
protected ProductName() {
this.value = null;
}
private ProductName(String value) {
validate(value);
this.value = value;
}
public static ProductName of(String value) {
return new ProductName(value);
}
public String value() {
return value;
}
private void validate(String value) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException("상품명은 비어있을 수 없습니다.");
}
}
}
public class Product {
private final ProductName name;
private final Price price;
public Product(ProductName name, Price price) {
this.name = name;
this.price = price;
}
public long calculatePrice(int quantity) {
return price.value() * quantity;
}
}
@Entity
public class ProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private ProductName name;
private long price;
protected ProductEntity() {}
public ProductEntity(ProductName name, long price) {
this.name = name;
this.price = price;
}
public Product toDomain() {
return new Product(name, new Price(price));
}
}
회원이 상품을 주문하는 간단한 시나리오를 예로 들어볼게요. 이 상황에서 도메인과 엔티티가 어떻게 역할을 나누는지 살펴보겠습니다.
👉 도메인은 비즈니스 규칙과 판단 기준을 내리는 역할에 집중하며, 데이터가 어디서 왔는지는 신경 쓰지 않아요.
👉 엔티티는 데이터의 저장과 변경, 즉 영속성과 관련된 책임만 가지고 있어요.
@Transactional
public void completeOrder(Long memberId, Long productId, int quantity) {
MemberEntity member = memberRepository.findById(memberId);
ProductEntity product = productRepository.findById(productId);
Product domainProduct = product.toDomain();
long totalPrice = domainProduct.calculatePrice(quantity, LocalDate.now());
member.deductBalance(totalPrice);
product.reduceStock(quantity);
}
단점이 있지만, 장기적으로 보면 유지보수성이 뛰어나 프로젝트 규모가 커질수록 더 많은 이점이 있어요.
도메인과 엔티티의 분리는 처음엔 낯설고, 구현해야 할 코드도 많아 보여 부담스럽게 느껴질 수 있어요.
하지만 프로젝트의 규모가 커지고 복잡한 요구사항이 늘어날수록, 각 객체가 자신의 책임에 집중하도록 설계하는 것의 중요성은 점점 더 커집니다.
이번 글에서는 그런 구조를 만들어가기 위한 하나의 방향으로 도메인과 엔티티를 분리하는 이유와 방법을 살펴보았고, 실제 예시를 통해 어떻게 적용할 수 있을지도 함께 고민해봤습니다.
이러한 설계는 단순히 “기술적으로 멋있어 보이기 위해서”가 아니라,
협업이 쉬운 구조,
테스트가 가능한 로직 분리,
유지보수가 용이한 아키텍처를 만들기 위한 노력의 일환이에요.
작은 프로젝트에서도 한 번쯤 적용해보면
“아, 이래서 분리를 하는구나” 하고 체감하게 되는 순간이 분명히 올 거예요.
읽어주셔서 감사합니다! 🙏