본문 바로가기
Books/도메인 주도 개발 시작하기

Chapter2. 아키텍처 개요

by YoonJong 2024. 4. 5.
728x90

  • 상위 계층에서 하위 계층으로의 의존만 존재하고 하위 계층은 상위 계층에 의존하지 않는다.

1. 표현 영역 (Presentation Layer)

  • 사용자 인터페이스(UI)를 담당
  • 사용자와 직접 상호 작용하며, 시각적 요소와 기능을 제공
  • 예시: JSP, Thymeleaf, React, Vue.js 등

2. 응용 영역 (Application Layer)

  • 비즈니스 규칙을 구현
  • 도메인 모델과 상호 작용하여 사용자 요청을 처리
  • 예시: 서비스 클래스, 유틸리티 클래스 등
@Transactional
public void cancel(OrderNo orderNo, Canceller canceller) {
    Order order = orderRepository.findById(orderNo)
            .orElseThrow(() -> new NoOrderException());
    if (!cancelPolicy.hasCancellationPermission(order, canceller)) {
        throw new NoCancellablePermission();
    }
    order.cancel();
}

3. 도메인 영역 (Domain Layer)

  • 도메인의 핵심 로직 구현
  • 비즈니스 핵심 개념과 규칙을 담당
  • 엔티티, 값 객체, 저장소 등을 포함
  • 예시: 엔티티 클래스, 인터페이스, 저장소 인터페이스 등
@Entity
@Table(name = "purchase_order")
@Access(AccessType.FIELD)
public class Order {
    @EmbeddedId
    private OrderNo number;

    @Version
    private long version;

    @Embedded
    private Orderer orderer;
    
    ...
    ...

// 핵심 로직 구현
public void cancel() {
    verifyNotYetShipped();
    this.state = OrderState.CANCELED;
    Events.raise(new OrderCanceledEvent(number.getNumber()));
}

4. 인프라스트럭처 영역 (Infrastructure Layer)

  • 데이터베이스, 파일 시스템, 네트워킹 등 외부 시스템과의 상호 작용을 담당
  • 도메인 모델에 영향을 주지 않고 외부 시스템에 대한 추상화 계층을 제공
  • 예시: JDBC, JPA, Spring Data JPA 등
public interface UserRepository extends JpaRepository<User, Long> {}

  • DIP (의존역전의 원칙)
    • DIP 원칙은 고수준 모듈이 저수준 모듈의 구현에 직접 의존해서는 안 되며, 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다는 개념
      • 고수준 모듈: 추상화된 개념으로, 의미 있는 단일 기능을 제공합니다. 구체적인 구현보다는 기능의 정의에 집중
      • 저수준 모듈: 구체적인 구현을 담당하며, 고수준 모듈에서 필요한 하위 기능을 제공
    • 변경 효율성 향상: A사 알람 기능 API가 변경되어도 AlarmService 인터페이스를 만족하는 다른 구현체로 쉽게 교체 가능
    • 테스트 용이성 향상: AlarmService 인터페이스를 구현하는 모의 객체를 사용하여 알람 서비스를 쉽게 테스트 가능
    • 코드의 결합도 감소: 알람 기능에 대한 의존성을 추상화하여 코드의 결합도를 낮출 수 있음.
// DIP 예제

// 알림 인터페이스 생성
public interface AlarmService {
    void sendAlarm(String message);
}

// A사 알람 구현
public class AAlarmService implements AlarmService {
    @Override
    public void sendAlarm(String message) {
        // A사 알람 기능 API 사용
        System.out.println("A사 알람: " + message);
    }
}

// B사 알람 구현
public class BAlarmService implements AlarmService {
    @Override
    public void sendAlarm(String message) {
        // B사 알람 기능 API 사용
        System.out.println("B사 알람: " + message);
    }
}

public class Main {
    public static void main(String[] args) {
        AlarmService alarmService = new AAlarmService(); // A사 알람 기능 사용
        alarmService.sendAlarm("알람 메시지");

        alarmService = new BAlarmService(); // B사 알람 기능 사용
        alarmService.sendAlarm("알람 메시지");
    }
}
  • 도메인 영역의 주요 구성요소

1. 엔티티

  • 도메인의 독립적인 존재
  • 고유한 식별자를 가지고 있음
  • 상태와 행위를 가짐
  • 예시: 고객, 주문, 제품

2. 밸류

  • 엔티티의 속성을 나타내는 값 객체
  • 불변하며, 동일성 비교를 통해 식별
  • 예시: 이름, 주소, 전화번호

3. 애그리거트

  • 엔티티들의 논리적 그룹
  • 일관성을 유지하는 하나의 단위로 작동
  • 부모 엔티티(루트 엔티티)와 자식 엔티티로 구성
  • 예시
    • 주문: 주문 엔티티, 주문 항목 엔티티, 배송 정보 밸류 객체
    • 고객: 고객 엔티티, 주소 밸류 객체, 연락처 밸류 객체

 

4. 리포지터리

  • 특정 엔티티 또는 애그리거트에 대한 데이터 접근을 담당
  • CRUD(Create, Read, Update, Delete) 작업을 수행
  • 도메인 로직과 분리되어 구현
  • 예시: 고객 리포지터리, 주문 리포지터리

5. 도메인 서비스

  • 복잡한 비즈니스 로직을 수행하는 객체
  • 여러 엔티티 또는 애그리거트에 걸쳐 작동
  • 재사용 가능한 독립적인 단위
  • 예시: 주문 처리 서비스, 결제 서비스
  • 도메인 모델 엔티티와 DB 테이블의 엔티티 구분
    • 도메인 모델 엔티티 : 데이터 + 도메인 기능
    public class Order {
    
        private Long id;
        private Customer customer;
        private List<OrderItem> orderItems;
        private OrderStatus orderStatus; // 밸류(값) 타입 포함 가능 
    
        public void calculateTotalPrice() {
            // ...
        }
    }
    
    • DB 테이블의 엔티티 : 테이블 구조에 필요한 속성
    public class OrderEntity {
    
        private Long id;
        private Long customerId;
    }
    
  • 모듈 예시
    • 한 패키지에 가능하면 10 ~ 15 개 미만으로 타입 개수를 유지하려고 한다고 한다. ( 최범균님 )
# 표현 계층

presentation/
├── controller/
│   └── UserController.java
└── view/
    └── user/
        ├── index.html
        └── detail.html

# 응용 계층

application/
├── service/
│   └── UserService.java
└── util/
    └── ValidationUtil.java

# 도메인 계층 - 여러 하위 도메인으로 분리 가능

domain/
├── entity/
│   └── User.java
├── product/
│   ├── entity/
│   │   └── Product.java
│   └── service/
│       └── ProductService.java
├── order/
│   ├── entity/
│   │   └── Order.java
│   └── service/
│       └── OrderService.java
└── cart/
    ├── entity/
    │   └── Cart.java
    └── service/
        └── CartService.java

# 인프라 스트럭쳐

infrastructure/
├── repository/
│   └── UserRepository.java
└── dao/
    └── UserDaoImpl.java
728x90

댓글