DDD 패턴 적용 (feat. 백오피스 API 설계를 살짝 곁들인. )

Seong Hyeon Kim·2024년 9월 7일
0

용어 정리 및 해설

목록 보기
6/6

백오피스 API 설계와 DDD 적용: 첫 경험기

1. 백오피스 API 작업과 DDD를 처음으로 도입

최근 백오피스 API 작업을 시작하면서, 기존의 MVC 패턴에서 DDD(도메인 주도 설계)로 전환을 요구받았다. 그동안 비즈니스 로직을 MVC 패턴을 사용해 왔지만, 백오피스에서 더 복잡한 비즈니스 로직을 체계적으로 관리하기 위해 DDD를 적용하기로 결정했다. 백오피스에서 처리할 주요 기능은 다음과 같다.


  • 상품 관리 API: 상품 생성, 수정, 삭제 작업

  • CS 작업을 위한 주문 관리 API: 기존 주문 테이블과 관련된 수정 및 조회 작업

  • 백오피스 로그인 및 유저 관리 API: 로컬 로그인, 어드민 유저 정보 조회, JWT 토큰 발급 및 재발급 API


이 글에서는 처음으로 DDD를 도입하며 겪은 내용들을 설명하고, DDD의 핵심 개념인 애그리게잇(Aggregate)서비스 계층의 역할 분리를 중심으로 백오피스 API에 어떻게 적용했는지를 공유하고자 한다.




2. DDD(도메인 주도 설계)란?

DDD는 도메인(비즈니스 로직)에 집중하는 설계 철학이다. 이는 도메인 전문가와 개발자가 같은 언어로 소통하며 시스템을 설계하고, 그 결과물로 도메인 모델을 기반으로 한 애플리케이션을 개발하게 한다. 여기서 중요한 개념이 애그리게잇(Aggregate)이다.


애그리게잇(Aggregate)이란?

  • 애그리게잇은 여러 개의 엔티티(Entity)와 값 객체(Value Object)를 하나로 묶어서 처리하는 도메인의 단위를 의미한다.

  • 애그리게잇은 비즈니스 규칙을 관리하고, 도메인 객체의 상태를 책임지며, 트랜잭션의 경계를 정의하는 역할을 한다.

  • 쉽게 말해, 애그리게잇은 도메인에서 발생하는 여러 이벤트나 상태 변경을 하나의 단위로 처리하여 비즈니스 규칙이 흩어지지 않도록 한다.




3. ProductAggregate와 도메인 로직

예를 들어, 상품 관련 도메인에서 가격을 변경하는 비즈니스 로직을 처리한다고 가정해 보자. 우리는 이미 비즈니스 로직에 Product라는 엔티티가 있다고 가정하고, 이 엔티티를 관리하는 애그리게잇을 작성하게 된다.

public class ProductAggregate {

    private Product product;

    public ProductAggregate(Product product) {
        this.product = product;
    }

    // 가격 변경에 대한 비즈니스 규칙 적용
    public void changePrice(Long newPrice, User user) {
        if (!user.isVip() && newPrice < product.getOriginalPrice()) {
            throw new IllegalArgumentException("Only VIP users can set prices below the original price.");
        }

        if (newPrice <= 0) {
            throw new IllegalArgumentException("Price must be greater than zero.");
        }

        this.product.setPrice(newPrice);
    }

    public Product getProduct() {
        return product;
    }
}

  • ProductAggregate는 상품의 가격을 변경할 때 필요한 비즈니스 규칙을 모두 포함한다.

  • 여기서 서비스는 단순히 애그리게잇을 호출하고, 비즈니스 로직은 전적으로 애그리게잇에 위임된다.

  • 이로써, 여러 서비스에서 동일한 규칙을 반복하지 않고, 하나의 애그리게잇에서 규칙을 중앙화하여 관리할 수 있다.




4. 왜 애그리게잇에서 비즈니스 로직을 처리해야 할까?

여기에서 "왜 서비스 계층에서 비즈니스 로직을 처리하지 않고 애그리게잇에서 처리해야 할까? 굳..이? "라는 의문을 가질 수 있다. 단순한 검증 로직은 서비스에서 처리해도 큰 문제가 없어 보이지만, DDD의 핵심은 도메인 객체가 자신의 상태와 규칙을 책임지게 하는 것이다. 여기에는 여러 가지 이유가 있다.


  1. 비즈니스 로직의 중앙화
    여러 서비스에서 동일한 비즈니스 규칙을 적용해야 하는 경우, 이 규칙을 애그리게잇에서 관리하면 코드 중복을 방지 할 수 있다. 만약 상품 가격 변경에 대한 로직이 여러 서비스에 분산되어 있다면, 나중에 비즈니스 규칙이 바뀔 때 모든 서비스를 수정해야 하는 문제가 생긴다. 애그리게잇에 집중시킴으로써 이러한 문제를 방지할 수 있다.
  1. 도메인 객체의 책임 강화
    도메인 객체가 자신의 상태를 검증하고 관리함으로써, 비즈니스 로직이 한 곳에 집중되고 외부에서 도메인 상태를 임의로 변경하지 못하도록 보호할 수 있다. 이렇게 하면 도메인 상태가 일관성을 유지하며, 예기치 않은 버그를 방지할 수 있다.
  1. 확장성
    단순한 규칙이라도 시간이 지나면서 더 복잡한 비즈니스 요구사항이 추가될 수 있다. 예를 들어, 할인 정책이나 특정 고객에만 허용되는 가격 변경 등 추가 규칙이 필요할 수 있다. 이러한 로직이 애그리게잇에 있으면, 새로운 규칙이 추가되더라도 쉽게 확장 할 수 있다.



5. 서비스 계층과 도메인 계층의 역할 분리

  • DDD에서 중요한 또 다른 개념은 서비스 계층도메인 계층의 역할 분리이다.
  • 서비스 계층은 주로 외부 요청을 처리하고, 도메인 계층(애그리게잇)에 비즈니스 로직 처리를 위임한다.
  • 도메인 계층은 도메인의 규칙과 상태를 관리하며, 서비스 계층은 이를 호출하는 역할만 맡는다.
// 서비스에서
public void changeProductPrice(Long productId, Long newPrice, User user) {
    Product product = productRepository.findById(productId);
    ProductAggregate productAggregate = new ProductAggregate(product);
    
    productAggregate.changePrice(newPrice, user);
    productRepository.save(productAggregate.getProduct());
}

위 코드에서 서비스 계층은 단순히 도메인 계층인 ProductAggregate를 호출하고, 가격 변경을 요청할 뿐이다. 서비스는 도메인의 로직을 직접 다루지 않고, 도메인 계층이 비즈니스 규칙을 처리하도록 한다.




6. 백오피스에서 DDD 적용의 필요성

백오피스 시스템은 복잡한 비즈니스 로직을 관리해야 할 때가 많다. 특히 상품 관리, 주문 관리, 그리고 어드민 유저 관리에서 발생하는 다양한 규칙을 애그리게잇으로 관리하면, 시스템이 확장되거나 새로운 규칙이 추가될 때 더 쉽게 유지보수할 수 있다.

예를 들어, 주문 테이블과 관련된 작업에서도 기존 비즈니스 로직을 그대로 사용하면서, 백오피스 API에서 레포지토리 를 통해 애그리게잇을 호출하고 관리할 수 있다. 이렇게 하면 기존 비즈니스 로직과 백오피스 API가 상호 독립적으로 관리되면서도, 규칙을 일관성 있게 유지할 수 있다.




마무리

  • DDD는 처음 접하면 다소 복잡하게 느껴질 수 있지만, 도메인 로직의 중앙화, 도메인 객체의 책임 강화, 확장성 등을 고려할 때 매우 강력한 패턴이다.

  • 특히 백오피스와 같은 관리 시스템에서 비즈니스 로직을 체계적으로 관리할 수 있는 도구로 DDD는 유용하다.

  • 백오피스 API 작업에서도 DDD를 적용함으로써, 복잡한 비즈니스 요구사항을 유연하게 처리할 수 있을 것이다.

profile
삽질도 100번 하면 요령이 생긴다. 부족한 건 경험으로 채우는 개발자

0개의 댓글