❐ Description
도메인 주도 설계의 목표는 기술보다는 도메인에 대한 모델에 집중해 더 나은 소프트웨어를 만드는 것
"에릭 에반스 - 도메인 주도 설계" 6장의 Repository 내용 정리.
여기서 만든 예제는 스스로 이해를 돕기 위해 만든 간단한 예제.
- 저장된 객체를 가져오는 것은 실제로는 생성의 한 부분집합
- Entity의 생명주기 가운데 중간 단계에 불과
❐ 필요한 데이터를 직접 획득해서 조작하면 안된다.
우선 여기서 가장 중요하게 설명하는 것은 아래와 같다.
클라이언트 코드에서 직접적으로 데이터베이스를 사용해서 Aggregate나 캡슐화와 같은
특징을 활용하는 것을 우회하려고 하고, 그 대신 필요한 데이터를 직접 획득해서 조작하면 안된다.
아래와 같이 하지말라는 것이다.
// 클라이언트 코드
public void updateOrderStatus(Long orderId, String status) {
// 🔥 데이터베이스 직접 접근
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(
"UPDATE orders SET status = ? WHERE id = ?");
statement.setString(1, status);
statement.setLong(2, orderId);
statement.executeUpdate();
// 🔥 도메인 규칙을 무시하고 상태를 직접 변경
if (status.equals("CANCELED")) {
PreparedStatement refundStatement = connection.prepareStatement(
"UPDATE payments SET status = 'REFUND' WHERE order_id = ?");
refundStatement.setLong(1, orderId);
refundStatement.executeUpdate();
}
}
- 도메인 규칙이 캡슐화되지 않고 클라이언트 코드에 노출된다.
- 데이터베이스 스키마가 변경될 경우 클라이언트 코드가 영향을 받는다.
- 코드 재사용성이 떨어지고 유지보수가 어렵다.
그럼 이 책에서 지향하는 바는 무엇일까?
// 클라이언트 코드
@Transactional
public void cancelOrder(Long orderId) {
// 👍 Repository를 통해 Aggregate를 로드
Order order = orderRepository.findById(orderId);
if (order == null) {
throw new IllegalArgumentException("Order not found");
}
// 👍 도메인 로직 호출
order.cancel();
// Repository를 통해 저장
orderRepository.save(order);
}
- 도메인 규칙이 엔티티 내에서 처리된다.
- 데이터베이스 스키마가 변경에 대해 클라이언트 코드가 영향을 받지 않는다.
- 도메인 엔티티는 다른 서비스나 유즈케이스에서도 재사용될 수 있다.
❐ Repository의 이점
1. 영속화된 객체를 획득하고 생명주기를 관리하는 단순한 모델 제공
@Transactional(readOnly = true)
public Optional<User> findById(UserId id) {
return userRepository.findBYId(id);
}
2. 영속화 기술과 데이터 소스로부터 애플리케이션 설계 분리
Repository는 데이터베이스 기술(SQL, NoSQL 등)을 도메인 로직으로 부터 분리한다.
@Transactional(readOnly = true)
public Optional<User> findById(UserId id) {
// JPA를 통해 조회, 추후에 영속화 기술을 바꿔도 해당 코드는 바뀌지 않음.
return userRepository.findBYId(id);
}
3. 객체 접근에 관한 설계 결정을 제공
Repository는 클라이언트가 객체에 어떻게 접근할지에 대한 규칙과 인터페이스를 제공하며,
복잡한 쿼리나 필터링 로직을 캡슐화한다.
4. 테스트에서 사용할 가짜 구현을 손쉽게 대체 가능
테스트 시 Repository의 가짜(Mock) 구현을 사용해 데이터베이스 연결 없이 비즈니스 로직을
검증할 수 있다.
❐ Factory와의 관계
Factory가 객체 생애의 초기 단계를 다루는 데 반해, Repository는 중간 단계와 마지막
단계를 관리하는데 도움된다. 객체가 메모리에 상주하거나 객체 데이터베이스에 저장돼
있을 때 는 객체를 다루기가 매우 쉽다.
하지만 일반적으로는 적어도 관계형 데이터베이스나 파일, 또는 다른 비객체지향적인 시스템에
객체 저장소가 존재한다. 그러한 경우에는 획득한 데이터를 객체 형태로 재구성해야 한다.
여기서 "재구성"이라는 단어는 저장되어 있는 객체로부터 인스턴스를 만들어 내는 것이라고 한다.
그리고 재구성을 해야하는 이유는 Redis와 같이 비객체지향적 저장소에 저장된 데이터를 객체로
사용하려면 직력화/역직렬화 과정이 필요한데, 이 과정을 이 책에서는 "재구성"이라는 단어로 표현했다고
생각한다.
☑️ Factory와 Repository의 역할 차이
- Factory : 객체 생애의 초기 단계를 담당하며, 새로운 객체를 생성한다.
- Repository : 객체 생애의 중간 및 마지막 단계를 관리하며, 기존 객체를 찾아오거나 재구성한다.
☑️ 책임 분리
- Factory :객체 생성에 집중
- Repository : 영속화(저장)에 집중
'Architecture > DDD' 카테고리의 다른 글
Bounded Context (0) | 2025.03.17 |
---|---|
7. 언어의 사용 (확장 예제) (0) | 2025.03.05 |
6-2. Factory (0) | 2024.12.03 |
ReadMe.md (0) | 2024.12.03 |